initial commit

This commit is contained in:
technyon
2022-03-22 21:10:43 +01:00
commit b5e57da5a0
531 changed files with 180736 additions and 0 deletions

View File

@@ -0,0 +1,267 @@
# Coding Style for Apache NimBLE
Apache NimBLE project is part of Apache Mynewt projct and follows its coding
style.
# Coding Style for Apache Mynewt Core
This document is meant to define the coding style for Apache Mynewt, and
all subprojects of Apache Mynewt. This covers C and Assembly coding
conventions, *only*. Other languages (such as Go), have their own
coding conventions.
## Headers
* All files that are newly written, should have the Apache License clause
at the top of them.
* For files that are copied from another source, but contain an Apache
compatible license, the original license header shall be maintained.
* For more information on applying the Apache license, the definitive
source is here: http://www.apache.org/dev/apply-license.html
* The Apache License clause for the top of files is as follows:
```no-highlight
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
```
## Whitespace and Braces
* Code must be indented to 4 spaces, tabs should not be used.
* Do not add whitespace at the end of a line.
* Put space after keywords (for, if, return, switch, while).
* for, else, if, while statements must have braces around their
code blocks, i.e., do:
```
if (x) {
assert(0);
} else {
assert(0);
}
```
Not:
```
if (x)
assert(0);
else
assert(0);
```
* Braces for statements must be on the same line as the statement. Good:
```
for (i = 0; i < 10; i++) {
if (i == 5) {
break;
} else {
continue;
}
}
```
Not:
```
for (i = 0; i < 10; i++)
{ <-- brace must be on same line as for
if (i == 5) {
break;
} <-- no new line between else
else {
continue;
}
}
```
* After a function declaration, the braces should be on a newline, i.e. do:
```
static void *
function(int var1, int var2)
{
```
not:
```
static void *
function(int var1, int var2) {
```
## Line Length and Wrap
* Line length should never exceed 79 columns.
* When you have to wrap a long statement, put the operator at the end of the
line. i.e.:
```
if (x &&
y == 10 &&
b)
```
Not:
```
if (x
&& y == 10
&& b)
```
## Comments
* No C++ style comments allowed.
* When using a single line comment, put it above the line of code that you
intend to comment, i.e., do:
```
/* check variable */
if (a) {
```
Not:
```
if (a) { /* check variable */
```
* All public APIs should be commented with Doxygen style comments describing
purpose, parameters and return values. Private APIs need not be documented.
## Header files
* Header files must contain the following structure:
* Apache License (see above)
* ```#ifdef``` aliasing, to prevent multiple includes
* ```#include``` directives for other required header files
* ```#ifdef __cplusplus``` wrappers to maintain C++ friendly APIs
* Contents of the header file
* ```#ifdef``` aliasing, shall be in the following format, where
the package name is "os" and the file name is "callout.h":
```no-highlight
#ifndef _OS_CALLOUT_H
#define _OS_CALLOUT_H
```
* ```#include``` directives must happen prior to the cplusplus
wrapper.
* The cplusplus wrapper must have the following format, and precedes
any contents of the header file:
```no-highlight
#ifdef __cplusplus
#extern "C" {
##endif
```
## Naming
* Names of functions, structures and variables must be in all lowercase.
* Names should be as short as possible, but no shorter.
* Globally visible names must be prefixed with the name of the module,
followed by the '_' character, i.e.:
```
os_callout_init(&c)
```
Not:
```
callout_init(c)
```
## Functions
* No spaces after function names when calling a function, i.e, do:
```
rc = function(a)
```
Not:
```
rc = function (a)
```
* Arguments to function calls should have spaces between the comma, i.e. do:
```
rc = function(a, b)
```
Not:
```
rc = function(a,b)
```
* The function type must be on a line by itself preceding the function, i.e. do:
```
static void *
function(int var1, int var2)
{
```
Not:
```
static void *function(int var1, int var2)
{
```
* In general, for functions that return values that denote success or error, 0
shall be success, and non-zero shall be the failure code.
## Variables and Macros
* Do not use typedefs for structures. This makes it impossible for
applications to use pointers to those structures opaquely.
* typedef may be used for non-structure types, where it is beneficial to
hide or alias the underlying type used (e.g. ```os_time_t```.) Indicate
typedefs by applying the ```_t``` marker to them.
* Place all function-local variable definitions at the top of the function body, before any statements.
## Compiler Directives
* Code must compile cleanly with -Wall enabled.

View File

@@ -0,0 +1,217 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
This product bundles queue.h 8.5, which is available under the "3-clause BSD"
license. For details, see porting/nimble/include/os/queue.h
This product partly derives from FreeBSD, which is available under the
"3-clause BSD" license. For details, see:
* porting/nimble/src/os_mbuf.c
This product bundles Gary S. Brown's CRC32 implementation, which is available
under the following license:
COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
code or tables extracted from it, as desired without restriction.
This product bundles tinycrypt, which is available under the "3-clause BSD"
license. For details, and bundled files see:
* ext/tinycrypt/LICENSE

View File

@@ -0,0 +1,9 @@
Apache Mynewt NimBLE
Copyright 2015-2020 The Apache Software Foundation
Modifications Copyright 2017-2020 Espressif Systems (Shanghai) CO., LTD.
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
Portions of this software were developed at
Runtime Inc, copyright 2015.

View File

@@ -0,0 +1,169 @@
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
-->
<img src="http://mynewt.apache.org/img/logo.svg" width="250" alt="Apache Mynewt">
## Overview
Apache NimBLE is an open-source Bluetooth 5.1 stack (both Host & Controller)
that completely replaces the proprietary SoftDevice on Nordic chipsets. It is
part of [Apache Mynewt project](https://github.com/apache/mynewt-core).
Features highlight:
- Support for 251 byte packet size
- Support for all 4 roles concurrently - Broadcaster, Observer, Peripheral and Central
- Support for up to 32 simultaneous connections.
- Legacy and SC (secure connections) SMP support (pairing and bonding).
- Advertising Extensions.
- Coded (aka Long Range) and 2M PHYs.
- Bluetooth Mesh.
## Supported hardware
Controller supports Nordic nRF51 and nRF52 chipsets. Host runs on any board
and architecture [supported](https://github.com/apache/mynewt-core#overview)
by Apache Mynewt OS.
## Browsing
If you are browsing around the source tree, and want to see some of the
major functional chunks, here are a few pointers:
- nimble/controller: Contains code for controller including Link Layer and HCI implementation
([controller](https://github.com/apache/mynewt-nimble/tree/master/nimble/controller))
- nimble/drivers: Contains drivers for supported radio transceivers (Nordic nRF51 and nRF52)
([drivers](https://github.com/apache/mynewt-nimble/tree/master/nimble/drivers))
- nimble/host: Contains code for host subsystem. This includes protocols like
L2CAP and ATT, support for HCI commands and events, Generic Access Profile (GAP),
Generic Attribute Profile (GATT) and Security Manager (SM).
([host](https://github.com/apache/mynewt-nimble/tree/master/nimble/host))
- nimble/host/mesh: Contains code for Bluetooth Mesh subsystem.
([mesh](https://github.com/apache/mynewt-nimble/tree/master/nimble/host/mesh))
- nimble/transport: Contains code for supported transport protocols between host
and controller. This includes UART, emSPI and RAM (used in combined build when
host and controller run on same CPU)
([transport](https://github.com/apache/mynewt-nimble/tree/master/nimble/transport))
- porting: Contains implementation of NimBLE Porting Layer (NPL) for supported
operating systems
([porting](https://github.com/apache/mynewt-nimble/tree/master/porting))
- ext: Contains external libraries used by NimBLE. Those are used if not
provided by OS
([ext](https://github.com/apache/mynewt-nimble/tree/master/ext))
- kernel: Contains the core of the RTOS ([kernel/os](https://github.com/apache/mynewt-core/tree/master/kernel/os))
## Sample Applications
There are also some sample applications that show how to Apache Mynewt NimBLE
stack. These sample applications are located in the `apps/` directory of
Apache Mynewt [repo](https://github.com/apache/mynewt-core). Some examples:
* [blecent](https://github.com/apache/mynewt-nimble/tree/master/apps/blecent):
A basic central device with no user interface. This application scans for
a peripheral that supports the alert notification service (ANS). Upon
discovering such a peripheral, blecent connects and performs a characteristic
read, characteristic write, and notification subscription.
* [blehci](https://github.com/apache/mynewt-nimble/tree/master/apps/blehci):
Implements a BLE controller-only application. A separate host-only
implementation, such as Linux's BlueZ, can interface with this application via
HCI over UART.
* [bleprph](https://github.com/apache/mynewt-nimble/tree/master/apps/bleprph): An
implementation of a minimal BLE peripheral.
* [btshell](https://github.com/apache/mynewt-nimble/tree/master/apps/btshell): A
shell-like application allowing to configure and use most of NimBLE
functionality from command line.
* [bleuart](https://github.com/apache/mynewt-core/tree/master/apps/bleuart):
Implements a simple BLE peripheral that supports the Nordic
UART / Serial Port Emulation service
(https://developer.nordicsemi.com/nRF5_SDK/nRF51_SDK_v8.x.x/doc/8.0.0/s110/html/a00072.html).
# Getting Help
If you are having trouble using or contributing to Apache Mynewt NimBLE, or just
want to talk to a human about what you're working on, you can contact us via the
[developers mailing list](mailto:dev@mynewt.apache.org).
Although not a formal channel, you can also find a number of core developers
on the #mynewt channel on Freenode IRC or #general channel on [Mynewt Slack](https://mynewt.slack.com/join/shared_invite/enQtNjA1MTg0NzgyNzg3LTcyMmZiOGQzOGMxM2U4ODFmMTIwNjNmYTE5Y2UwYjQwZWIxNTE0MTUzY2JmMTEzOWFjYWZkNGM0YmM4MzAxNWQ)
Also, be sure to checkout the [Frequently Asked Questions](https://mynewt.apache.org/faq/answers)
for some help troubleshooting first.
# Contributing
Anybody who works with Apache Mynewt can be a contributing member of the
community that develops and deploys it. The process of releasing an operating
system for microcontrollers is never done: and we welcome your contributions
to that effort.
More information can be found at the Community section of the Apache Mynewt
website, located [here](https://mynewt.apache.org/community).
## Pull Requests
Apache Mynewt welcomes pull request via Github. Discussions are done on Github,
but depending on the topic, can also be relayed to the official Apache Mynewt
developer mailing list dev@mynewt.apache.org.
If you are suggesting a new feature, please email the developer list directly,
with a description of the feature you are planning to work on.
## Filing Bugs
Bugs can be filed on the
[Apache Mynewt NimBLE Issues](https://github.com/apache/mynewt-nimble/issues).
Please label the issue as a "Bug".
Where possible, please include a self-contained reproduction case!
## Feature Requests
Feature requests should also be filed on the
[Apache Mynewt NimBLE Bug Tracker](https://github.com/apache/mynewt-nimble/issues).
Please label the issue as a "Feature" or "Enhancement" depending on the scope.
## Writing Tests
We love getting newt tests! Apache Mynewt is a huge undertaking, and improving
code coverage is a win for every Apache Mynewt user.
<!--
TODO
## Writing Documentation
Contributing to documentation (in addition to writing tests), is a great way
to get involved with the Apache Mynewt project.
The Mynewt NimBLE documentation is found in [/docs](/docs).
-->
# License
The code in this repository is all under either the Apache 2 license, or a
license compatible with the Apache 2 license. See the LICENSE file for more
information.

View File

@@ -0,0 +1,33 @@
# RELEASE NOTES
18 March 2020 - Apache NimBLE v1.3.0
For full release notes, please visit the
[Apache Mynewt Wiki](https://cwiki.apache.org/confluence/display/MYNEWT/Release+Notes).
Apache NimBLE is an open-source Bluetooth 5.1 stack (both Host & Controller) that completely
replaces the proprietary SoftDevice on Nordic chipsets.
New features in this version of NimBLE include:
* Support for Bluetooth Core Specification 5.1
* New blestress test application
* Dialog DA1469x CMAC driver
* Support for LE Secure Connections out-of-band (OOB) association model
* Support for automated generation of syscfg for ports
* Qualification related bugfixes
* BLE Mesh improvements - fixes and resync with latest Zephyr code
* RIOT OS port fixes and improvements
* btshell sample application improvements
* improvements for bttester application
* Controller duplicates filtering improvements
* Multi PHY support improvements
* Memory and CPU usage optimizations
* Use of packed structs for HCI (code size reduction)
* Linux sample improvements
* PTS test instructions updates
* Clock managements improvements in controller
If working on next-generation RTOS and Bluetooth protocol stack
sounds exciting to you, get in touch, by sending a mail to the Apache Mynewt
Developer's list, dev@mynewt.apache.org.

View File

@@ -0,0 +1,16 @@
#ifndef __CONSOLE_H__
#define __CONSOLE_H__
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#define console_printf printf
#ifdef __cplusplus
}
#endif
#endif /* __CONSOLE_H__ */

View File

@@ -0,0 +1,59 @@
// Copyright 2016-2019 Espressif Systems (Shanghai) PTE LTD
//
// 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
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ESP_COMPILER_H
#define __ESP_COMPILER_H
/*
* The likely and unlikely macro pairs:
* These macros are useful to place when application
* knows the majority ocurrence of a decision paths,
* placing one of these macros can hint the compiler
* to reorder instructions producing more optimized
* code.
*/
#if (CONFIG_COMPILER_OPTIMIZATION_PERF)
#ifndef likely
#define likely(x) __builtin_expect(!!(x), 1)
#endif
#ifndef unlikely
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif
#else
#ifndef likely
#define likely(x) (x)
#endif
#ifndef unlikely
#define unlikely(x) (x)
#endif
#endif
/*
* Utility macros used for designated initializers, which work differently
* in C99 and C++ standards mainly for aggregate types.
* The member separator, comma, is already part of the macro, please omit the trailing comma.
* Usage example:
* struct config_t { char* pchr; char arr[SIZE]; } config = {
* ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(pchr)
* ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(arr, "Value")
* };
*/
#ifdef __cplusplus
#define ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(member, value) { .member = value },
#define ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(member) .member = { },
#else
#define ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(member, value) .member = value,
#define ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(member)
#endif
#endif

View File

@@ -0,0 +1,125 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifdef ESP_PLATFORM
#ifndef __ESP_NIMBLE_HCI_H__
#define __ESP_NIMBLE_HCI_H__
#include "nimble/nimble/include/nimble/ble_hci_trans.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BLE_HCI_UART_H4_NONE 0x00
#define BLE_HCI_UART_H4_CMD 0x01
#define BLE_HCI_UART_H4_ACL 0x02
#define BLE_HCI_UART_H4_SCO 0x03
#define BLE_HCI_UART_H4_EVT 0x04
/**
* @brief Initialize VHCI transport layer between NimBLE Host and
* ESP Bluetooth controller
*
* This function initializes the transport buffers to be exchanged
* between NimBLE host and ESP controller. It also registers required
* host callbacks with the controller.
*
* @return
* - ESP_OK if the initialization is successful
* - Appropriate error code from esp_err_t in case of an error
*/
esp_err_t esp_nimble_hci_init(void);
/**
* @brief Initialize ESP Bluetooth controller(link layer) and VHCI transport
* layer between NimBLE Host and ESP Bluetooth controller
*
* This function initializes ESP controller in BLE only mode and the
* transport buffers to be exchanged between NimBLE host and ESP controller.
* It also registers required host callbacks with the controller.
*
* Below is the sequence of APIs to be called to initialize/enable NimBLE host and ESP controller:
*
* @code{c}
* void ble_host_task(void *param)
* {
* nimble_port_run(); //This function will return only when nimble_port_stop() is executed.
* nimble_port_freertos_deinit();
* }
*
* int ret = esp_nimble_hci_and_controller_init();
* if (ret != ESP_OK) {
ESP_LOGE(TAG, "esp_nimble_hci_and_controller_init() failed with error: %d", ret);
* return;
* }
*
* nimble_port_init();
*
* //Initialize the NimBLE Host configuration
*
* nimble_port_freertos_init(ble_host_task);
* @endcode
*
* nimble_port_freertos_init() is an optional call that creates a new task in which the NimBLE
* host will run. The task function should have a call to nimble_port_run(). If a separate task
* is not required, calling nimble_port_run() will run the NimBLE host in the current task.
*
* @return
* - ESP_OK if the initialization is successful
* - Appropriate error code from esp_err_t in case of an error
*/
esp_err_t esp_nimble_hci_and_controller_init(void);
/**
* @brief Deinitialize VHCI transport layer between NimBLE Host and
* ESP Bluetooth controller
*
* @note This function should be called after the NimBLE host is deinitialized.
*
* @return
* - ESP_OK if the deinitialization is successful
* - Appropriate error codes from esp_err_t in case of an error
*/
esp_err_t esp_nimble_hci_deinit(void);
/**
* @brief Deinitialize VHCI transport layer between NimBLE Host and
* ESP Bluetooth controller and disable and deinitialize the controller
*
* @note This function should not be executed in the context of Bluetooth host task.
*
* @note This function should be called after the NimBLE host is deinitialized.
*
* Below is the sequence of APIs to be called to disable/deinit NimBLE host and ESP controller:
*
* @code{c}
* int ret = nimble_port_stop();
* if (ret == 0) {
* nimble_port_deinit();
*
* ret = esp_nimble_hci_and_controller_deinit();
* if (ret != ESP_OK) {
ESP_LOGE(TAG, "esp_nimble_hci_and_controller_deinit() failed with error: %d", ret);
* }
* }
* @endcode
*
* If nimble_port_freertos_init() is used during initialization, then
* nimble_port_freertos_deinit() should be called in the host task after nimble_port_run().
*
* @return
* - ESP_OK if the deinitialization is successful
* - Appropriate error codes from esp_err_t in case of an error
*/
esp_err_t esp_nimble_hci_and_controller_deinit(void);
#ifdef __cplusplus
}
#endif
#endif /* __ESP_NIMBLE_HCI_H__ */
#endif

View File

@@ -0,0 +1,583 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifdef ESP_PLATFORM
#include <assert.h>
#include "nimble/porting/nimble/include/sysinit/sysinit.h"
#include "nimble/nimble/include/nimble/hci_common.h"
#include "nimble/nimble/host/include/host/ble_hs.h"
#include "nimble/porting/nimble/include/nimble/nimble_port.h"
#include "nimble/porting/npl/freertos/include/nimble/nimble_port_freertos.h"
#include "../include/esp_nimble_hci.h"
#include "../../port/include/esp_nimble_mem.h"
#include <esp_bt.h>
#include <freertos/semphr.h>
#include "../include/esp_compiler.h"
/* IPC is used to improve performance when calls come from a processor not running the NimBLE stack */
/* but does not exist for solo */
#ifndef CONFIG_FREERTOS_UNICORE
#include "esp_ipc.h"
#endif
#define NIMBLE_VHCI_TIMEOUT_MS 2000
#define BLE_HCI_EVENT_HDR_LEN (2)
#define BLE_HCI_CMD_HDR_LEN (3)
static ble_hci_trans_rx_cmd_fn *ble_hci_rx_cmd_hs_cb;
static void *ble_hci_rx_cmd_hs_arg;
static ble_hci_trans_rx_acl_fn *ble_hci_rx_acl_hs_cb;
static void *ble_hci_rx_acl_hs_arg;
static struct os_mbuf_pool ble_hci_acl_mbuf_pool;
static struct os_mempool_ext ble_hci_acl_pool;
/*
* The MBUF payload size must accommodate the HCI data header size plus the
* maximum ACL data packet length. The ACL block size is the size of the
* mbufs we will allocate.
*/
#define ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) \
+ BLE_MBUF_MEMBLOCK_OVERHEAD \
+ BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT)
static os_membuf_t *ble_hci_acl_buf;
static struct os_mempool ble_hci_cmd_pool;
static os_membuf_t *ble_hci_cmd_buf;
static struct os_mempool ble_hci_evt_hi_pool;
static os_membuf_t *ble_hci_evt_hi_buf;
static struct os_mempool ble_hci_evt_lo_pool;
static os_membuf_t *ble_hci_evt_lo_buf;
static SemaphoreHandle_t vhci_send_sem;
const static char *TAG = "NimBLE";
int os_msys_buf_alloc(void);
void os_msys_buf_free(void);
void ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb,
void *cmd_arg,
ble_hci_trans_rx_acl_fn *acl_cb,
void *acl_arg)
{
ble_hci_rx_cmd_hs_cb = cmd_cb;
ble_hci_rx_cmd_hs_arg = cmd_arg;
ble_hci_rx_acl_hs_cb = acl_cb;
ble_hci_rx_acl_hs_arg = acl_arg;
}
/* Added; Called from the core NimBLE is running on, not used for unicore */
#ifndef CONFIG_FREERTOS_UNICORE
void ble_hci_trans_hs_cmd_tx_on_core(void *arg)
{
// Ugly but necessary as the arduino core does not provide enough IPC stack for variables.
esp_vhci_host_send_packet((uint8_t*)arg, *((uint8_t*)arg + 3) + 1 + BLE_HCI_CMD_HDR_LEN);
}
#endif
/* Modified to use ipc calls in arduino to correct performance issues */
int ble_hci_trans_hs_cmd_tx(uint8_t *cmd)
{
uint16_t len;
uint8_t rc = 0;
assert(cmd != NULL);
*cmd = BLE_HCI_UART_H4_CMD;
len = BLE_HCI_CMD_HDR_LEN + cmd[3] + 1;
if (!esp_vhci_host_check_send_available()) {
ESP_LOGD(TAG, "Controller not ready to receive packets");
}
if (xSemaphoreTake(vhci_send_sem, NIMBLE_VHCI_TIMEOUT_MS / portTICK_PERIOD_MS) == pdTRUE) {
/* esp_ipc_call_blocking does not exist for solo */
#ifndef CONFIG_FREERTOS_UNICORE
if (xPortGetCoreID() != CONFIG_BT_NIMBLE_PINNED_TO_CORE && !xPortInIsrContext()) {
esp_ipc_call_blocking(CONFIG_BT_NIMBLE_PINNED_TO_CORE,
ble_hci_trans_hs_cmd_tx_on_core, cmd);
} else {
esp_vhci_host_send_packet(cmd, len);
}
#else /* Unicore */
esp_vhci_host_send_packet(cmd, len);
#endif
} else {
rc = BLE_HS_ETIMEOUT_HCI;
}
ble_hci_trans_buf_free(cmd);
return rc;
}
int ble_hci_trans_ll_evt_tx(uint8_t *hci_ev)
{
int rc = ESP_FAIL;
if (ble_hci_rx_cmd_hs_cb) {
rc = ble_hci_rx_cmd_hs_cb(hci_ev, ble_hci_rx_cmd_hs_arg);
}
return rc;
}
/* Added; Called from the core NimBLE is running on, not used for unicore */
#ifndef CONFIG_FREERTOS_UNICORE
void ble_hci_trans_hs_acl_tx_on_core(void *arg)
{
// Ugly but necessary as the arduino core does not provide enough IPC stack for variables.
esp_vhci_host_send_packet((uint8_t*)arg + 2, *(uint16_t*)arg);
}
#endif
/* Modified to use ipc calls in arduino to correct performance issues */
int ble_hci_trans_hs_acl_tx(struct os_mbuf *om)
{
uint16_t len = 0;
uint8_t data[MYNEWT_VAL(BLE_ACL_BUF_SIZE) + 3], rc = 0;
bool tx_using_nimble_core = 0;
/* If this packet is zero length, just free it */
if (OS_MBUF_PKTLEN(om) == 0) {
os_mbuf_free_chain(om);
return 0;
}
if (!esp_vhci_host_check_send_available()) {
ESP_LOGD(TAG, "Controller not ready to receive packets");
}
len = 1 + OS_MBUF_PKTLEN(om);
/* Don't check core ID if unicore */
#ifndef CONFIG_FREERTOS_UNICORE
tx_using_nimble_core = xPortGetCoreID() != CONFIG_BT_NIMBLE_PINNED_TO_CORE;
if (tx_using_nimble_core && !xPortInIsrContext()) {
data[0] = len;
data[1] = (len >> 8);
data[2] = BLE_HCI_UART_H4_ACL;
os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[3]);
} else {
data[0] = BLE_HCI_UART_H4_ACL;
os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[1]);
}
#else /* Unicore */
data[0] = BLE_HCI_UART_H4_ACL;
os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[1]);
#endif
if (xSemaphoreTake(vhci_send_sem, NIMBLE_VHCI_TIMEOUT_MS / portTICK_PERIOD_MS) == pdTRUE) {
/* esp_ipc_call_blocking does not exist for solo */
#ifndef CONFIG_FREERTOS_UNICORE
if (tx_using_nimble_core && !xPortInIsrContext()) {
esp_ipc_call_blocking(CONFIG_BT_NIMBLE_PINNED_TO_CORE,
ble_hci_trans_hs_acl_tx_on_core, data);
} else {
esp_vhci_host_send_packet(data, len);
}
#else /* Unicore */
esp_vhci_host_send_packet(data, len);
#endif
} else {
rc = BLE_HS_ETIMEOUT_HCI;
}
os_mbuf_free_chain(om);
return rc;
}
int ble_hci_trans_ll_acl_tx(struct os_mbuf *om)
{
int rc = ESP_FAIL;
if (ble_hci_rx_acl_hs_cb) {
rc = ble_hci_rx_acl_hs_cb(om, ble_hci_rx_acl_hs_arg);
}
return rc;
}
uint8_t *ble_hci_trans_buf_alloc(int type)
{
uint8_t *buf;
switch (type) {
case BLE_HCI_TRANS_BUF_CMD:
buf = os_memblock_get(&ble_hci_cmd_pool);
break;
case BLE_HCI_TRANS_BUF_EVT_HI:
buf = os_memblock_get(&ble_hci_evt_hi_pool);
if (buf == NULL) {
/* If no high-priority event buffers remain, try to grab a
* low-priority one.
*/
buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO);
}
break;
case BLE_HCI_TRANS_BUF_EVT_LO:
buf = os_memblock_get(&ble_hci_evt_lo_pool);
break;
default:
assert(0);
buf = NULL;
}
return buf;
}
void ble_hci_trans_buf_free(uint8_t *buf)
{
int rc;
/* XXX: this may look a bit odd, but the controller uses the command
* buffer to send back the command complete/status as an immediate
* response to the command. This was done to insure that the controller
* could always send back one of these events when a command was received.
* Thus, we check to see which pool the buffer came from so we can free
* it to the appropriate pool
*/
if (os_memblock_from(&ble_hci_evt_hi_pool, buf)) {
rc = os_memblock_put(&ble_hci_evt_hi_pool, buf);
assert(rc == 0);
} else if (os_memblock_from(&ble_hci_evt_lo_pool, buf)) {
rc = os_memblock_put(&ble_hci_evt_lo_pool, buf);
assert(rc == 0);
} else {
assert(os_memblock_from(&ble_hci_cmd_pool, buf));
rc = os_memblock_put(&ble_hci_cmd_pool, buf);
assert(rc == 0);
}
}
/**
* Unsupported; the RAM transport does not have a dedicated ACL data packet
* pool.
*/
int ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg)
{
ble_hci_acl_pool.mpe_put_cb = cb;
ble_hci_acl_pool.mpe_put_arg = arg;
return 0;
}
int ble_hci_trans_reset(void)
{
/* No work to do. All allocated buffers are owned by the host or
* controller, and they will get freed by their owners.
*/
return 0;
}
/**
* Allocates a buffer (mbuf) for ACL operation.
*
* @return The allocated buffer on success;
* NULL on buffer exhaustion.
*/
static struct os_mbuf *ble_hci_trans_acl_buf_alloc(void)
{
struct os_mbuf *m;
uint8_t usrhdr_len;
#if MYNEWT_VAL(BLE_DEVICE)
usrhdr_len = sizeof(struct ble_mbuf_hdr);
#elif MYNEWT_VAL(BLE_HS_FLOW_CTRL)
usrhdr_len = BLE_MBUF_HS_HDR_LEN;
#else
usrhdr_len = 0;
#endif
m = os_mbuf_get_pkthdr(&ble_hci_acl_mbuf_pool, usrhdr_len);
return m;
}
static void ble_hci_rx_acl(uint8_t *data, uint16_t len)
{
struct os_mbuf *m;
int rc;
int sr;
if (len < BLE_HCI_DATA_HDR_SZ || len > MYNEWT_VAL(BLE_ACL_BUF_SIZE)) {
return;
}
m = ble_hci_trans_acl_buf_alloc();
if (!m) {
ESP_LOGE(TAG, "%s failed to allocate ACL buffers; increase ACL_BUF_COUNT", __func__);
return;
}
if ((rc = os_mbuf_append(m, data, len)) != 0) {
ESP_LOGE(TAG, "%s failed to os_mbuf_append; rc = %d", __func__, rc);
os_mbuf_free_chain(m);
return;
}
OS_ENTER_CRITICAL(sr);
if (ble_hci_rx_acl_hs_cb) {
ble_hci_rx_acl_hs_cb(m, NULL);
}
OS_EXIT_CRITICAL(sr);
}
static void ble_hci_transport_init(void)
{
int rc;
/* Ensure this function only gets called by sysinit. */
SYSINIT_ASSERT_ACTIVE();
rc = os_mempool_ext_init(&ble_hci_acl_pool,
MYNEWT_VAL(BLE_ACL_BUF_COUNT),
ACL_BLOCK_SIZE,
ble_hci_acl_buf,
"ble_hci_acl_pool");
SYSINIT_PANIC_ASSERT(rc == 0);
rc = os_mbuf_pool_init(&ble_hci_acl_mbuf_pool,
&ble_hci_acl_pool.mpe_mp,
ACL_BLOCK_SIZE,
MYNEWT_VAL(BLE_ACL_BUF_COUNT));
SYSINIT_PANIC_ASSERT(rc == 0);
/*
* Create memory pool of HCI command buffers. NOTE: we currently dont
* allow this to be configured. The controller will only allow one
* outstanding command. We decided to keep this a pool in case we allow
* allow the controller to handle more than one outstanding command.
*/
rc = os_mempool_init(&ble_hci_cmd_pool,
1,
BLE_HCI_TRANS_CMD_SZ,
ble_hci_cmd_buf,
"ble_hci_cmd_pool");
SYSINIT_PANIC_ASSERT(rc == 0);
rc = os_mempool_init(&ble_hci_evt_hi_pool,
MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
ble_hci_evt_hi_buf,
"ble_hci_evt_hi_pool");
SYSINIT_PANIC_ASSERT(rc == 0);
rc = os_mempool_init(&ble_hci_evt_lo_pool,
MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
ble_hci_evt_lo_buf,
"ble_hci_evt_lo_pool");
SYSINIT_PANIC_ASSERT(rc == 0);
}
/*
* @brief: BT controller callback function, used to notify the upper layer that
* controller is ready to receive command
*/
static void controller_rcv_pkt_ready(void)
{
if (vhci_send_sem) {
xSemaphoreGive(vhci_send_sem);
}
}
/*
* @brief: BT controller callback function, to transfer data packet to the host
*/
static int host_rcv_pkt(uint8_t *data, uint16_t len)
{
if (data[0] == BLE_HCI_UART_H4_EVT) {
uint8_t *evbuf;
int totlen;
int rc;
totlen = BLE_HCI_EVENT_HDR_LEN + data[2];
assert(totlen <= UINT8_MAX + BLE_HCI_EVENT_HDR_LEN);
if (totlen > MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) {
ESP_LOGE(TAG, "Received HCI data length at host (%d) exceeds maximum configured HCI event buffer size (%d).",
totlen, MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE));
ble_hs_sched_reset(BLE_HS_ECONTROLLER);
return 0;
}
if (data[1] == BLE_HCI_EVCODE_HW_ERROR) {
assert(0);
}
/* Allocate LE Advertising Report Event from lo pool only */
if ((data[1] == BLE_HCI_EVCODE_LE_META) && (data[3] == BLE_HCI_LE_SUBEV_ADV_RPT)) {
evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO);
/* Skip advertising report if we're out of memory */
if (!evbuf) {
return 0;
}
} else {
evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
assert(evbuf != NULL);
}
memcpy(evbuf, &data[1], totlen);
rc = ble_hci_trans_ll_evt_tx(evbuf);
assert(rc == 0);
} else if (data[0] == BLE_HCI_UART_H4_ACL) {
ble_hci_rx_acl(data + 1, len - 1);
}
return 0;
}
static const esp_vhci_host_callback_t vhci_host_cb = {
.notify_host_send_available = controller_rcv_pkt_ready,
.notify_host_recv = host_rcv_pkt,
};
static void ble_buf_free(void)
{
os_msys_buf_free();
nimble_platform_mem_free(ble_hci_evt_hi_buf);
ble_hci_evt_hi_buf = NULL;
nimble_platform_mem_free(ble_hci_evt_lo_buf);
ble_hci_evt_lo_buf = NULL;
nimble_platform_mem_free(ble_hci_cmd_buf);
ble_hci_cmd_buf = NULL;
nimble_platform_mem_free(ble_hci_acl_buf);
ble_hci_acl_buf = NULL;
}
static esp_err_t ble_buf_alloc(void)
{
if (os_msys_buf_alloc()) {
return ESP_ERR_NO_MEM;
}
ble_hci_evt_hi_buf = (os_membuf_t *) nimble_platform_mem_calloc(1,
(sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))));
ble_hci_evt_lo_buf = (os_membuf_t *) nimble_platform_mem_calloc(1,
(sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))));
ble_hci_cmd_buf = (os_membuf_t *) nimble_platform_mem_calloc(1,
(sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ)));
ble_hci_acl_buf = (os_membuf_t *) nimble_platform_mem_calloc(1,
(sizeof(os_membuf_t) * OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT),
ACL_BLOCK_SIZE)));
if (!ble_hci_evt_hi_buf || !ble_hci_evt_lo_buf || !ble_hci_cmd_buf || !ble_hci_acl_buf) {
ble_buf_free();
return ESP_ERR_NO_MEM;
}
return ESP_OK;
}
esp_err_t esp_nimble_hci_init(void)
{
esp_err_t ret;
ret = ble_buf_alloc();
if (ret != ESP_OK) {
goto err;
}
if ((ret = esp_vhci_host_register_callback(&vhci_host_cb)) != ESP_OK) {
goto err;
}
ble_hci_transport_init();
vhci_send_sem = xSemaphoreCreateBinary();
if (vhci_send_sem == NULL) {
ret = ESP_ERR_NO_MEM;
goto err;
}
xSemaphoreGive(vhci_send_sem);
return ret;
err:
ble_buf_free();
return ret;
}
esp_err_t esp_nimble_hci_and_controller_init(void)
{
esp_err_t ret;
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
return ret;
}
if ((ret = esp_bt_controller_enable(ESP_BT_MODE_BLE)) != ESP_OK) {
return ret;
}
return esp_nimble_hci_init();
}
static esp_err_t ble_hci_transport_deinit(void)
{
int ret = 0;
ret += os_mempool_clear(&ble_hci_evt_lo_pool);
ret += os_mempool_clear(&ble_hci_evt_hi_pool);
ret += os_mempool_clear(&ble_hci_cmd_pool);
ret += os_mempool_ext_clear(&ble_hci_acl_pool);
if (ret) {
return ESP_FAIL;
} else {
return ESP_OK;
}
}
esp_err_t esp_nimble_hci_deinit(void)
{
if (vhci_send_sem) {
/* Dummy take & give semaphore before deleting */
xSemaphoreTake(vhci_send_sem, portMAX_DELAY);
xSemaphoreGive(vhci_send_sem);
vSemaphoreDelete(vhci_send_sem);
vhci_send_sem = NULL;
}
esp_err_t ret = ble_hci_transport_deinit();
if (ret != ESP_OK) {
return ret;
}
ble_buf_free();
return ESP_OK;
}
esp_err_t esp_nimble_hci_and_controller_deinit(void)
{
int ret;
ret = esp_nimble_hci_deinit();
if (ret != ESP_OK) {
return ret;
}
ret = esp_bt_controller_disable();
if (ret != ESP_OK) {
return ret;
}
ret = esp_bt_controller_deinit();
if (ret != ESP_OK) {
return ret;
}
return ESP_OK;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ESP_NIMBLE_MEM_H__
#define __ESP_NIMBLE_MEM_H__
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
void *nimble_platform_mem_malloc(size_t size);
void *nimble_platform_mem_calloc(size_t n, size_t size);
void nimble_platform_mem_free(void *ptr);
#ifdef __cplusplus
}
#endif
#endif /* __ESP_NIMBLE_MEM_H__ */

View File

@@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifdef ESP_PLATFORM
#include "esp_attr.h"
#include "esp_heap_caps.h"
#include "nimconfig.h"
#include "../include/esp_nimble_mem.h"
IRAM_ATTR void *nimble_platform_mem_malloc(size_t size)
{
#ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL
return heap_caps_malloc(size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_IRAM_8BIT
return heap_caps_malloc_prefer(size, 2, MALLOC_CAP_INTERNAL|MALLOC_CAP_IRAM_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#else
return malloc(size);
#endif
}
IRAM_ATTR void *nimble_platform_mem_calloc(size_t n, size_t size)
{
#ifdef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL
return heap_caps_calloc(n, size, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL
return heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT);
#elif CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_IRAM_8BIT
return heap_caps_calloc_prefer(n, size, 2, MALLOC_CAP_INTERNAL|MALLOC_CAP_IRAM_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
#else
return calloc(n, size);
#endif
}
IRAM_ATTR void nimble_platform_mem_free(void *ptr)
{
heap_caps_free(ptr);
}
#endif

View File

@@ -0,0 +1,15 @@
Architect:
Rafael Misoczki <rafael.misoczki@intel.com>
Open Source Maintainer:
Constanza Heath <constanza.m.heath@intel.com>
Rafael Misoczki <rafael.misoczki@intel.com>
Contributors:
Constanza Heath <constanza.m.heath@intel.com>
Rafael Misoczki <rafael.misoczki@intel.com>
Flavio Santes <flavio.santes@intel.com>
Jarkko Sakkinen <jarkko.sakkinen@intel.com>
Chris Morrison
Marti Bolivar
Colin Ian King

View File

@@ -0,0 +1,61 @@
================================================================================
TinyCrypt Cryptographic Library
================================================================================
Copyright (c) 2017, Intel Corporation. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of the Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================================================
Copyright (c) 2014, Kenneth MacKay
All rights reserved.
https://github.com/kmackay/micro-ecc
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================================================

View File

@@ -0,0 +1,71 @@
================================================================================
TinyCrypt Cryptographic Library
================================================================================
Copyright (c) 2017, Intel Corporation. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of the Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================================================
Overview:
The TinyCrypt Library provides an implementation for constrained devices of a
minimal set of standard cryptography primitives.
Please, ***SEE THE DOCUMENTATION*** folder for more information on the supported
cryptographic primitives and the limitations of TinyCrypt library. For usage,
security and technicalities, please see the corresponding header file of each
cryptographic primitive.
================================================================================
Organization:
/lib: C source code of the cryptographic primitives.
/lib/include/tinycrypt: C header files of the cryptographic primitives.
/tests: Test vectors of the cryptographic primitives.
/doc: Documentation of TinyCrypt.
================================================================================
Building:
1) In Makefile.conf set:
- CFLAGS for compiler flags.
- CC for compiler.
- ENABLE_TESTS for enabling (true) or disabling (false) tests compilation.
2) In lib/Makefile select the primitives required by your project.
3) In tests/Makefile select the corresponding tests of the selected primitives.
4) make
5) run tests in tests/
================================================================================

View File

@@ -0,0 +1 @@
0.2.8

View File

@@ -0,0 +1,352 @@
TinyCrypt Cryptographic Library
###############################
Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
Overview
********
The TinyCrypt Library provides an implementation for targeting constrained devices
with a minimal set of standard cryptography primitives, as listed below. To better
serve applications targeting constrained devices, TinyCrypt implementations differ
from the standard specifications (see the Important Remarks section for some
important differences). Certain cryptographic primitives depend on other
primitives, as mentioned in the list below.
Aside from the Important Remarks section below, valuable information on the usage,
security and technicalities of each cryptographic primitive are found in the
corresponding header file.
* SHA-256:
* Type of primitive: Hash function.
* Standard Specification: NIST FIPS PUB 180-4.
* Requires: --
* HMAC-SHA256:
* Type of primitive: Message authentication code.
* Standard Specification: RFC 2104.
* Requires: SHA-256
* HMAC-PRNG:
* Type of primitive: Pseudo-random number generator (256-bit strength).
* Standard Specification: NIST SP 800-90A.
* Requires: SHA-256 and HMAC-SHA256.
* AES-128:
* Type of primitive: Block cipher.
* Standard Specification: NIST FIPS PUB 197.
* Requires: --
* AES-CBC mode:
* Type of primitive: Encryption mode of operation.
* Standard Specification: NIST SP 800-38A.
* Requires: AES-128.
* AES-CTR mode:
* Type of primitive: Encryption mode of operation.
* Standard Specification: NIST SP 800-38A.
* Requires: AES-128.
* AES-CMAC mode:
* Type of primitive: Message authentication code.
* Standard Specification: NIST SP 800-38B.
* Requires: AES-128.
* AES-CCM mode:
* Type of primitive: Authenticated encryption.
* Standard Specification: NIST SP 800-38C.
* Requires: AES-128.
* CTR-PRNG:
* Type of primitive: Pseudo-random number generator (128-bit strength).
* Standard Specification: NIST SP 800-90A.
* Requires: AES-128.
* ECC-DH:
* Type of primitive: Key exchange based on curve NIST p-256.
* Standard Specification: RFC 6090.
* Requires: ECC auxiliary functions (ecc.h/c).
* ECC-DSA:
* Type of primitive: Digital signature based on curve NIST p-256.
* Standard Specification: RFC 6090.
* Requires: ECC auxiliary functions (ecc.h/c).
Design Goals
************
* Minimize the code size of each cryptographic primitive. This means minimize
the size of a platform-independent implementation, as presented in TinyCrypt.
Note that various applications may require further features, optimizations with
respect to other metrics and countermeasures for particular threats. These
peculiarities would increase the code size and thus are not considered here.
* Minimize the dependencies among the cryptographic primitives. This means
that it is unnecessary to build and allocate object code for more primitives
than the ones strictly required by the intended application. In other words,
one can select and compile only the primitives required by the application.
Important Remarks
*****************
The cryptographic implementations in TinyCrypt library have some limitations.
Some of these limitations are inherent to the cryptographic primitives
themselves, while others are specific to TinyCrypt. These limitations were accepted
in order to meet its design goals (in special, minimal code size) and to better
serve applications targeting constrained devices in general. Some of these
limitations are discussed in-depth below.
General Remarks
***************
* TinyCrypt does **not** intend to be fully side-channel resistant. Due to the
variety of side-channel attacks, many of them only relevant to certain
platforms. In this sense, instead of penalizing all library users with
side-channel countermeasures such as increasing the overall code size,
TinyCrypt only implements certain generic timing-attack countermeasures.
Specific Remarks
****************
* SHA-256:
* The number of bits_hashed in the state is not checked for overflow. Note
however that this will only be a problem if you intend to hash more than
2^64 bits, which is an extremely large window.
* HMAC:
* The HMAC verification process is assumed to be performed by the application.
This compares the computed tag with some given tag.
Note that conventional memory-comparison methods (such as memcmp function)
might be vulnerable to timing attacks; thus be sure to use a constant-time
memory comparison function (such as compare_constant_time
function provided in lib/utils.c).
* The tc_hmac_final function, responsible for computing the message tag,
cleans the state context before exiting. Thus, applications do not need to
clean the TCHmacState_t ctx after calling tc_hmac_final. This should not
be changed in future versions of the library as there are applications
currently relying on this good-practice/feature of TinyCrypt.
* HMAC-PRNG:
* Before using HMAC-PRNG, you *must* find an entropy source to produce a seed.
PRNGs only stretch the seed into a seemingly random output of arbitrary
length. The security of the output is exactly equal to the
unpredictability of the seed.
* NIST SP 800-90A requires three items as seed material in the initialization
step: entropy seed, personalization and a nonce (which is not implemented).
TinyCrypt requires the personalization byte array and automatically creates
the entropy seed using a mandatory call to the re-seed function.
* AES-128:
* The current implementation does not support other key-lengths (such as 256
bits). Note that if you need AES-256, it doesn't sound as though your
application is running in a constrained environment. AES-256 requires keys
twice the size as for AES-128, and the key schedule is 40% larger.
* CTR mode:
* The AES-CTR mode limits the size of a data message they encrypt to 2^32
blocks. If you need to encrypt larger data sets, your application would
need to replace the key after 2^32 block encryptions.
* CTR-PRNG:
* Before using CTR-PRNG, you *must* find an entropy source to produce a seed.
PRNGs only stretch the seed into a seemingly random output of arbitrary
length. The security of the output is exactly equal to the
unpredictability of the seed.
* CBC mode:
* TinyCrypt CBC decryption assumes that the iv and the ciphertext are
contiguous (as produced by TinyCrypt CBC encryption). This allows for a
very efficient decryption algorithm that would not otherwise be possible.
* CMAC mode:
* AES128-CMAC mode of operation offers 64 bits of security against collision
attacks. Note however that an external attacker cannot generate the tags
him/herself without knowing the MAC key. In this sense, to attack the
collision property of AES128-CMAC, an external attacker would need the
cooperation of the legal user to produce an exponentially high number of
tags (e.g. 2^64) to finally be able to look for collisions and benefit
from them. As an extra precaution, the current implementation allows to at
most 2^48 calls to tc_cmac_update function before re-calling tc_cmac_setup
(allowing a new key to be set), as suggested in Appendix B of SP 800-38B.
* CCM mode:
* There are a few tradeoffs for the selection of the parameters of CCM mode.
In special, there is a tradeoff between the maximum number of invocations
of CCM under a given key and the maximum payload length for those
invocations. Both things are related to the parameter 'q' of CCM mode. The
maximum number of invocations of CCM under a given key is determined by
the nonce size, which is: 15-q bytes. The maximum payload length for those
invocations is defined as 2^(8q) bytes.
To achieve minimal code size, TinyCrypt CCM implementation fixes q = 2,
which is a quite reasonable choice for constrained applications. The
implications of this choice are:
The nonce size is: 13 bytes.
The maximum payload length is: 2^16 bytes = 65 KB.
The mac size parameter is an important parameter to estimate the security
against collision attacks (that aim at finding different messages that
produce the same authentication tag). TinyCrypt CCM implementation
accepts any even integer between 4 and 16, as suggested in SP 800-38C.
* TinyCrypt CCM implementation accepts associated data of any length between
0 and (2^16 - 2^8) = 65280 bytes.
* TinyCrypt CCM implementation accepts:
* Both non-empty payload and associated data (it encrypts and
authenticates the payload and only authenticates the associated data);
* Non-empty payload and empty associated data (it encrypts and
authenticates the payload);
* Non-empty associated data and empty payload (it degenerates to an
authentication-only mode on the associated data).
* RFC-3610, which also specifies CCM, presents a few relevant security
suggestions, such as: it is recommended for most applications to use a
mac size greater than 8. Besides, it is emphasized that the usage of the
same nonce for two different messages which are encrypted with the same
key obviously destroys the security properties of CCM mode.
* ECC-DH and ECC-DSA:
* TinyCrypt ECC implementation is based on micro-ecc (see
https://github.com/kmackay/micro-ecc). In the original micro-ecc
documentation, there is an important remark about the way integers are
represented:
"Integer representation: To reduce code size, all large integers are
represented using little-endian words - so the least significant word is
first. You can use the 'ecc_bytes2native()' and 'ecc_native2bytes()'
functions to convert between the native integer representation and the
standardized octet representation."
Note that the assumed bit layout is: {31, 30, ..., 0}, {63, 62, ..., 32},
{95, 94, ..., 64}, {127, 126, ..., 96} for a very-long-integer (vli)
consisting of 4 unsigned integers (as an example).
* A cryptographically-secure PRNG function must be set (using uECC_set_rng())
before calling uECC_make_key() or uECC_sign().
Examples of Applications
************************
It is possible to do useful cryptography with only the given small set of
primitives. With this list of primitives it becomes feasible to support a range
of cryptography usages:
* Measurement of code, data structures, and other digital artifacts (SHA256);
* Generate commitments (SHA256);
* Construct keys (HMAC-SHA256);
* Extract entropy from strings containing some randomness (HMAC-SHA256);
* Construct random mappings (HMAC-SHA256);
* Construct nonces and challenges (HMAC-PRNG, CTR-PRNG);
* Authenticate using a shared secret (HMAC-SHA256);
* Create an authenticated, replay-protected session (HMAC-SHA256 + HMAC-PRNG);
* Authenticated encryption (AES-128 + AES-CCM);
* Key-exchange (EC-DH);
* Digital signature (EC-DSA);
Test Vectors
************
The library provides a test program for each cryptographic primitive (see 'test'
folder). Besides illustrating how to use the primitives, these tests evaluate
the correctness of the implementations by checking the results against
well-known publicly validated test vectors.
For the case of the HMAC-PRNG, due to the necessity of performing an extensive
battery test to produce meaningful conclusions, we suggest the user to evaluate
the unpredictability of the implementation by using the NIST Statistical Test
Suite (see References).
For the case of the EC-DH and EC-DSA implementations, most of the test vectors
were obtained from the site of the NIST Cryptographic Algorithm Validation
Program (CAVP), see References.
References
**********
* `NIST FIPS PUB 180-4 (SHA-256)`_
.. _NIST FIPS PUB 180-4 (SHA-256):
http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
* `NIST FIPS PUB 197 (AES-128)`_
.. _NIST FIPS PUB 197 (AES-128):
http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
* `NIST SP800-90A (HMAC-PRNG)`_
.. _NIST SP800-90A (HMAC-PRNG):
http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf
* `NIST SP 800-38A (AES-CBC and AES-CTR)`_
.. _NIST SP 800-38A (AES-CBC and AES-CTR):
http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
* `NIST SP 800-38B (AES-CMAC)`_
.. _NIST SP 800-38B (AES-CMAC):
http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf
* `NIST SP 800-38C (AES-CCM)`_
.. _NIST SP 800-38C (AES-CCM):
http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
* `NIST Statistical Test Suite (useful for testing HMAC-PRNG)`_
.. _NIST Statistical Test Suite (useful for testing HMAC-PRNG):
http://csrc.nist.gov/groups/ST/toolkit/rng/documentation_software.html
* `NIST Cryptographic Algorithm Validation Program (CAVP) site`_
.. _NIST Cryptographic Algorithm Validation Program (CAVP) site:
http://csrc.nist.gov/groups/STM/cavp/
* `RFC 2104 (HMAC-SHA256)`_
.. _RFC 2104 (HMAC-SHA256):
https://www.ietf.org/rfc/rfc2104.txt
* `RFC 6090 (ECC-DH and ECC-DSA)`_
.. _RFC 6090 (ECC-DH and ECC-DSA):
https://www.ietf.org/rfc/rfc6090.txt

View File

@@ -0,0 +1,130 @@
/* aes.h - TinyCrypt interface to an AES-128 implementation */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief -- Interface to an AES-128 implementation.
*
* Overview: AES-128 is a NIST approved block cipher specified in
* FIPS 197. Block ciphers are deterministic algorithms that
* perform a transformation specified by a symmetric key in fixed-
* length data sets, also called blocks.
*
* Security: AES-128 provides approximately 128 bits of security.
*
* Usage: 1) call tc_aes128_set_encrypt/decrypt_key to set the key.
*
* 2) call tc_aes_encrypt/decrypt to process the data.
*/
#ifndef __TC_AES_H__
#define __TC_AES_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define Nb (4) /* number of columns (32-bit words) comprising the state */
#define Nk (4) /* number of 32-bit words comprising the key */
#define Nr (10) /* number of rounds */
#define TC_AES_BLOCK_SIZE (Nb*Nk)
#define TC_AES_KEY_SIZE (Nb*Nk)
typedef struct tc_aes_key_sched_struct {
unsigned int words[Nb*(Nr+1)];
} *TCAesKeySched_t;
/**
* @brief Set AES-128 encryption key
* Uses key k to initialize s
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL
* @note This implementation skips the additional steps required for keys
* larger than 128 bits, and must not be used for AES-192 or
* AES-256 key schedule -- see FIPS 197 for details
* @param s IN/OUT -- initialized struct tc_aes_key_sched_struct
* @param k IN -- points to the AES key
*/
int tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k);
/**
* @brief AES-128 Encryption procedure
* Encrypts contents of in buffer into out buffer under key;
* schedule s
* @note Assumes s was initialized by aes_set_encrypt_key;
* out and in point to 16 byte buffers
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if: out == NULL or in == NULL or s == NULL
* @param out IN/OUT -- buffer to receive ciphertext block
* @param in IN -- a plaintext block to encrypt
* @param s IN -- initialized AES key schedule
*/
int tc_aes_encrypt(uint8_t *out, const uint8_t *in,
const TCAesKeySched_t s);
/**
* @brief Set the AES-128 decryption key
* Uses key k to initialize s
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL
* @note This is the implementation of the straightforward inverse cipher
* using the cipher documented in FIPS-197 figure 12, not the
* equivalent inverse cipher presented in Figure 15
* @warning This routine skips the additional steps required for keys larger
* than 128, and must not be used for AES-192 or AES-256 key
* schedule -- see FIPS 197 for details
* @param s IN/OUT -- initialized struct tc_aes_key_sched_struct
* @param k IN -- points to the AES key
*/
int tc_aes128_set_decrypt_key(TCAesKeySched_t s, const uint8_t *k);
/**
* @brief AES-128 Encryption procedure
* Decrypts in buffer into out buffer under key schedule s
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if: out is NULL or in is NULL or s is NULL
* @note Assumes s was initialized by aes_set_encrypt_key
* out and in point to 16 byte buffers
* @param out IN/OUT -- buffer to receive ciphertext block
* @param in IN -- a plaintext block to encrypt
* @param s IN -- initialized AES key schedule
*/
int tc_aes_decrypt(uint8_t *out, const uint8_t *in,
const TCAesKeySched_t s);
#ifdef __cplusplus
}
#endif
#endif /* __TC_AES_H__ */

View File

@@ -0,0 +1,151 @@
/* cbc_mode.h - TinyCrypt interface to a CBC mode implementation */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief Interface to a CBC mode implementation.
*
* Overview: CBC (for "cipher block chaining") mode is a NIST approved mode of
* operation defined in SP 800-38a. It can be used with any block
* cipher to provide confidentiality of strings whose lengths are
* multiples of the block_size of the underlying block cipher.
* TinyCrypt hard codes AES as the block cipher.
*
* Security: CBC mode provides data confidentiality given that the maximum
* number q of blocks encrypted under a single key satisfies
* q < 2^63, which is not a practical constraint (it is considered a
* good practice to replace the encryption when q == 2^56). CBC mode
* provides NO data integrity.
*
* CBC mode assumes that the IV value input into the
* tc_cbc_mode_encrypt is randomly generated. The TinyCrypt library
* provides HMAC-PRNG module, which generates suitable IVs. Other
* methods for generating IVs are acceptable, provided that the
* values of the IVs generated appear random to any adversary,
* including someone with complete knowledge of the system design.
*
* The randomness property on which CBC mode's security depends is
* the unpredictability of the IV. Since it is unpredictable, this
* means in practice that CBC mode requires that the IV is stored
* somehow with the ciphertext in order to recover the plaintext.
*
* TinyCrypt CBC encryption prepends the IV to the ciphertext,
* because this affords a more efficient (few buffers) decryption.
* Hence tc_cbc_mode_encrypt assumes the ciphertext buffer is always
* 16 bytes larger than the plaintext buffer.
*
* Requires: AES-128
*
* Usage: 1) call tc_cbc_mode_encrypt to encrypt data.
*
* 2) call tc_cbc_mode_decrypt to decrypt data.
*
*/
#ifndef __TC_CBC_MODE_H__
#define __TC_CBC_MODE_H__
#include "aes.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief CBC encryption procedure
* CBC encrypts inlen bytes of the in buffer into the out buffer
* using the encryption key schedule provided, prepends iv to out
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* out == NULL or
* in == NULL or
* ctr == NULL or
* sched == NULL or
* inlen == 0 or
* (inlen % TC_AES_BLOCK_SIZE) != 0 or
* (outlen % TC_AES_BLOCK_SIZE) != 0 or
* outlen != inlen + TC_AES_BLOCK_SIZE
* @note Assumes: - sched has been configured by aes_set_encrypt_key
* - iv contains a 16 byte random string
* - out buffer is large enough to hold the ciphertext + iv
* - out buffer is a contiguous buffer
* - in holds the plaintext and is a contiguous buffer
* - inlen gives the number of bytes in the in buffer
* @param out IN/OUT -- buffer to receive the ciphertext
* @param outlen IN -- length of ciphertext buffer in bytes
* @param in IN -- plaintext to encrypt
* @param inlen IN -- length of plaintext buffer in bytes
* @param iv IN -- the IV for the this encrypt/decrypt
* @param sched IN -- AES key schedule for this encrypt
*/
int tc_cbc_mode_encrypt(uint8_t *out, unsigned int outlen, const uint8_t *in,
unsigned int inlen, const uint8_t *iv,
const TCAesKeySched_t sched);
/**
* @brief CBC decryption procedure
* CBC decrypts inlen bytes of the in buffer into the out buffer
* using the provided encryption key schedule
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* out == NULL or
* in == NULL or
* sched == NULL or
* inlen == 0 or
* outlen == 0 or
* (inlen % TC_AES_BLOCK_SIZE) != 0 or
* (outlen % TC_AES_BLOCK_SIZE) != 0 or
* outlen != inlen + TC_AES_BLOCK_SIZE
* @note Assumes:- in == iv + ciphertext, i.e. the iv and the ciphertext are
* contiguous. This allows for a very efficient decryption
* algorithm that would not otherwise be possible
* - sched was configured by aes_set_decrypt_key
* - out buffer is large enough to hold the decrypted plaintext
* and is a contiguous buffer
* - inlen gives the number of bytes in the in buffer
* @param out IN/OUT -- buffer to receive decrypted data
* @param outlen IN -- length of plaintext buffer in bytes
* @param in IN -- ciphertext to decrypt, including IV
* @param inlen IN -- length of ciphertext buffer in bytes
* @param iv IN -- the IV for the this encrypt/decrypt
* @param sched IN -- AES key schedule for this decrypt
*
*/
int tc_cbc_mode_decrypt(uint8_t *out, unsigned int outlen, const uint8_t *in,
unsigned int inlen, const uint8_t *iv,
const TCAesKeySched_t sched);
#ifdef __cplusplus
}
#endif
#endif /* __TC_CBC_MODE_H__ */

View File

@@ -0,0 +1,211 @@
/* ccm_mode.h - TinyCrypt interface to a CCM mode implementation */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief Interface to a CCM mode implementation.
*
* Overview: CCM (for "Counter with CBC-MAC") mode is a NIST approved mode of
* operation defined in SP 800-38C.
*
* TinyCrypt CCM implementation accepts:
*
* 1) Both non-empty payload and associated data (it encrypts and
* authenticates the payload and also authenticates the associated
* data);
* 2) Non-empty payload and empty associated data (it encrypts and
* authenticates the payload);
* 3) Non-empty associated data and empty payload (it degenerates to
* an authentication mode on the associated data).
*
* TinyCrypt CCM implementation accepts associated data of any length
* between 0 and (2^16 - 2^8) bytes.
*
* Security: The mac length parameter is an important parameter to estimate the
* security against collision attacks (that aim at finding different
* messages that produce the same authentication tag). TinyCrypt CCM
* implementation accepts any even integer between 4 and 16, as
* suggested in SP 800-38C.
*
* RFC-3610, which also specifies CCM, presents a few relevant
* security suggestions, such as: it is recommended for most
* applications to use a mac length greater than 8. Besides, the
* usage of the same nonce for two different messages which are
* encrypted with the same key destroys the security of CCM mode.
*
* Requires: AES-128
*
* Usage: 1) call tc_ccm_config to configure.
*
* 2) call tc_ccm_mode_encrypt to encrypt data and generate tag.
*
* 3) call tc_ccm_mode_decrypt to decrypt data and verify tag.
*/
#ifndef __TC_CCM_MODE_H__
#define __TC_CCM_MODE_H__
#include "aes.h"
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* max additional authenticated size in bytes: 2^16 - 2^8 = 65280 */
#define TC_CCM_AAD_MAX_BYTES 0xff00
/* max message size in bytes: 2^(8L) = 2^16 = 65536 */
#define TC_CCM_PAYLOAD_MAX_BYTES 0x10000
/* struct tc_ccm_mode_struct represents the state of a CCM computation */
typedef struct tc_ccm_mode_struct {
TCAesKeySched_t sched; /* AES key schedule */
uint8_t *nonce; /* nonce required by CCM */
unsigned int mlen; /* mac length in bytes (parameter t in SP-800 38C) */
} *TCCcmMode_t;
/**
* @brief CCM configuration procedure
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* c == NULL or
* sched == NULL or
* nonce == NULL or
* mlen != {4, 6, 8, 10, 12, 16}
* @param c -- CCM state
* @param sched IN -- AES key schedule
* @param nonce IN - nonce
* @param nlen -- nonce length in bytes
* @param mlen -- mac length in bytes (parameter t in SP-800 38C)
*/
int tc_ccm_config(TCCcmMode_t c, TCAesKeySched_t sched, uint8_t *nonce,
unsigned int nlen, unsigned int mlen);
/**
* @brief CCM tag generation and encryption procedure
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* out == NULL or
* c == NULL or
* ((plen > 0) and (payload == NULL)) or
* ((alen > 0) and (associated_data == NULL)) or
* (alen >= TC_CCM_AAD_MAX_BYTES) or
* (plen >= TC_CCM_PAYLOAD_MAX_BYTES) or
* (olen < plen + maclength)
*
* @param out OUT -- encrypted data
* @param olen IN -- output length in bytes
* @param associated_data IN -- associated data
* @param alen IN -- associated data length in bytes
* @param payload IN -- payload
* @param plen IN -- payload length in bytes
* @param c IN -- CCM state
*
* @note: out buffer should be at least (plen + c->mlen) bytes long.
*
* @note: The sequence b for encryption is formatted as follows:
* b = [FLAGS | nonce | counter ], where:
* FLAGS is 1 byte long
* nonce is 13 bytes long
* counter is 2 bytes long
* The byte FLAGS is composed by the following 8 bits:
* 0-2 bits: used to represent the value of q-1
* 3-7 btis: always 0's
*
* @note: The sequence b for authentication is formatted as follows:
* b = [FLAGS | nonce | length(mac length)], where:
* FLAGS is 1 byte long
* nonce is 13 bytes long
* length(mac length) is 2 bytes long
* The byte FLAGS is composed by the following 8 bits:
* 0-2 bits: used to represent the value of q-1
* 3-5 bits: mac length (encoded as: (mlen-2)/2)
* 6: Adata (0 if alen == 0, and 1 otherwise)
* 7: always 0
*/
int tc_ccm_generation_encryption(uint8_t *out, unsigned int olen,
const uint8_t *associated_data,
unsigned int alen, const uint8_t *payload,
unsigned int plen, TCCcmMode_t c);
/**
* @brief CCM decryption and tag verification procedure
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* out == NULL or
* c == NULL or
* ((plen > 0) and (payload == NULL)) or
* ((alen > 0) and (associated_data == NULL)) or
* (alen >= TC_CCM_AAD_MAX_BYTES) or
* (plen >= TC_CCM_PAYLOAD_MAX_BYTES) or
* (olen < plen - c->mlen)
*
* @param out OUT -- decrypted data
* @param associated_data IN -- associated data
* @param alen IN -- associated data length in bytes
* @param payload IN -- payload
* @param plen IN -- payload length in bytes
* @param c IN -- CCM state
*
* @note: out buffer should be at least (plen - c->mlen) bytes long.
*
* @note: The sequence b for encryption is formatted as follows:
* b = [FLAGS | nonce | counter ], where:
* FLAGS is 1 byte long
* nonce is 13 bytes long
* counter is 2 bytes long
* The byte FLAGS is composed by the following 8 bits:
* 0-2 bits: used to represent the value of q-1
* 3-7 btis: always 0's
*
* @note: The sequence b for authentication is formatted as follows:
* b = [FLAGS | nonce | length(mac length)], where:
* FLAGS is 1 byte long
* nonce is 13 bytes long
* length(mac length) is 2 bytes long
* The byte FLAGS is composed by the following 8 bits:
* 0-2 bits: used to represent the value of q-1
* 3-5 bits: mac length (encoded as: (mlen-2)/2)
* 6: Adata (0 if alen == 0, and 1 otherwise)
* 7: always 0
*/
int tc_ccm_decryption_verification(uint8_t *out, unsigned int olen,
const uint8_t *associated_data,
unsigned int alen, const uint8_t *payload, unsigned int plen,
TCCcmMode_t c);
#ifdef __cplusplus
}
#endif
#endif /* __TC_CCM_MODE_H__ */

View File

@@ -0,0 +1,194 @@
/* cmac_mode.h -- interface to a CMAC implementation */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief Interface to a CMAC implementation.
*
* Overview: CMAC is defined NIST in SP 800-38B, and is the standard algorithm
* for computing a MAC using a block cipher. It can compute the MAC
* for a byte string of any length. It is distinguished from CBC-MAC
* in the processing of the final message block; CMAC uses a
* different technique to compute the final message block is full
* size or only partial, while CBC-MAC uses the same technique for
* both. This difference permits CMAC to be applied to variable
* length messages, while all messages authenticated by CBC-MAC must
* be the same length.
*
* Security: AES128-CMAC mode of operation offers 64 bits of security against
* collision attacks. Note however that an external attacker cannot
* generate the tags him/herself without knowing the MAC key. In this
* sense, to attack the collision property of AES128-CMAC, an
* external attacker would need the cooperation of the legal user to
* produce an exponentially high number of tags (e.g. 2^64) to
* finally be able to look for collisions and benefit from them. As
* an extra precaution, the current implementation allows to at most
* 2^48 calls to the tc_cmac_update function before re-calling
* tc_cmac_setup (allowing a new key to be set), as suggested in
* Appendix B of SP 800-38B.
*
* Requires: AES-128
*
* Usage: This implementation provides a "scatter-gather" interface, so that
* the CMAC value can be computed incrementally over a message
* scattered in different segments throughout memory. Experience shows
* this style of interface tends to minimize the burden of programming
* correctly. Like all symmetric key operations, it is session
* oriented.
*
* To begin a CMAC session, use tc_cmac_setup to initialize a struct
* tc_cmac_struct with encryption key and buffer. Our implementation
* always assume that the AES key to be the same size as the block
* cipher block size. Once setup, this data structure can be used for
* many CMAC computations.
*
* Once the state has been setup with a key, computing the CMAC of
* some data requires three steps:
*
* (1) first use tc_cmac_init to initialize a new CMAC computation.
* (2) next mix all of the data into the CMAC computation state using
* tc_cmac_update. If all of the data resides in a single data
* segment then only one tc_cmac_update call is needed; if data
* is scattered throughout memory in n data segments, then n calls
* will be needed. CMAC IS ORDER SENSITIVE, to be able to detect
* attacks that swap bytes, so the order in which data is mixed
* into the state is critical!
* (3) Once all of the data for a message has been mixed, use
* tc_cmac_final to compute the CMAC tag value.
*
* Steps (1)-(3) can be repeated as many times as you want to CMAC
* multiple messages. A practical limit is 2^48 1K messages before you
* have to change the key.
*
* Once you are done computing CMAC with a key, it is a good idea to
* destroy the state so an attacker cannot recover the key; use
* tc_cmac_erase to accomplish this.
*/
#ifndef __TC_CMAC_MODE_H__
#define __TC_CMAC_MODE_H__
#include "aes.h"
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* padding for last message block */
#define TC_CMAC_PADDING 0x80
/* struct tc_cmac_struct represents the state of a CMAC computation */
typedef struct tc_cmac_struct {
/* initialization vector */
uint8_t iv[TC_AES_BLOCK_SIZE];
/* used if message length is a multiple of block_size bytes */
uint8_t K1[TC_AES_BLOCK_SIZE];
/* used if message length isn't a multiple block_size bytes */
uint8_t K2[TC_AES_BLOCK_SIZE];
/* where to put bytes that didn't fill a block */
uint8_t leftover[TC_AES_BLOCK_SIZE];
/* identifies the encryption key */
unsigned int keyid;
/* next available leftover location */
unsigned int leftover_offset;
/* AES key schedule */
TCAesKeySched_t sched;
/* calls to tc_cmac_update left before re-key */
uint64_t countdown;
} *TCCmacState_t;
/**
* @brief Configures the CMAC state to use the given AES key
* @return returns TC_CRYPTO_SUCCESS (1) after having configured the CMAC state
* returns TC_CRYPTO_FAIL (0) if:
* s == NULL or
* key == NULL
*
* @param s IN/OUT -- the state to set up
* @param key IN -- the key to use
* @param sched IN -- AES key schedule
*/
int tc_cmac_setup(TCCmacState_t s, const uint8_t *key,
TCAesKeySched_t sched);
/**
* @brief Erases the CMAC state
* @return returns TC_CRYPTO_SUCCESS (1) after having configured the CMAC state
* returns TC_CRYPTO_FAIL (0) if:
* s == NULL
*
* @param s IN/OUT -- the state to erase
*/
int tc_cmac_erase(TCCmacState_t s);
/**
* @brief Initializes a new CMAC computation
* @return returns TC_CRYPTO_SUCCESS (1) after having initialized the CMAC state
* returns TC_CRYPTO_FAIL (0) if:
* s == NULL
*
* @param s IN/OUT -- the state to initialize
*/
int tc_cmac_init(TCCmacState_t s);
/**
* @brief Incrementally computes CMAC over the next data segment
* @return returns TC_CRYPTO_SUCCESS (1) after successfully updating the CMAC state
* returns TC_CRYPTO_FAIL (0) if:
* s == NULL or
* if data == NULL when dlen > 0
*
* @param s IN/OUT -- the CMAC state
* @param data IN -- the next data segment to MAC
* @param dlen IN -- the length of data in bytes
*/
int tc_cmac_update(TCCmacState_t s, const uint8_t *data, size_t dlen);
/**
* @brief Generates the tag from the CMAC state
* @return returns TC_CRYPTO_SUCCESS (1) after successfully generating the tag
* returns TC_CRYPTO_FAIL (0) if:
* tag == NULL or
* s == NULL
*
* @param tag OUT -- the CMAC tag
* @param s IN -- CMAC state
*/
int tc_cmac_final(uint8_t *tag, TCCmacState_t s);
#ifdef __cplusplus
}
#endif
#endif /* __TC_CMAC_MODE_H__ */

View File

@@ -0,0 +1,61 @@
/* constants.h - TinyCrypt interface to constants */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief -- Interface to constants.
*
*/
#ifndef __TC_CONSTANTS_H__
#define __TC_CONSTANTS_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#ifndef NULL
#define NULL ((void *)0)
#endif
#define TC_CRYPTO_SUCCESS 1
#define TC_CRYPTO_FAIL 0
#define TC_ZERO_BYTE 0x00
#ifdef __cplusplus
}
#endif
#endif /* __TC_CONSTANTS_H__ */

View File

@@ -0,0 +1,108 @@
/* ctr_mode.h - TinyCrypt interface to CTR mode */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief Interface to CTR mode.
*
* Overview: CTR (pronounced "counter") mode is a NIST approved mode of
* operation defined in SP 800-38a. It can be used with any
* block cipher to provide confidentiality of strings of any
* length. TinyCrypt hard codes AES128 as the block cipher.
*
* Security: CTR mode achieves confidentiality only if the counter value is
* never reused with a same encryption key. If the counter is
* repeated, than an adversary might be able to defeat the scheme.
*
* A usual method to ensure different counter values refers to
* initialize the counter in a given value (0, for example) and
* increases it every time a new block is enciphered. This naturally
* leaves to a limitation on the number q of blocks that can be
* enciphered using a same key: q < 2^(counter size).
*
* TinyCrypt uses a counter of 32 bits. This means that after 2^32
* block encryptions, the counter will be reused (thus losing CBC
* security). 2^32 block encryptions should be enough for most of
* applications targeting constrained devices. Applications intended
* to encrypt a larger number of blocks must replace the key after
* 2^32 block encryptions.
*
* CTR mode provides NO data integrity.
*
* Requires: AES-128
*
* Usage: 1) call tc_ctr_mode to process the data to encrypt/decrypt.
*
*/
#ifndef __TC_CTR_MODE_H__
#define __TC_CTR_MODE_H__
#include "aes.h"
#include "constants.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief CTR mode encryption/decryption procedure.
* CTR mode encrypts (or decrypts) inlen bytes from in buffer into out buffer
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* out == NULL or
* in == NULL or
* ctr == NULL or
* sched == NULL or
* inlen == 0 or
* outlen == 0 or
* inlen != outlen
* @note Assumes:- The current value in ctr has NOT been used with sched
* - out points to inlen bytes
* - in points to inlen bytes
* - ctr is an integer counter in littleEndian format
* - sched was initialized by aes_set_encrypt_key
* @param out OUT -- produced ciphertext (plaintext)
* @param outlen IN -- length of ciphertext buffer in bytes
* @param in IN -- data to encrypt (or decrypt)
* @param inlen IN -- length of input data in bytes
* @param ctr IN/OUT -- the current counter value
* @param sched IN -- an initialized AES key schedule
*/
int tc_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in,
unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched);
#ifdef __cplusplus
}
#endif
#endif /* __TC_CTR_MODE_H__ */

View File

@@ -0,0 +1,166 @@
/* ctr_prng.h - TinyCrypt interface to a CTR-PRNG implementation */
/*
* Copyright (c) 2016, Chris Morrison
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief Interface to a CTR-PRNG implementation.
*
* Overview: A pseudo-random number generator (PRNG) generates a sequence
* of numbers that have a distribution close to the one expected
* for a sequence of truly random numbers. The NIST Special
* Publication 800-90A specifies several mechanisms to generate
* sequences of pseudo random numbers, including the CTR-PRNG one
* which is based on AES. TinyCrypt implements CTR-PRNG with
* AES-128.
*
* Security: A cryptographically secure PRNG depends on the existence of an
* entropy source to provide a truly random seed as well as the
* security of the primitives used as the building blocks (AES-128
* in this instance).
*
* Requires: - AES-128
*
* Usage: 1) call tc_ctr_prng_init to seed the prng context
*
* 2) call tc_ctr_prng_reseed to mix in additional entropy into
* the prng context
*
* 3) call tc_ctr_prng_generate to output the pseudo-random data
*
* 4) call tc_ctr_prng_uninstantiate to zero out the prng context
*/
#ifndef __TC_CTR_PRNG_H__
#define __TC_CTR_PRNG_H__
#include "aes.h"
#define TC_CTR_PRNG_RESEED_REQ -1
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
/* updated each time another BLOCKLEN_BYTES bytes are produced */
uint8_t V[TC_AES_BLOCK_SIZE];
/* updated whenever the PRNG is reseeded */
struct tc_aes_key_sched_struct key;
/* number of requests since initialization/reseeding */
uint64_t reseedCount;
} TCCtrPrng_t;
/**
* @brief CTR-PRNG initialization procedure
* Initializes prng context with entropy and personalization string (if any)
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* ctx == NULL,
* entropy == NULL,
* entropyLen < (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE)
* @note Only the first (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes of
* both the entropy and personalization inputs are used -
* supplying additional bytes has no effect.
* @param ctx IN/OUT -- the PRNG context to initialize
* @param entropy IN -- entropy used to seed the PRNG
* @param entropyLen IN -- entropy length in bytes
* @param personalization IN -- personalization string used to seed the PRNG
* (may be null)
* @param plen IN -- personalization length in bytes
*
*/
int tc_ctr_prng_init(TCCtrPrng_t * const ctx,
uint8_t const * const entropy,
unsigned int entropyLen,
uint8_t const * const personalization,
unsigned int pLen);
/**
* @brief CTR-PRNG reseed procedure
* Mixes entropy and additional_input into the prng context
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* ctx == NULL,
* entropy == NULL,
* entropylen < (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE)
* @note It is better to reseed an existing prng context rather than
* re-initialise, so that any existing entropy in the context is
* presereved. This offers some protection against undetected failures
* of the entropy source.
* @note Assumes tc_ctr_prng_init has been called for ctx
* @param ctx IN/OUT -- the PRNG state
* @param entropy IN -- entropy to mix into the prng
* @param entropylen IN -- length of entropy in bytes
* @param additional_input IN -- additional input to the prng (may be null)
* @param additionallen IN -- additional input length in bytes
*/
int tc_ctr_prng_reseed(TCCtrPrng_t * const ctx,
uint8_t const * const entropy,
unsigned int entropyLen,
uint8_t const * const additional_input,
unsigned int additionallen);
/**
* @brief CTR-PRNG generate procedure
* Generates outlen pseudo-random bytes into out buffer, updates prng
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CTR_PRNG_RESEED_REQ (-1) if a reseed is needed
* returns TC_CRYPTO_FAIL (0) if:
* ctx == NULL,
* out == NULL,
* outlen >= 2^16
* @note Assumes tc_ctr_prng_init has been called for ctx
* @param ctx IN/OUT -- the PRNG context
* @param additional_input IN -- additional input to the prng (may be null)
* @param additionallen IN -- additional input length in bytes
* @param out IN/OUT -- buffer to receive output
* @param outlen IN -- size of out buffer in bytes
*/
int tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
uint8_t const * const additional_input,
unsigned int additionallen,
uint8_t * const out,
unsigned int outlen);
/**
* @brief CTR-PRNG uninstantiate procedure
* Zeroes the internal state of the supplied prng context
* @return none
* @param ctx IN/OUT -- the PRNG context
*/
void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx);
#ifdef __cplusplus
}
#endif
#endif /* __TC_CTR_PRNG_H__ */

View File

@@ -0,0 +1,545 @@
/* ecc.h - TinyCrypt interface to common ECC functions */
/* Copyright (c) 2014, Kenneth MacKay
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief -- Interface to common ECC functions.
*
* Overview: This software is an implementation of common functions
* necessary to elliptic curve cryptography. This implementation uses
* curve NIST p-256.
*
* Security: The curve NIST p-256 provides approximately 128 bits of security.
*
*/
#ifndef __TC_UECC_H__
#define __TC_UECC_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Word size (4 bytes considering 32-bits architectures) */
#define uECC_WORD_SIZE 4
/* setting max number of calls to prng: */
#ifndef uECC_RNG_MAX_TRIES
#define uECC_RNG_MAX_TRIES 64
#endif
/* defining data types to store word and bit counts: */
typedef int8_t wordcount_t;
typedef int16_t bitcount_t;
/* defining data type for comparison result: */
typedef int8_t cmpresult_t;
/* defining data type to store ECC coordinate/point in 32bits words: */
typedef unsigned int uECC_word_t;
/* defining data type to store an ECC coordinate/point in 64bits words: */
typedef uint64_t uECC_dword_t;
/* defining masks useful for ecc computations: */
#define HIGH_BIT_SET 0x80000000
#define uECC_WORD_BITS 32
#define uECC_WORD_BITS_SHIFT 5
#define uECC_WORD_BITS_MASK 0x01F
/* Number of words of 32 bits to represent an element of the the curve p-256: */
#define NUM_ECC_WORDS 8
/* Number of bytes to represent an element of the the curve p-256: */
#define NUM_ECC_BYTES (uECC_WORD_SIZE*NUM_ECC_WORDS)
/* structure that represents an elliptic curve (e.g. p256):*/
struct uECC_Curve_t;
typedef const struct uECC_Curve_t * uECC_Curve;
struct uECC_Curve_t {
wordcount_t num_words;
wordcount_t num_bytes;
bitcount_t num_n_bits;
uECC_word_t p[NUM_ECC_WORDS];
uECC_word_t n[NUM_ECC_WORDS];
uECC_word_t G[NUM_ECC_WORDS * 2];
uECC_word_t b[NUM_ECC_WORDS];
void (*double_jacobian)(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * Z1,
uECC_Curve curve);
void (*x_side)(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve);
void (*mmod_fast)(uECC_word_t *result, uECC_word_t *product);
};
/*
* @brief computes doubling of point ion jacobian coordinates, in place.
* @param X1 IN/OUT -- x coordinate
* @param Y1 IN/OUT -- y coordinate
* @param Z1 IN/OUT -- z coordinate
* @param curve IN -- elliptic curve
*/
void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1,
uECC_word_t * Z1, uECC_Curve curve);
/*
* @brief Computes x^3 + ax + b. result must not overlap x.
* @param result OUT -- x^3 + ax + b
* @param x IN -- value of x
* @param curve IN -- elliptic curve
*/
void x_side_default(uECC_word_t *result, const uECC_word_t *x,
uECC_Curve curve);
/*
* @brief Computes result = product % curve_p
* from http://www.nsa.gov/ia/_files/nist-routines.pdf
* @param result OUT -- product % curve_p
* @param product IN -- value to be reduced mod curve_p
*/
void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int *product);
/* Bytes to words ordering: */
#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##d##c##b##a, 0x##h##g##f##e
#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a
#define BITS_TO_WORDS(num_bits) \
((num_bits + ((uECC_WORD_SIZE * 8) - 1)) / (uECC_WORD_SIZE * 8))
#define BITS_TO_BYTES(num_bits) ((num_bits + 7) / 8)
/* definition of curve NIST p-256: */
static const struct uECC_Curve_t curve_secp256r1 = {
NUM_ECC_WORDS,
NUM_ECC_BYTES,
256, /* num_n_bits */ {
BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00),
BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),
BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF)
}, {
BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3),
BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC),
BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF)
}, {
BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4),
BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77),
BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8),
BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B),
BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB),
BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B),
BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E),
BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F)
}, {
BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B),
BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65),
BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3),
BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A)
},
&double_jacobian_default,
&x_side_default,
&vli_mmod_fast_secp256r1
};
uECC_Curve uECC_secp256r1(void);
/*
* @brief Generates a random integer in the range 0 < random < top.
* Both random and top have num_words words.
* @param random OUT -- random integer in the range 0 < random < top
* @param top IN -- upper limit
* @param num_words IN -- number of words
* @return a random integer in the range 0 < random < top
*/
int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
wordcount_t num_words);
/* uECC_RNG_Function type
* The RNG function should fill 'size' random bytes into 'dest'. It should
* return 1 if 'dest' was filled with random data, or 0 if the random data could
* not be generated. The filled-in values should be either truly random, or from
* a cryptographically-secure PRNG.
*
* A correctly functioning RNG function must be set (using uECC_set_rng())
* before calling uECC_make_key() or uECC_sign().
*
* Setting a correctly functioning RNG function improves the resistance to
* side-channel attacks for uECC_shared_secret().
*
* A correct RNG function is set by default. If you are building on another
* POSIX-compliant system that supports /dev/random or /dev/urandom, you can
* define uECC_POSIX to use the predefined RNG.
*/
typedef int(*uECC_RNG_Function)(uint8_t *dest, unsigned int size);
/*
* @brief Set the function that will be used to generate random bytes. The RNG
* function should return 1 if the random data was generated, or 0 if the random
* data could not be generated.
*
* @note On platforms where there is no predefined RNG function, this must be
* called before uECC_make_key() or uECC_sign() are used.
*
* @param rng_function IN -- function that will be used to generate random bytes
*/
void uECC_set_rng(uECC_RNG_Function rng_function);
/*
* @brief provides current uECC_RNG_Function.
* @return Returns the function that will be used to generate random bytes.
*/
uECC_RNG_Function uECC_get_rng(void);
/*
* @brief computes the size of a private key for the curve in bytes.
* @param curve IN -- elliptic curve
* @return size of a private key for the curve in bytes.
*/
int uECC_curve_private_key_size(uECC_Curve curve);
/*
* @brief computes the size of a public key for the curve in bytes.
* @param curve IN -- elliptic curve
* @return the size of a public key for the curve in bytes.
*/
int uECC_curve_public_key_size(uECC_Curve curve);
/*
* @brief Compute the corresponding public key for a private key.
* @param private_key IN -- The private key to compute the public key for
* @param public_key OUT -- Will be filled in with the corresponding public key
* @param curve
* @return Returns 1 if key was computed successfully, 0 if an error occurred.
*/
int uECC_compute_public_key(const uint8_t *private_key,
uint8_t *public_key, uECC_Curve curve);
/*
* @brief Compute public-key.
* @return corresponding public-key.
* @param result OUT -- public-key
* @param private_key IN -- private-key
* @param curve IN -- elliptic curve
*/
uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
uECC_word_t *private_key, uECC_Curve curve);
/*
* @brief Regularize the bitcount for the private key so that attackers cannot
* use a side channel attack to learn the number of leading zeros.
* @return Regularized k
* @param k IN -- private-key
* @param k0 IN/OUT -- regularized k
* @param k1 IN/OUT -- regularized k
* @param curve IN -- elliptic curve
*/
uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0,
uECC_word_t *k1, uECC_Curve curve);
/*
* @brief Point multiplication algorithm using Montgomery's ladder with co-Z
* coordinates. See http://eprint.iacr.org/2011/338.pdf.
* @note Result may overlap point.
* @param result OUT -- returns scalar*point
* @param point IN -- elliptic curve point
* @param scalar IN -- scalar
* @param initial_Z IN -- initial value for z
* @param num_bits IN -- number of bits in scalar
* @param curve IN -- elliptic curve
*/
void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point,
const uECC_word_t * scalar, const uECC_word_t * initial_Z,
bitcount_t num_bits, uECC_Curve curve);
/*
* @brief Constant-time comparison to zero - secure way to compare long integers
* @param vli IN -- very long integer
* @param num_words IN -- number of words in the vli
* @return 1 if vli == 0, 0 otherwise.
*/
uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words);
/*
* @brief Check if 'point' is the point at infinity
* @param point IN -- elliptic curve point
* @param curve IN -- elliptic curve
* @return if 'point' is the point at infinity, 0 otherwise.
*/
uECC_word_t EccPoint_isZero(const uECC_word_t *point, uECC_Curve curve);
/*
* @brief computes the sign of left - right, in constant time.
* @param left IN -- left term to be compared
* @param right IN -- right term to be compared
* @param num_words IN -- number of words
* @return the sign of left - right
*/
cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right,
wordcount_t num_words);
/*
* @brief computes sign of left - right, not in constant time.
* @note should not be used if inputs are part of a secret
* @param left IN -- left term to be compared
* @param right IN -- right term to be compared
* @param num_words IN -- number of words
* @return the sign of left - right
*/
cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, const uECC_word_t *right,
wordcount_t num_words);
/*
* @brief Computes result = (left - right) % mod.
* @note Assumes that (left < mod) and (right < mod), and that result does not
* overlap mod.
* @param result OUT -- (left - right) % mod
* @param left IN -- leftright term in modular subtraction
* @param right IN -- right term in modular subtraction
* @param mod IN -- mod
* @param num_words IN -- number of words
*/
void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, const uECC_word_t *mod,
wordcount_t num_words);
/*
* @brief Computes P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) or
* P => P', Q => P + Q
* @note assumes Input P = (x1, y1, Z), Q = (x2, y2, Z)
* @param X1 IN -- x coordinate of P
* @param Y1 IN -- y coordinate of P
* @param X2 IN -- x coordinate of Q
* @param Y2 IN -- y coordinate of Q
* @param curve IN -- elliptic curve
*/
void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * X2,
uECC_word_t * Y2, uECC_Curve curve);
/*
* @brief Computes (x1 * z^2, y1 * z^3)
* @param X1 IN -- previous x1 coordinate
* @param Y1 IN -- previous y1 coordinate
* @param Z IN -- z value
* @param curve IN -- elliptic curve
*/
void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z,
uECC_Curve curve);
/*
* @brief Check if bit is set.
* @return Returns nonzero if bit 'bit' of vli is set.
* @warning It is assumed that the value provided in 'bit' is within the
* boundaries of the word-array 'vli'.
* @note The bit ordering layout assumed for vli is: {31, 30, ..., 0},
* {63, 62, ..., 32}, {95, 94, ..., 64}, {127, 126,..., 96} for a vli consisting
* of 4 uECC_word_t elements.
*/
uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit);
/*
* @brief Computes result = product % mod, where product is 2N words long.
* @param result OUT -- product % mod
* @param mod IN -- module
* @param num_words IN -- number of words
* @warning Currently only designed to work for curve_p or curve_n.
*/
void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
const uECC_word_t *mod, wordcount_t num_words);
/*
* @brief Computes modular product (using curve->mmod_fast)
* @param result OUT -- (left * right) mod % curve_p
* @param left IN -- left term in product
* @param right IN -- right term in product
* @param curve IN -- elliptic curve
*/
void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, uECC_Curve curve);
/*
* @brief Computes result = left - right.
* @note Can modify in place.
* @param result OUT -- left - right
* @param left IN -- left term in subtraction
* @param right IN -- right term in subtraction
* @param num_words IN -- number of words
* @return borrow
*/
uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, wordcount_t num_words);
/*
* @brief Constant-time comparison function(secure way to compare long ints)
* @param left IN -- left term in comparison
* @param right IN -- right term in comparison
* @param num_words IN -- number of words
* @return Returns 0 if left == right, 1 otherwise.
*/
uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right,
wordcount_t num_words);
/*
* @brief Computes (left * right) % mod
* @param result OUT -- (left * right) % mod
* @param left IN -- left term in product
* @param right IN -- right term in product
* @param mod IN -- mod
* @param num_words IN -- number of words
*/
void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, const uECC_word_t *mod,
wordcount_t num_words);
/*
* @brief Computes (1 / input) % mod
* @note All VLIs are the same size.
* @note See "Euclid's GCD to Montgomery Multiplication to the Great Divide"
* @param result OUT -- (1 / input) % mod
* @param input IN -- value to be modular inverted
* @param mod IN -- mod
* @param num_words -- number of words
*/
void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
const uECC_word_t *mod, wordcount_t num_words);
/*
* @brief Sets dest = src.
* @param dest OUT -- destination buffer
* @param src IN -- origin buffer
* @param num_words IN -- number of words
*/
void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src,
wordcount_t num_words);
/*
* @brief Computes (left + right) % mod.
* @note Assumes that (left < mod) and right < mod), and that result does not
* overlap mod.
* @param result OUT -- (left + right) % mod.
* @param left IN -- left term in addition
* @param right IN -- right term in addition
* @param mod IN -- mod
* @param num_words IN -- number of words
*/
void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, const uECC_word_t *mod,
wordcount_t num_words);
/*
* @brief Counts the number of bits required to represent vli.
* @param vli IN -- very long integer
* @param max_words IN -- number of words
* @return number of bits in given vli
*/
bitcount_t uECC_vli_numBits(const uECC_word_t *vli,
const wordcount_t max_words);
/*
* @brief Erases (set to 0) vli
* @param vli IN -- very long integer
* @param num_words IN -- number of words
*/
void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words);
/*
* @brief check if it is a valid point in the curve
* @param point IN -- point to be checked
* @param curve IN -- elliptic curve
* @return 0 if point is valid
* @exception returns -1 if it is a point at infinity
* @exception returns -2 if x or y is smaller than p,
* @exception returns -3 if y^2 != x^3 + ax + b.
*/
int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve);
/*
* @brief Check if a public key is valid.
* @param public_key IN -- The public key to be checked.
* @return returns 0 if the public key is valid
* @exception returns -1 if it is a point at infinity
* @exception returns -2 if x or y is smaller than p,
* @exception returns -3 if y^2 != x^3 + ax + b.
* @exception returns -4 if public key is the group generator.
*
* @note Note that you are not required to check for a valid public key before
* using any other uECC functions. However, you may wish to avoid spending CPU
* time computing a shared secret or verifying a signature using an invalid
* public key.
*/
int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve);
/*
* @brief Converts an integer in uECC native format to big-endian bytes.
* @param bytes OUT -- bytes representation
* @param num_bytes IN -- number of bytes
* @param native IN -- uECC native representation
*/
void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
const unsigned int *native);
/*
* @brief Converts big-endian bytes to an integer in uECC native format.
* @param native OUT -- uECC native representation
* @param bytes IN -- bytes representation
* @param num_bytes IN -- number of bytes
*/
void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes,
int num_bytes);
#ifdef __cplusplus
}
#endif
#endif /* __TC_UECC_H__ */

View File

@@ -0,0 +1,131 @@
/* ecc_dh.h - TinyCrypt interface to EC-DH implementation */
/*
* Copyright (c) 2014, Kenneth MacKay
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief -- Interface to EC-DH implementation.
*
* Overview: This software is an implementation of EC-DH. This implementation
* uses curve NIST p-256.
*
* Security: The curve NIST p-256 provides approximately 128 bits of security.
*/
#ifndef __TC_ECC_DH_H__
#define __TC_ECC_DH_H__
#include "ecc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Create a public/private key pair.
* @return returns TC_CRYPTO_SUCCESS (1) if the key pair was generated successfully
* returns TC_CRYPTO_FAIL (0) if error while generating key pair
*
* @param p_public_key OUT -- Will be filled in with the public key. Must be at
* least 2 * the curve size (in bytes) long. For curve secp256r1, p_public_key
* must be 64 bytes long.
* @param p_private_key OUT -- Will be filled in with the private key. Must be as
* long as the curve order (for secp256r1, p_private_key must be 32 bytes long).
*
* @note side-channel countermeasure: algorithm strengthened against timing
* attack.
* @warning A cryptographically-secure PRNG function must be set (using
* uECC_set_rng()) before calling uECC_make_key().
*/
int uECC_make_key(uint8_t *p_public_key, uint8_t *p_private_key, uECC_Curve curve);
#ifdef ENABLE_TESTS
/**
* @brief Create a public/private key pair given a specific d.
*
* @note THIS FUNCTION SHOULD BE CALLED ONLY FOR TEST PURPOSES. Refer to
* uECC_make_key() function for real applications.
*/
int uECC_make_key_with_d(uint8_t *p_public_key, uint8_t *p_private_key,
unsigned int *d, uECC_Curve curve);
#endif
/**
* @brief Compute a shared secret given your secret key and someone else's
* public key.
* @return returns TC_CRYPTO_SUCCESS (1) if the shared secret was computed successfully
* returns TC_CRYPTO_FAIL (0) otherwise
*
* @param p_secret OUT -- Will be filled in with the shared secret value. Must be
* the same size as the curve size (for curve secp256r1, secret must be 32 bytes
* long.
* @param p_public_key IN -- The public key of the remote party.
* @param p_private_key IN -- Your private key.
*
* @warning It is recommended to use the output of uECC_shared_secret() as the
* input of a recommended Key Derivation Function (see NIST SP 800-108) in
* order to produce a cryptographically secure symmetric key.
*/
int uECC_shared_secret(const uint8_t *p_public_key, const uint8_t *p_private_key,
uint8_t *p_secret, uECC_Curve curve);
#ifdef __cplusplus
}
#endif
#endif /* __TC_ECC_DH_H__ */

View File

@@ -0,0 +1,139 @@
/* ecc_dh.h - TinyCrypt interface to EC-DSA implementation */
/*
* Copyright (c) 2014, Kenneth MacKay
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief -- Interface to EC-DSA implementation.
*
* Overview: This software is an implementation of EC-DSA. This implementation
* uses curve NIST p-256.
*
* Security: The curve NIST p-256 provides approximately 128 bits of security.
*
* Usage: - To sign: Compute a hash of the data you wish to sign (SHA-2 is
* recommended) and pass it in to ecdsa_sign function along with your
* private key and a random number. You must use a new non-predictable
* random number to generate each new signature.
* - To verify a signature: Compute the hash of the signed data using
* the same hash as the signer and pass it to this function along with
* the signer's public key and the signature values (r and s).
*/
#ifndef __TC_ECC_DSA_H__
#define __TC_ECC_DSA_H__
#include "ecc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Generate an ECDSA signature for a given hash value.
* @return returns TC_CRYPTO_SUCCESS (1) if the signature generated successfully
* returns TC_CRYPTO_FAIL (0) if an error occurred.
*
* @param p_private_key IN -- Your private key.
* @param p_message_hash IN -- The hash of the message to sign.
* @param p_hash_size IN -- The size of p_message_hash in bytes.
* @param p_signature OUT -- Will be filled in with the signature value. Must be
* at least 2 * curve size long (for secp256r1, signature must be 64 bytes long).
*
* @warning A cryptographically-secure PRNG function must be set (using
* uECC_set_rng()) before calling uECC_sign().
* @note Usage: Compute a hash of the data you wish to sign (SHA-2 is
* recommended) and pass it in to this function along with your private key.
* @note side-channel countermeasure: algorithm strengthened against timing
* attack.
*/
int uECC_sign(const uint8_t *p_private_key, const uint8_t *p_message_hash,
unsigned p_hash_size, uint8_t *p_signature, uECC_Curve curve);
#ifdef ENABLE_TESTS
/*
* THIS FUNCTION SHOULD BE CALLED FOR TEST PURPOSES ONLY.
* Refer to uECC_sign() function for real applications.
*/
int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash,
unsigned int hash_size, uECC_word_t *k, uint8_t *signature,
uECC_Curve curve);
#endif
/**
* @brief Verify an ECDSA signature.
* @return returns TC_SUCCESS (1) if the signature is valid
* returns TC_FAIL (0) if the signature is invalid.
*
* @param p_public_key IN -- The signer's public key.
* @param p_message_hash IN -- The hash of the signed data.
* @param p_hash_size IN -- The size of p_message_hash in bytes.
* @param p_signature IN -- The signature values.
*
* @note Usage: Compute the hash of the signed data using the same hash as the
* signer and pass it to this function along with the signer's public key and
* the signature values (hash_size and signature).
*/
int uECC_verify(const uint8_t *p_public_key, const uint8_t *p_message_hash,
unsigned int p_hash_size, const uint8_t *p_signature, uECC_Curve curve);
#ifdef __cplusplus
}
#endif
#endif /* __TC_ECC_DSA_H__ */

View File

@@ -0,0 +1,81 @@
/* uECC_platform_specific.h - Interface to platform specific functions*/
/* Copyright (c) 2014, Kenneth MacKay
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.*/
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* uECC_platform_specific.h -- Interface to platform specific functions
*/
#ifndef __UECC_PLATFORM_SPECIFIC_H_
#define __UECC_PLATFORM_SPECIFIC_H_
/*
* The RNG function should fill 'size' random bytes into 'dest'. It should
* return 1 if 'dest' was filled with random data, or 0 if the random data could
* not be generated. The filled-in values should be either truly random, or from
* a cryptographically-secure PRNG.
*
* A cryptographically-secure PRNG function must be set (using uECC_set_rng())
* before calling uECC_make_key() or uECC_sign().
*
* Setting a cryptographically-secure PRNG function improves the resistance to
* side-channel attacks for uECC_shared_secret().
*
* A correct PRNG function is set by default (default_RNG_defined = 1) and works
* for some platforms, such as Unix and Linux. For other platforms, you may need
* to provide another PRNG function.
*/
#define default_RNG_defined 0
int default_CSPRNG(uint8_t *dest, unsigned int size);
#endif /* __UECC_PLATFORM_SPECIFIC_H_ */

View File

@@ -0,0 +1,139 @@
/* hmac.h - TinyCrypt interface to an HMAC implementation */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief Interface to an HMAC implementation.
*
* Overview: HMAC is a message authentication code based on hash functions.
* TinyCrypt hard codes SHA-256 as the hash function. A message
* authentication code based on hash functions is also called a
* keyed cryptographic hash function since it performs a
* transformation specified by a key in an arbitrary length data
* set into a fixed length data set (also called tag).
*
* Security: The security of the HMAC depends on the length of the key and
* on the security of the hash function. Note that HMAC primitives
* are much less affected by collision attacks than their
* corresponding hash functions.
*
* Requires: SHA-256
*
* Usage: 1) call tc_hmac_set_key to set the HMAC key.
*
* 2) call tc_hmac_init to initialize a struct hash_state before
* processing the data.
*
* 3) call tc_hmac_update to process the next input segment;
* tc_hmac_update can be called as many times as needed to process
* all of the segments of the input; the order is important.
*
* 4) call tc_hmac_final to out put the tag.
*/
#ifndef __TC_HMAC_H__
#define __TC_HMAC_H__
#include "sha256.h"
#ifdef __cplusplus
extern "C" {
#endif
struct tc_hmac_state_struct {
/* the internal state required by h */
struct tc_sha256_state_struct hash_state;
/* HMAC key schedule */
uint8_t key[2*TC_SHA256_BLOCK_SIZE];
};
typedef struct tc_hmac_state_struct *TCHmacState_t;
/**
* @brief HMAC set key procedure
* Configures ctx to use key
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if
* ctx == NULL or
* key == NULL or
* key_size == 0
* @param ctx IN/OUT -- the struct tc_hmac_state_struct to initial
* @param key IN -- the HMAC key to configure
* @param key_size IN -- the HMAC key size
*/
int tc_hmac_set_key(TCHmacState_t ctx, const uint8_t *key,
unsigned int key_size);
/**
* @brief HMAC initialize procedure
* Initializes ctx to begin the next HMAC operation
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if: ctx == NULL or key == NULL
* @param ctx IN/OUT -- struct tc_hmac_state_struct buffer to initialize
*/
int tc_hmac_init(TCHmacState_t ctx);
/**
* @brief HMAC update procedure
* Mixes data_length bytes addressed by data into state
* @return returns TC_CRYPTO_SUCCCESS (1)
* returns TC_CRYPTO_FAIL (0) if: ctx == NULL or key == NULL
* @note Assumes state has been initialized by tc_hmac_init
* @param ctx IN/OUT -- state of HMAC computation so far
* @param data IN -- data to incorporate into state
* @param data_length IN -- size of data in bytes
*/
int tc_hmac_update(TCHmacState_t ctx, const void *data,
unsigned int data_length);
/**
* @brief HMAC final procedure
* Writes the HMAC tag into the tag buffer
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* tag == NULL or
* ctx == NULL or
* key == NULL or
* taglen != TC_SHA256_DIGEST_SIZE
* @note ctx is erased before exiting. This should never be changed/removed.
* @note Assumes the tag bufer is at least sizeof(hmac_tag_size(state)) bytes
* state has been initialized by tc_hmac_init
* @param tag IN/OUT -- buffer to receive computed HMAC tag
* @param taglen IN -- size of tag in bytes
* @param ctx IN/OUT -- the HMAC state for computing tag
*/
int tc_hmac_final(uint8_t *tag, unsigned int taglen, TCHmacState_t ctx);
#ifdef __cplusplus
}
#endif
#endif /*__TC_HMAC_H__*/

View File

@@ -0,0 +1,164 @@
/* hmac_prng.h - TinyCrypt interface to an HMAC-PRNG implementation */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief Interface to an HMAC-PRNG implementation.
*
* Overview: A pseudo-random number generator (PRNG) generates a sequence
* of numbers that have a distribution close to the one expected
* for a sequence of truly random numbers. The NIST Special
* Publication 800-90A specifies several mechanisms to generate
* sequences of pseudo random numbers, including the HMAC-PRNG one
* which is based on HMAC. TinyCrypt implements HMAC-PRNG with
* certain modifications from the NIST SP 800-90A spec.
*
* Security: A cryptographically secure PRNG depends on the existence of an
* entropy source to provide a truly random seed as well as the
* security of the primitives used as the building blocks (HMAC and
* SHA256, for TinyCrypt).
*
* The NIST SP 800-90A standard tolerates a null personalization,
* while TinyCrypt requires a non-null personalization. This is
* because a personalization string (the host name concatenated
* with a time stamp, for example) is easily computed and might be
* the last line of defense against failure of the entropy source.
*
* Requires: - SHA-256
* - HMAC
*
* Usage: 1) call tc_hmac_prng_init to set the HMAC key and process the
* personalization data.
*
* 2) call tc_hmac_prng_reseed to process the seed and additional
* input.
*
* 3) call tc_hmac_prng_generate to out put the pseudo-random data.
*/
#ifndef __TC_HMAC_PRNG_H__
#define __TC_HMAC_PRNG_H__
#include "sha256.h"
#include "hmac.h"
#ifdef __cplusplus
extern "C" {
#endif
#define TC_HMAC_PRNG_RESEED_REQ -1
struct tc_hmac_prng_struct {
/* the HMAC instance for this PRNG */
struct tc_hmac_state_struct h;
/* the PRNG key */
uint8_t key[TC_SHA256_DIGEST_SIZE];
/* PRNG state */
uint8_t v[TC_SHA256_DIGEST_SIZE];
/* calls to tc_hmac_prng_generate left before re-seed */
unsigned int countdown;
};
typedef struct tc_hmac_prng_struct *TCHmacPrng_t;
/**
* @brief HMAC-PRNG initialization procedure
* Initializes prng with personalization, disables tc_hmac_prng_generate
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* prng == NULL,
* personalization == NULL,
* plen > MAX_PLEN
* @note Assumes: - personalization != NULL.
* The personalization is a platform unique string (e.g., the host
* name) and is the last line of defense against failure of the
* entropy source
* @warning NIST SP 800-90A specifies 3 items as seed material during
* initialization: entropy seed, personalization, and an optional
* nonce. TinyCrypts requires instead a non-null personalization
* (which is easily computed) and indirectly requires an entropy
* seed (since the reseed function is mandatorily called after
* initialize)
* @param prng IN/OUT -- the PRNG state to initialize
* @param personalization IN -- personalization string
* @param plen IN -- personalization length in bytes
*/
int tc_hmac_prng_init(TCHmacPrng_t prng,
const uint8_t *personalization,
unsigned int plen);
/**
* @brief HMAC-PRNG reseed procedure
* Mixes seed into prng, enables tc_hmac_prng_generate
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* prng == NULL,
* seed == NULL,
* seedlen < MIN_SLEN,
* seendlen > MAX_SLEN,
* additional_input != (const uint8_t *) 0 && additionallen == 0,
* additional_input != (const uint8_t *) 0 && additionallen > MAX_ALEN
* @note Assumes:- tc_hmac_prng_init has been called for prng
* - seed has sufficient entropy.
*
* @param prng IN/OUT -- the PRNG state
* @param seed IN -- entropy to mix into the prng
* @param seedlen IN -- length of seed in bytes
* @param additional_input IN -- additional input to the prng
* @param additionallen IN -- additional input length in bytes
*/
int tc_hmac_prng_reseed(TCHmacPrng_t prng, const uint8_t *seed,
unsigned int seedlen, const uint8_t *additional_input,
unsigned int additionallen);
/**
* @brief HMAC-PRNG generate procedure
* Generates outlen pseudo-random bytes into out buffer, updates prng
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_HMAC_PRNG_RESEED_REQ (-1) if a reseed is needed
* returns TC_CRYPTO_FAIL (0) if:
* out == NULL,
* prng == NULL,
* outlen == 0,
* outlen >= MAX_OUT
* @note Assumes tc_hmac_prng_init has been called for prng
* @param out IN/OUT -- buffer to receive output
* @param outlen IN -- size of out buffer in bytes
* @param prng IN/OUT -- the PRNG state
*/
int tc_hmac_prng_generate(uint8_t *out, unsigned int outlen, TCHmacPrng_t prng);
#ifdef __cplusplus
}
#endif
#endif /* __TC_HMAC_PRNG_H__ */

View File

@@ -0,0 +1,129 @@
/* sha256.h - TinyCrypt interface to a SHA-256 implementation */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief Interface to a SHA-256 implementation.
*
* Overview: SHA-256 is a NIST approved cryptographic hashing algorithm
* specified in FIPS 180. A hash algorithm maps data of arbitrary
* size to data of fixed length.
*
* Security: SHA-256 provides 128 bits of security against collision attacks
* and 256 bits of security against pre-image attacks. SHA-256 does
* NOT behave like a random oracle, but it can be used as one if
* the string being hashed is prefix-free encoded before hashing.
*
* Usage: 1) call tc_sha256_init to initialize a struct
* tc_sha256_state_struct before hashing a new string.
*
* 2) call tc_sha256_update to hash the next string segment;
* tc_sha256_update can be called as many times as needed to hash
* all of the segments of a string; the order is important.
*
* 3) call tc_sha256_final to out put the digest from a hashing
* operation.
*/
#ifndef __TC_SHA256_H__
#define __TC_SHA256_H__
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define TC_SHA256_BLOCK_SIZE (64)
#define TC_SHA256_DIGEST_SIZE (32)
#define TC_SHA256_STATE_BLOCKS (TC_SHA256_DIGEST_SIZE/4)
struct tc_sha256_state_struct {
unsigned int iv[TC_SHA256_STATE_BLOCKS];
uint64_t bits_hashed;
uint8_t leftover[TC_SHA256_BLOCK_SIZE];
size_t leftover_offset;
};
typedef struct tc_sha256_state_struct *TCSha256State_t;
/**
* @brief SHA256 initialization procedure
* Initializes s
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if s == NULL
* @param s Sha256 state struct
*/
int tc_sha256_init(TCSha256State_t s);
/**
* @brief SHA256 update procedure
* Hashes data_length bytes addressed by data into state s
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* s == NULL,
* s->iv == NULL,
* data == NULL
* @note Assumes s has been initialized by tc_sha256_init
* @warning The state buffer 'leftover' is left in memory after processing
* If your application intends to have sensitive data in this
* buffer, remind to erase it after the data has been processed
* @param s Sha256 state struct
* @param data message to hash
* @param datalen length of message to hash
*/
int tc_sha256_update (TCSha256State_t s, const uint8_t *data, size_t datalen);
/**
* @brief SHA256 final procedure
* Inserts the completed hash computation into digest
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* s == NULL,
* s->iv == NULL,
* digest == NULL
* @note Assumes: s has been initialized by tc_sha256_init
* digest points to at least TC_SHA256_DIGEST_SIZE bytes
* @warning The state buffer 'leftover' is left in memory after processing
* If your application intends to have sensitive data in this
* buffer, remind to erase it after the data has been processed
* @param digest unsigned eight bit integer
* @param Sha256 state struct
*/
int tc_sha256_final(uint8_t *digest, TCSha256State_t s);
#ifdef __cplusplus
}
#endif
#endif /* __TC_SHA256_H__ */

View File

@@ -0,0 +1,95 @@
/* utils.h - TinyCrypt interface to platform-dependent run-time operations */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief Interface to platform-dependent run-time operations.
*
*/
#ifndef __TC_UTILS_H__
#define __TC_UTILS_H__
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Copy the the buffer 'from' to the buffer 'to'.
* @return returns TC_CRYPTO_SUCCESS (1)
* returns TC_CRYPTO_FAIL (0) if:
* from_len > to_len.
*
* @param to OUT -- destination buffer
* @param to_len IN -- length of destination buffer
* @param from IN -- origin buffer
* @param from_len IN -- length of origin buffer
*/
unsigned int _copy(uint8_t *to, unsigned int to_len,
const uint8_t *from, unsigned int from_len);
/**
* @brief Set the value 'val' into the buffer 'to', 'len' times.
*
* @param to OUT -- destination buffer
* @param val IN -- value to be set in 'to'
* @param len IN -- number of times the value will be copied
*/
void _set(void *to, uint8_t val, unsigned int len);
/*
* @brief AES specific doubling function, which utilizes
* the finite field used by AES.
* @return Returns a^2
*
* @param a IN/OUT -- value to be doubled
*/
uint8_t _double_byte(uint8_t a);
/*
* @brief Constant-time algorithm to compare if two sequences of bytes are equal
* @return Returns 0 if equal, and non-zero otherwise
*
* @param a IN -- sequence of bytes a
* @param b IN -- sequence of bytes b
* @param size IN -- size of sequences a and b
*/
int _compare(const uint8_t *a, const uint8_t *b, size_t size);
#ifdef __cplusplus
}
#endif
#endif /* __TC_UTILS_H__ */

View File

@@ -0,0 +1,164 @@
/* aes_decrypt.c - TinyCrypt implementation of AES decryption procedure */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../include/tinycrypt/aes.h"
#include "../include/tinycrypt/constants.h"
#include "../include/tinycrypt/utils.h"
static const uint8_t inv_sbox[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
0x55, 0x21, 0x0c, 0x7d
};
int tc_aes128_set_decrypt_key(TCAesKeySched_t s, const uint8_t *k)
{
return tc_aes128_set_encrypt_key(s, k);
}
#define mult8(a)(_double_byte(_double_byte(_double_byte(a))))
#define mult9(a)(mult8(a)^(a))
#define multb(a)(mult8(a)^_double_byte(a)^(a))
#define multd(a)(mult8(a)^_double_byte(_double_byte(a))^(a))
#define multe(a)(mult8(a)^_double_byte(_double_byte(a))^_double_byte(a))
static inline void mult_row_column(uint8_t *out, const uint8_t *in)
{
out[0] = multe(in[0]) ^ multb(in[1]) ^ multd(in[2]) ^ mult9(in[3]);
out[1] = mult9(in[0]) ^ multe(in[1]) ^ multb(in[2]) ^ multd(in[3]);
out[2] = multd(in[0]) ^ mult9(in[1]) ^ multe(in[2]) ^ multb(in[3]);
out[3] = multb(in[0]) ^ multd(in[1]) ^ mult9(in[2]) ^ multe(in[3]);
}
static inline void inv_mix_columns(uint8_t *s)
{
uint8_t t[Nb*Nk];
mult_row_column(t, s);
mult_row_column(&t[Nb], s+Nb);
mult_row_column(&t[2*Nb], s+(2*Nb));
mult_row_column(&t[3*Nb], s+(3*Nb));
(void)_copy(s, sizeof(t), t, sizeof(t));
}
static inline void add_round_key(uint8_t *s, const unsigned int *k)
{
s[0] ^= (uint8_t)(k[0] >> 24); s[1] ^= (uint8_t)(k[0] >> 16);
s[2] ^= (uint8_t)(k[0] >> 8); s[3] ^= (uint8_t)(k[0]);
s[4] ^= (uint8_t)(k[1] >> 24); s[5] ^= (uint8_t)(k[1] >> 16);
s[6] ^= (uint8_t)(k[1] >> 8); s[7] ^= (uint8_t)(k[1]);
s[8] ^= (uint8_t)(k[2] >> 24); s[9] ^= (uint8_t)(k[2] >> 16);
s[10] ^= (uint8_t)(k[2] >> 8); s[11] ^= (uint8_t)(k[2]);
s[12] ^= (uint8_t)(k[3] >> 24); s[13] ^= (uint8_t)(k[3] >> 16);
s[14] ^= (uint8_t)(k[3] >> 8); s[15] ^= (uint8_t)(k[3]);
}
static inline void inv_sub_bytes(uint8_t *s)
{
unsigned int i;
for (i = 0; i < (Nb*Nk); ++i) {
s[i] = inv_sbox[s[i]];
}
}
/*
* This inv_shift_rows also implements the matrix flip required for
* inv_mix_columns, but performs it here to reduce the number of memory
* operations.
*/
static inline void inv_shift_rows(uint8_t *s)
{
uint8_t t[Nb*Nk];
t[0] = s[0]; t[1] = s[13]; t[2] = s[10]; t[3] = s[7];
t[4] = s[4]; t[5] = s[1]; t[6] = s[14]; t[7] = s[11];
t[8] = s[8]; t[9] = s[5]; t[10] = s[2]; t[11] = s[15];
t[12] = s[12]; t[13] = s[9]; t[14] = s[6]; t[15] = s[3];
(void)_copy(s, sizeof(t), t, sizeof(t));
}
int tc_aes_decrypt(uint8_t *out, const uint8_t *in, const TCAesKeySched_t s)
{
uint8_t state[Nk*Nb];
unsigned int i;
if (out == (uint8_t *) 0) {
return TC_CRYPTO_FAIL;
} else if (in == (const uint8_t *) 0) {
return TC_CRYPTO_FAIL;
} else if (s == (TCAesKeySched_t) 0) {
return TC_CRYPTO_FAIL;
}
(void)_copy(state, sizeof(state), in, sizeof(state));
add_round_key(state, s->words + Nb*Nr);
for (i = Nr - 1; i > 0; --i) {
inv_shift_rows(state);
inv_sub_bytes(state);
add_round_key(state, s->words + Nb*i);
inv_mix_columns(state);
}
inv_shift_rows(state);
inv_sub_bytes(state);
add_round_key(state, s->words);
(void)_copy(out, sizeof(state), state, sizeof(state));
/*zeroing out the state buffer */
_set(state, TC_ZERO_BYTE, sizeof(state));
return TC_CRYPTO_SUCCESS;
}

View File

@@ -0,0 +1,191 @@
/* aes_encrypt.c - TinyCrypt implementation of AES encryption procedure */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../include/tinycrypt/aes.h"
#include "../include/tinycrypt/utils.h"
#include "../include/tinycrypt/constants.h"
static const uint8_t sbox[256] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
0xb0, 0x54, 0xbb, 0x16
};
static inline unsigned int rotword(unsigned int a)
{
return (((a) >> 24)|((a) << 8));
}
#define subbyte(a, o)(sbox[((a) >> (o))&0xff] << (o))
#define subword(a)(subbyte(a, 24)|subbyte(a, 16)|subbyte(a, 8)|subbyte(a, 0))
int tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k)
{
const unsigned int rconst[11] = {
0x00000000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000
};
unsigned int i;
unsigned int t;
if (s == (TCAesKeySched_t) 0) {
return TC_CRYPTO_FAIL;
} else if (k == (const uint8_t *) 0) {
return TC_CRYPTO_FAIL;
}
for (i = 0; i < Nk; ++i) {
s->words[i] = (k[Nb*i]<<24) | (k[Nb*i+1]<<16) |
(k[Nb*i+2]<<8) | (k[Nb*i+3]);
}
for (; i < (Nb * (Nr + 1)); ++i) {
t = s->words[i-1];
if ((i % Nk) == 0) {
t = subword(rotword(t)) ^ rconst[i/Nk];
}
s->words[i] = s->words[i-Nk] ^ t;
}
return TC_CRYPTO_SUCCESS;
}
static inline void add_round_key(uint8_t *s, const unsigned int *k)
{
s[0] ^= (uint8_t)(k[0] >> 24); s[1] ^= (uint8_t)(k[0] >> 16);
s[2] ^= (uint8_t)(k[0] >> 8); s[3] ^= (uint8_t)(k[0]);
s[4] ^= (uint8_t)(k[1] >> 24); s[5] ^= (uint8_t)(k[1] >> 16);
s[6] ^= (uint8_t)(k[1] >> 8); s[7] ^= (uint8_t)(k[1]);
s[8] ^= (uint8_t)(k[2] >> 24); s[9] ^= (uint8_t)(k[2] >> 16);
s[10] ^= (uint8_t)(k[2] >> 8); s[11] ^= (uint8_t)(k[2]);
s[12] ^= (uint8_t)(k[3] >> 24); s[13] ^= (uint8_t)(k[3] >> 16);
s[14] ^= (uint8_t)(k[3] >> 8); s[15] ^= (uint8_t)(k[3]);
}
static inline void sub_bytes(uint8_t *s)
{
unsigned int i;
for (i = 0; i < (Nb * Nk); ++i) {
s[i] = sbox[s[i]];
}
}
#define triple(a)(_double_byte(a)^(a))
static inline void mult_row_column(uint8_t *out, const uint8_t *in)
{
out[0] = _double_byte(in[0]) ^ triple(in[1]) ^ in[2] ^ in[3];
out[1] = in[0] ^ _double_byte(in[1]) ^ triple(in[2]) ^ in[3];
out[2] = in[0] ^ in[1] ^ _double_byte(in[2]) ^ triple(in[3]);
out[3] = triple(in[0]) ^ in[1] ^ in[2] ^ _double_byte(in[3]);
}
static inline void mix_columns(uint8_t *s)
{
uint8_t t[Nb*Nk];
mult_row_column(t, s);
mult_row_column(&t[Nb], s+Nb);
mult_row_column(&t[2 * Nb], s + (2 * Nb));
mult_row_column(&t[3 * Nb], s + (3 * Nb));
(void) _copy(s, sizeof(t), t, sizeof(t));
}
/*
* This shift_rows also implements the matrix flip required for mix_columns, but
* performs it here to reduce the number of memory operations.
*/
static inline void shift_rows(uint8_t *s)
{
uint8_t t[Nb * Nk];
t[0] = s[0]; t[1] = s[5]; t[2] = s[10]; t[3] = s[15];
t[4] = s[4]; t[5] = s[9]; t[6] = s[14]; t[7] = s[3];
t[8] = s[8]; t[9] = s[13]; t[10] = s[2]; t[11] = s[7];
t[12] = s[12]; t[13] = s[1]; t[14] = s[6]; t[15] = s[11];
(void) _copy(s, sizeof(t), t, sizeof(t));
}
int tc_aes_encrypt(uint8_t *out, const uint8_t *in, const TCAesKeySched_t s)
{
uint8_t state[Nk*Nb];
unsigned int i;
if (out == (uint8_t *) 0) {
return TC_CRYPTO_FAIL;
} else if (in == (const uint8_t *) 0) {
return TC_CRYPTO_FAIL;
} else if (s == (TCAesKeySched_t) 0) {
return TC_CRYPTO_FAIL;
}
(void)_copy(state, sizeof(state), in, sizeof(state));
add_round_key(state, s->words);
for (i = 0; i < (Nr - 1); ++i) {
sub_bytes(state);
shift_rows(state);
mix_columns(state);
add_round_key(state, s->words + Nb*(i+1));
}
sub_bytes(state);
shift_rows(state);
add_round_key(state, s->words + Nb*(i+1));
(void)_copy(out, sizeof(state), state, sizeof(state));
/* zeroing out the state buffer */
_set(state, TC_ZERO_BYTE, sizeof(state));
return TC_CRYPTO_SUCCESS;
}

View File

@@ -0,0 +1,114 @@
/* cbc_mode.c - TinyCrypt implementation of CBC mode encryption & decryption */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../include/tinycrypt/cbc_mode.h"
#include "../include/tinycrypt/constants.h"
#include "../include/tinycrypt/utils.h"
int tc_cbc_mode_encrypt(uint8_t *out, unsigned int outlen, const uint8_t *in,
unsigned int inlen, const uint8_t *iv,
const TCAesKeySched_t sched)
{
uint8_t buffer[TC_AES_BLOCK_SIZE];
unsigned int n, m;
/* input sanity check: */
if (out == (uint8_t *) 0 ||
in == (const uint8_t *) 0 ||
sched == (TCAesKeySched_t) 0 ||
inlen == 0 ||
outlen == 0 ||
(inlen % TC_AES_BLOCK_SIZE) != 0 ||
(outlen % TC_AES_BLOCK_SIZE) != 0 ||
outlen != inlen + TC_AES_BLOCK_SIZE) {
return TC_CRYPTO_FAIL;
}
/* copy iv to the buffer */
(void)_copy(buffer, TC_AES_BLOCK_SIZE, iv, TC_AES_BLOCK_SIZE);
/* copy iv to the output buffer */
(void)_copy(out, TC_AES_BLOCK_SIZE, iv, TC_AES_BLOCK_SIZE);
out += TC_AES_BLOCK_SIZE;
for (n = m = 0; n < inlen; ++n) {
buffer[m++] ^= *in++;
if (m == TC_AES_BLOCK_SIZE) {
(void)tc_aes_encrypt(buffer, buffer, sched);
(void)_copy(out, TC_AES_BLOCK_SIZE,
buffer, TC_AES_BLOCK_SIZE);
out += TC_AES_BLOCK_SIZE;
m = 0;
}
}
return TC_CRYPTO_SUCCESS;
}
int tc_cbc_mode_decrypt(uint8_t *out, unsigned int outlen, const uint8_t *in,
unsigned int inlen, const uint8_t *iv,
const TCAesKeySched_t sched)
{
uint8_t buffer[TC_AES_BLOCK_SIZE];
const uint8_t *p;
unsigned int n, m;
/* sanity check the inputs */
if (out == (uint8_t *) 0 ||
in == (const uint8_t *) 0 ||
sched == (TCAesKeySched_t) 0 ||
inlen == 0 ||
outlen == 0 ||
(inlen % TC_AES_BLOCK_SIZE) != 0 ||
(outlen % TC_AES_BLOCK_SIZE) != 0 ||
outlen != inlen - TC_AES_BLOCK_SIZE) {
return TC_CRYPTO_FAIL;
}
/*
* Note that in == iv + ciphertext, i.e. the iv and the ciphertext are
* contiguous. This allows for a very efficient decryption algorithm
* that would not otherwise be possible.
*/
p = iv;
for (n = m = 0; n < inlen; ++n) {
if ((n % TC_AES_BLOCK_SIZE) == 0) {
(void)tc_aes_decrypt(buffer, in, sched);
in += TC_AES_BLOCK_SIZE;
m = 0;
}
*out++ = buffer[m++] ^ *p++;
}
return TC_CRYPTO_SUCCESS;
}

View File

@@ -0,0 +1,266 @@
/* ccm_mode.c - TinyCrypt implementation of CCM mode */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../include/tinycrypt/ccm_mode.h"
#include "../include/tinycrypt/constants.h"
#include "../include/tinycrypt/utils.h"
#include <stdio.h>
int tc_ccm_config(TCCcmMode_t c, TCAesKeySched_t sched, uint8_t *nonce,
unsigned int nlen, unsigned int mlen)
{
/* input sanity check: */
if (c == (TCCcmMode_t) 0 ||
sched == (TCAesKeySched_t) 0 ||
nonce == (uint8_t *) 0) {
return TC_CRYPTO_FAIL;
} else if (nlen != 13) {
return TC_CRYPTO_FAIL; /* The allowed nonce size is: 13. See documentation.*/
} else if ((mlen < 4) || (mlen > 16) || (mlen & 1)) {
return TC_CRYPTO_FAIL; /* The allowed mac sizes are: 4, 6, 8, 10, 12, 14, 16.*/
}
c->mlen = mlen;
c->sched = sched;
c->nonce = nonce;
return TC_CRYPTO_SUCCESS;
}
/**
* Variation of CBC-MAC mode used in CCM.
*/
static void ccm_cbc_mac(uint8_t *T, const uint8_t *data, unsigned int dlen,
unsigned int flag, TCAesKeySched_t sched)
{
unsigned int i;
if (flag > 0) {
T[0] ^= (uint8_t)(dlen >> 8);
T[1] ^= (uint8_t)(dlen);
dlen += 2; i = 2;
} else {
i = 0;
}
while (i < dlen) {
T[i++ % (Nb * Nk)] ^= *data++;
if (((i % (Nb * Nk)) == 0) || dlen == i) {
(void) tc_aes_encrypt(T, T, sched);
}
}
}
/**
* Variation of CTR mode used in CCM.
* The CTR mode used by CCM is slightly different than the conventional CTR
* mode (the counter is increased before encryption, instead of after
* encryption). Besides, it is assumed that the counter is stored in the last
* 2 bytes of the nonce.
*/
static int ccm_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in,
unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched)
{
uint8_t buffer[TC_AES_BLOCK_SIZE];
uint8_t nonce[TC_AES_BLOCK_SIZE];
uint16_t block_num;
unsigned int i;
/* input sanity check: */
if (out == (uint8_t *) 0 ||
in == (uint8_t *) 0 ||
ctr == (uint8_t *) 0 ||
sched == (TCAesKeySched_t) 0 ||
inlen == 0 ||
outlen == 0 ||
outlen != inlen) {
return TC_CRYPTO_FAIL;
}
/* copy the counter to the nonce */
(void) _copy(nonce, sizeof(nonce), ctr, sizeof(nonce));
/* select the last 2 bytes of the nonce to be incremented */
block_num = (uint16_t) ((nonce[14] << 8)|(nonce[15]));
for (i = 0; i < inlen; ++i) {
if ((i % (TC_AES_BLOCK_SIZE)) == 0) {
block_num++;
nonce[14] = (uint8_t)(block_num >> 8);
nonce[15] = (uint8_t)(block_num);
if (!tc_aes_encrypt(buffer, nonce, sched)) {
return TC_CRYPTO_FAIL;
}
}
/* update the output */
*out++ = buffer[i % (TC_AES_BLOCK_SIZE)] ^ *in++;
}
/* update the counter */
ctr[14] = nonce[14]; ctr[15] = nonce[15];
return TC_CRYPTO_SUCCESS;
}
int tc_ccm_generation_encryption(uint8_t *out, unsigned int olen,
const uint8_t *associated_data,
unsigned int alen, const uint8_t *payload,
unsigned int plen, TCCcmMode_t c)
{
/* input sanity check: */
if ((out == (uint8_t *) 0) ||
(c == (TCCcmMode_t) 0) ||
((plen > 0) && (payload == (uint8_t *) 0)) ||
((alen > 0) && (associated_data == (uint8_t *) 0)) ||
(alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */
(plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */
(olen < (plen + c->mlen))) { /* invalid output buffer size */
return TC_CRYPTO_FAIL;
}
uint8_t b[Nb * Nk];
uint8_t tag[Nb * Nk];
unsigned int i;
/* GENERATING THE AUTHENTICATION TAG: */
/* formatting the sequence b for authentication: */
b[0] = ((alen > 0) ? 0x40:0) | (((c->mlen - 2) / 2 << 3)) | (1);
for (i = 1; i <= 13; ++i) {
b[i] = c->nonce[i - 1];
}
b[14] = (uint8_t)(plen >> 8);
b[15] = (uint8_t)(plen);
/* computing the authentication tag using cbc-mac: */
(void) tc_aes_encrypt(tag, b, c->sched);
if (alen > 0) {
ccm_cbc_mac(tag, associated_data, alen, 1, c->sched);
}
if (plen > 0) {
ccm_cbc_mac(tag, payload, plen, 0, c->sched);
}
/* ENCRYPTION: */
/* formatting the sequence b for encryption: */
b[0] = 1; /* q - 1 = 2 - 1 = 1 */
b[14] = b[15] = TC_ZERO_BYTE;
/* encrypting payload using ctr mode: */
ccm_ctr_mode(out, plen, payload, plen, b, c->sched);
b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter for ctr_mode (0):*/
/* encrypting b and adding the tag to the output: */
(void) tc_aes_encrypt(b, b, c->sched);
out += plen;
for (i = 0; i < c->mlen; ++i) {
*out++ = tag[i] ^ b[i];
}
return TC_CRYPTO_SUCCESS;
}
int tc_ccm_decryption_verification(uint8_t *out, unsigned int olen,
const uint8_t *associated_data,
unsigned int alen, const uint8_t *payload,
unsigned int plen, TCCcmMode_t c)
{
/* input sanity check: */
if ((out == (uint8_t *) 0) ||
(c == (TCCcmMode_t) 0) ||
((plen > 0) && (payload == (uint8_t *) 0)) ||
((alen > 0) && (associated_data == (uint8_t *) 0)) ||
(alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */
(plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */
(olen < plen - c->mlen)) { /* invalid output buffer size */
return TC_CRYPTO_FAIL;
}
uint8_t b[Nb * Nk];
uint8_t tag[Nb * Nk];
unsigned int i;
/* DECRYPTION: */
/* formatting the sequence b for decryption: */
b[0] = 1; /* q - 1 = 2 - 1 = 1 */
for (i = 1; i < 14; ++i) {
b[i] = c->nonce[i - 1];
}
b[14] = b[15] = TC_ZERO_BYTE; /* initial counter value is 0 */
/* decrypting payload using ctr mode: */
ccm_ctr_mode(out, plen - c->mlen, payload, plen - c->mlen, b, c->sched);
b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter value (0) */
/* encrypting b and restoring the tag from input: */
(void) tc_aes_encrypt(b, b, c->sched);
for (i = 0; i < c->mlen; ++i) {
tag[i] = *(payload + plen - c->mlen + i) ^ b[i];
}
/* VERIFYING THE AUTHENTICATION TAG: */
/* formatting the sequence b for authentication: */
b[0] = ((alen > 0) ? 0x40:0)|(((c->mlen - 2) / 2 << 3)) | (1);
for (i = 1; i < 14; ++i) {
b[i] = c->nonce[i - 1];
}
b[14] = (uint8_t)((plen - c->mlen) >> 8);
b[15] = (uint8_t)(plen - c->mlen);
/* computing the authentication tag using cbc-mac: */
(void) tc_aes_encrypt(b, b, c->sched);
if (alen > 0) {
ccm_cbc_mac(b, associated_data, alen, 1, c->sched);
}
if (plen > 0) {
ccm_cbc_mac(b, out, plen - c->mlen, 0, c->sched);
}
/* comparing the received tag and the computed one: */
if (_compare(b, tag, c->mlen) == 0) {
return TC_CRYPTO_SUCCESS;
} else {
/* erase the decrypted buffer in case of mac validation failure: */
_set(out, 0, plen - c->mlen);
return TC_CRYPTO_FAIL;
}
}

View File

@@ -0,0 +1,254 @@
/* cmac_mode.c - TinyCrypt CMAC mode implementation */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../include/tinycrypt/aes.h"
#include "../include/tinycrypt/cmac_mode.h"
#include "../include/tinycrypt/constants.h"
#include "../include/tinycrypt/utils.h"
/* max number of calls until change the key (2^48).*/
const static uint64_t MAX_CALLS = ((uint64_t)1 << 48);
/*
* gf_wrap -- In our implementation, GF(2^128) is represented as a 16 byte
* array with byte 0 the most significant and byte 15 the least significant.
* High bit carry reduction is based on the primitive polynomial
*
* X^128 + X^7 + X^2 + X + 1,
*
* which leads to the reduction formula X^128 = X^7 + X^2 + X + 1. Indeed,
* since 0 = (X^128 + X^7 + X^2 + 1) mod (X^128 + X^7 + X^2 + X + 1) and since
* addition of polynomials with coefficients in Z/Z(2) is just XOR, we can
* add X^128 to both sides to get
*
* X^128 = (X^7 + X^2 + X + 1) mod (X^128 + X^7 + X^2 + X + 1)
*
* and the coefficients of the polynomial on the right hand side form the
* string 1000 0111 = 0x87, which is the value of gf_wrap.
*
* This gets used in the following way. Doubling in GF(2^128) is just a left
* shift by 1 bit, except when the most significant bit is 1. In the latter
* case, the relation X^128 = X^7 + X^2 + X + 1 says that the high order bit
* that overflows beyond 128 bits can be replaced by addition of
* X^7 + X^2 + X + 1 <--> 0x87 to the low order 128 bits. Since addition
* in GF(2^128) is represented by XOR, we therefore only have to XOR 0x87
* into the low order byte after a left shift when the starting high order
* bit is 1.
*/
const unsigned char gf_wrap = 0x87;
/*
* assumes: out != NULL and points to a GF(2^n) value to receive the
* doubled value;
* in != NULL and points to a 16 byte GF(2^n) value
* to double;
* the in and out buffers do not overlap.
* effects: doubles the GF(2^n) value pointed to by "in" and places
* the result in the GF(2^n) value pointed to by "out."
*/
void gf_double(uint8_t *out, uint8_t *in)
{
/* start with low order byte */
uint8_t *x = in + (TC_AES_BLOCK_SIZE - 1);
/* if msb == 1, we need to add the gf_wrap value, otherwise add 0 */
uint8_t carry = (in[0] >> 7) ? gf_wrap : 0;
out += (TC_AES_BLOCK_SIZE - 1);
for (;;) {
*out-- = (*x << 1) ^ carry;
if (x == in) {
break;
}
carry = *x-- >> 7;
}
}
int tc_cmac_setup(TCCmacState_t s, const uint8_t *key, TCAesKeySched_t sched)
{
/* input sanity check: */
if (s == (TCCmacState_t) 0 ||
key == (const uint8_t *) 0) {
return TC_CRYPTO_FAIL;
}
/* put s into a known state */
_set(s, 0, sizeof(*s));
s->sched = sched;
/* configure the encryption key used by the underlying block cipher */
tc_aes128_set_encrypt_key(s->sched, key);
/* compute s->K1 and s->K2 from s->iv using s->keyid */
_set(s->iv, 0, TC_AES_BLOCK_SIZE);
tc_aes_encrypt(s->iv, s->iv, s->sched);
gf_double (s->K1, s->iv);
gf_double (s->K2, s->K1);
/* reset s->iv to 0 in case someone wants to compute now */
tc_cmac_init(s);
return TC_CRYPTO_SUCCESS;
}
int tc_cmac_erase(TCCmacState_t s)
{
if (s == (TCCmacState_t) 0) {
return TC_CRYPTO_FAIL;
}
/* destroy the current state */
_set(s, 0, sizeof(*s));
return TC_CRYPTO_SUCCESS;
}
int tc_cmac_init(TCCmacState_t s)
{
/* input sanity check: */
if (s == (TCCmacState_t) 0) {
return TC_CRYPTO_FAIL;
}
/* CMAC starts with an all zero initialization vector */
_set(s->iv, 0, TC_AES_BLOCK_SIZE);
/* and the leftover buffer is empty */
_set(s->leftover, 0, TC_AES_BLOCK_SIZE);
s->leftover_offset = 0;
/* Set countdown to max number of calls allowed before re-keying: */
s->countdown = MAX_CALLS;
return TC_CRYPTO_SUCCESS;
}
int tc_cmac_update(TCCmacState_t s, const uint8_t *data, size_t data_length)
{
unsigned int i;
/* input sanity check: */
if (s == (TCCmacState_t) 0) {
return TC_CRYPTO_FAIL;
}
if (data_length == 0) {
return TC_CRYPTO_SUCCESS;
}
if (data == (const uint8_t *) 0) {
return TC_CRYPTO_FAIL;
}
if (s->countdown == 0) {
return TC_CRYPTO_FAIL;
}
s->countdown--;
if (s->leftover_offset > 0) {
/* last data added to s didn't end on a TC_AES_BLOCK_SIZE byte boundary */
size_t remaining_space = TC_AES_BLOCK_SIZE - s->leftover_offset;
if (data_length < remaining_space) {
/* still not enough data to encrypt this time either */
_copy(&s->leftover[s->leftover_offset], data_length, data, data_length);
s->leftover_offset += data_length;
return TC_CRYPTO_SUCCESS;
}
/* leftover block is now full; encrypt it first */
_copy(&s->leftover[s->leftover_offset],
remaining_space,
data,
remaining_space);
data_length -= remaining_space;
data += remaining_space;
s->leftover_offset = 0;
for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) {
s->iv[i] ^= s->leftover[i];
}
tc_aes_encrypt(s->iv, s->iv, s->sched);
}
/* CBC encrypt each (except the last) of the data blocks */
while (data_length > TC_AES_BLOCK_SIZE) {
for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) {
s->iv[i] ^= data[i];
}
tc_aes_encrypt(s->iv, s->iv, s->sched);
data += TC_AES_BLOCK_SIZE;
data_length -= TC_AES_BLOCK_SIZE;
}
if (data_length > 0) {
/* save leftover data for next time */
_copy(s->leftover, data_length, data, data_length);
s->leftover_offset = data_length;
}
return TC_CRYPTO_SUCCESS;
}
int tc_cmac_final(uint8_t *tag, TCCmacState_t s)
{
uint8_t *k;
unsigned int i;
/* input sanity check: */
if (tag == (uint8_t *) 0 ||
s == (TCCmacState_t) 0) {
return TC_CRYPTO_FAIL;
}
if (s->leftover_offset == TC_AES_BLOCK_SIZE) {
/* the last message block is a full-sized block */
k = (uint8_t *) s->K1;
} else {
/* the final message block is not a full-sized block */
size_t remaining = TC_AES_BLOCK_SIZE - s->leftover_offset;
_set(&s->leftover[s->leftover_offset], 0, remaining);
s->leftover[s->leftover_offset] = TC_CMAC_PADDING;
k = (uint8_t *) s->K2;
}
for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) {
s->iv[i] ^= s->leftover[i] ^ k[i];
}
tc_aes_encrypt(tag, s->iv, s->sched);
/* erasing state: */
tc_cmac_erase(s);
return TC_CRYPTO_SUCCESS;
}

View File

@@ -0,0 +1,85 @@
/* ctr_mode.c - TinyCrypt CTR mode implementation */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../include/tinycrypt/constants.h"
#include "../include/tinycrypt/ctr_mode.h"
#include "../include/tinycrypt/utils.h"
int tc_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in,
unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched)
{
uint8_t buffer[TC_AES_BLOCK_SIZE];
uint8_t nonce[TC_AES_BLOCK_SIZE];
unsigned int block_num;
unsigned int i;
/* input sanity check: */
if (out == (uint8_t *) 0 ||
in == (uint8_t *) 0 ||
ctr == (uint8_t *) 0 ||
sched == (TCAesKeySched_t) 0 ||
inlen == 0 ||
outlen == 0 ||
outlen != inlen) {
return TC_CRYPTO_FAIL;
}
/* copy the ctr to the nonce */
(void)_copy(nonce, sizeof(nonce), ctr, sizeof(nonce));
/* select the last 4 bytes of the nonce to be incremented */
block_num = (nonce[12] << 24) | (nonce[13] << 16) |
(nonce[14] << 8) | (nonce[15]);
for (i = 0; i < inlen; ++i) {
if ((i % (TC_AES_BLOCK_SIZE)) == 0) {
/* encrypt data using the current nonce */
if (tc_aes_encrypt(buffer, nonce, sched)) {
block_num++;
nonce[12] = (uint8_t)(block_num >> 24);
nonce[13] = (uint8_t)(block_num >> 16);
nonce[14] = (uint8_t)(block_num >> 8);
nonce[15] = (uint8_t)(block_num);
} else {
return TC_CRYPTO_FAIL;
}
}
/* update the output */
*out++ = buffer[i%(TC_AES_BLOCK_SIZE)] ^ *in++;
}
/* update the counter */
ctr[12] = nonce[12]; ctr[13] = nonce[13];
ctr[14] = nonce[14]; ctr[15] = nonce[15];
return TC_CRYPTO_SUCCESS;
}

View File

@@ -0,0 +1,283 @@
/* ctr_prng.c - TinyCrypt implementation of CTR-PRNG */
/*
* Copyright (c) 2016, Chris Morrison
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../include/tinycrypt/ctr_prng.h"
#include "../include/tinycrypt/utils.h"
#include "../include/tinycrypt/constants.h"
#include <string.h>
/*
* This PRNG is based on the CTR_DRBG described in Recommendation for Random
* Number Generation Using Deterministic Random Bit Generators,
* NIST SP 800-90A Rev. 1.
*
* Annotations to particular steps (e.g. 10.2.1.2 Step 1) refer to the steps
* described in that document.
*
*/
/**
* @brief Array incrementer
* Treats the supplied array as one contiguous number (MSB in arr[0]), and
* increments it by one
* @return none
* @param arr IN/OUT -- array to be incremented
* @param len IN -- size of arr in bytes
*/
static void arrInc(uint8_t arr[], unsigned int len)
{
unsigned int i;
if (0 != arr) {
for (i = len; i > 0U; i--) {
if (++arr[i-1] != 0U) {
break;
}
}
}
}
/**
* @brief CTR PRNG update
* Updates the internal state of supplied the CTR PRNG context
* increments it by one
* @return none
* @note Assumes: providedData is (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes long
* @param ctx IN/OUT -- CTR PRNG state
* @param providedData IN -- data used when updating the internal state
*/
static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const * const providedData)
{
if (0 != ctx) {
/* 10.2.1.2 step 1 */
uint8_t temp[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
unsigned int len = 0U;
/* 10.2.1.2 step 2 */
while (len < sizeof temp) {
unsigned int blocklen = sizeof(temp) - len;
uint8_t output_block[TC_AES_BLOCK_SIZE];
/* 10.2.1.2 step 2.1 */
arrInc(ctx->V, sizeof ctx->V);
/* 10.2.1.2 step 2.2 */
if (blocklen > TC_AES_BLOCK_SIZE) {
blocklen = TC_AES_BLOCK_SIZE;
}
(void)tc_aes_encrypt(output_block, ctx->V, &ctx->key);
/* 10.2.1.2 step 2.3/step 3 */
memcpy(&(temp[len]), output_block, blocklen);
len += blocklen;
}
/* 10.2.1.2 step 4 */
if (0 != providedData) {
unsigned int i;
for (i = 0U; i < sizeof temp; i++) {
temp[i] ^= providedData[i];
}
}
/* 10.2.1.2 step 5 */
(void)tc_aes128_set_encrypt_key(&ctx->key, temp);
/* 10.2.1.2 step 6 */
memcpy(ctx->V, &(temp[TC_AES_KEY_SIZE]), TC_AES_BLOCK_SIZE);
}
}
int tc_ctr_prng_init(TCCtrPrng_t * const ctx,
uint8_t const * const entropy,
unsigned int entropyLen,
uint8_t const * const personalization,
unsigned int pLen)
{
int result = TC_CRYPTO_FAIL;
unsigned int i;
uint8_t personalization_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
uint8_t zeroArr[TC_AES_BLOCK_SIZE] = {0U};
if (0 != personalization) {
/* 10.2.1.3.1 step 1 */
unsigned int len = pLen;
if (len > sizeof personalization_buf) {
len = sizeof personalization_buf;
}
/* 10.2.1.3.1 step 2 */
memcpy(personalization_buf, personalization, len);
}
if ((0 != ctx) && (0 != entropy) && (entropyLen >= sizeof seed_material)) {
/* 10.2.1.3.1 step 3 */
memcpy(seed_material, entropy, sizeof seed_material);
for (i = 0U; i < sizeof seed_material; i++) {
seed_material[i] ^= personalization_buf[i];
}
/* 10.2.1.3.1 step 4 */
(void)tc_aes128_set_encrypt_key(&ctx->key, zeroArr);
/* 10.2.1.3.1 step 5 */
memset(ctx->V, 0x00, sizeof ctx->V);
/* 10.2.1.3.1 step 6 */
tc_ctr_prng_update(ctx, seed_material);
/* 10.2.1.3.1 step 7 */
ctx->reseedCount = 1U;
result = TC_CRYPTO_SUCCESS;
}
return result;
}
int tc_ctr_prng_reseed(TCCtrPrng_t * const ctx,
uint8_t const * const entropy,
unsigned int entropyLen,
uint8_t const * const additional_input,
unsigned int additionallen)
{
unsigned int i;
int result = TC_CRYPTO_FAIL;
uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
if (0 != additional_input) {
/* 10.2.1.4.1 step 1 */
unsigned int len = additionallen;
if (len > sizeof additional_input_buf) {
len = sizeof additional_input_buf;
}
/* 10.2.1.4.1 step 2 */
memcpy(additional_input_buf, additional_input, len);
}
unsigned int seedlen = (unsigned int)TC_AES_KEY_SIZE + (unsigned int)TC_AES_BLOCK_SIZE;
if ((0 != ctx) && (entropyLen >= seedlen)) {
/* 10.2.1.4.1 step 3 */
memcpy(seed_material, entropy, sizeof seed_material);
for (i = 0U; i < sizeof seed_material; i++) {
seed_material[i] ^= additional_input_buf[i];
}
/* 10.2.1.4.1 step 4 */
tc_ctr_prng_update(ctx, seed_material);
/* 10.2.1.4.1 step 5 */
ctx->reseedCount = 1U;
result = TC_CRYPTO_SUCCESS;
}
return result;
}
int tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
uint8_t const * const additional_input,
unsigned int additionallen,
uint8_t * const out,
unsigned int outlen)
{
/* 2^48 - see section 10.2.1 */
static const uint64_t MAX_REQS_BEFORE_RESEED = 0x1000000000000ULL;
/* 2^19 bits - see section 10.2.1 */
static const unsigned int MAX_BYTES_PER_REQ = 65536U;
unsigned int result = TC_CRYPTO_FAIL;
if ((0 != ctx) && (0 != out) && (outlen < MAX_BYTES_PER_REQ)) {
/* 10.2.1.5.1 step 1 */
if (ctx->reseedCount > MAX_REQS_BEFORE_RESEED) {
result = TC_CTR_PRNG_RESEED_REQ;
} else {
uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
if (0 != additional_input) {
/* 10.2.1.5.1 step 2 */
unsigned int len = additionallen;
if (len > sizeof additional_input_buf) {
len = sizeof additional_input_buf;
}
memcpy(additional_input_buf, additional_input, len);
tc_ctr_prng_update(ctx, additional_input_buf);
}
/* 10.2.1.5.1 step 3 - implicit */
/* 10.2.1.5.1 step 4 */
unsigned int len = 0U;
while (len < outlen) {
unsigned int blocklen = outlen - len;
uint8_t output_block[TC_AES_BLOCK_SIZE];
/* 10.2.1.5.1 step 4.1 */
arrInc(ctx->V, sizeof ctx->V);
/* 10.2.1.5.1 step 4.2 */
(void)tc_aes_encrypt(output_block, ctx->V, &ctx->key);
/* 10.2.1.5.1 step 4.3/step 5 */
if (blocklen > TC_AES_BLOCK_SIZE) {
blocklen = TC_AES_BLOCK_SIZE;
}
memcpy(&(out[len]), output_block, blocklen);
len += blocklen;
}
/* 10.2.1.5.1 step 6 */
tc_ctr_prng_update(ctx, additional_input_buf);
/* 10.2.1.5.1 step 7 */
ctx->reseedCount++;
/* 10.2.1.5.1 step 8 */
result = TC_CRYPTO_SUCCESS;
}
}
return result;
}
void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx)
{
if (0 != ctx) {
memset(ctx->key.words, 0x00, sizeof ctx->key.words);
memset(ctx->V, 0x00, sizeof ctx->V);
ctx->reseedCount = 0U;
}
}

View File

@@ -0,0 +1,942 @@
/* ecc.c - TinyCrypt implementation of common ECC functions */
/*
* Copyright (c) 2014, Kenneth MacKay
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../include/tinycrypt/ecc.h"
#include "../include/tinycrypt/ecc_platform_specific.h"
#include <string.h>
/* IMPORTANT: Make sure a cryptographically-secure PRNG is set and the platform
* has access to enough entropy in order to feed the PRNG regularly. */
#if default_RNG_defined
static uECC_RNG_Function g_rng_function = &default_CSPRNG;
#else
static uECC_RNG_Function g_rng_function = 0;
#endif
void uECC_set_rng(uECC_RNG_Function rng_function)
{
g_rng_function = rng_function;
}
uECC_RNG_Function uECC_get_rng(void)
{
return g_rng_function;
}
int uECC_curve_private_key_size(uECC_Curve curve)
{
return BITS_TO_BYTES(curve->num_n_bits);
}
int uECC_curve_public_key_size(uECC_Curve curve)
{
return 2 * curve->num_bytes;
}
void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words)
{
wordcount_t i;
for (i = 0; i < num_words; ++i) {
vli[i] = 0;
}
}
uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words)
{
uECC_word_t bits = 0;
wordcount_t i;
for (i = 0; i < num_words; ++i) {
bits |= vli[i];
}
return (bits == 0);
}
uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit)
{
return (vli[bit >> uECC_WORD_BITS_SHIFT] &
((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));
}
/* Counts the number of words in vli. */
static wordcount_t vli_numDigits(const uECC_word_t *vli,
const wordcount_t max_words)
{
wordcount_t i;
/* Search from the end until we find a non-zero digit. We do it in reverse
* because we expect that most digits will be nonzero. */
for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) {
}
return (i + 1);
}
bitcount_t uECC_vli_numBits(const uECC_word_t *vli,
const wordcount_t max_words)
{
uECC_word_t i;
uECC_word_t digit;
wordcount_t num_digits = vli_numDigits(vli, max_words);
if (num_digits == 0) {
return 0;
}
digit = vli[num_digits - 1];
for (i = 0; digit; ++i) {
digit >>= 1;
}
return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);
}
void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src,
wordcount_t num_words)
{
wordcount_t i;
for (i = 0; i < num_words; ++i) {
dest[i] = src[i];
}
}
cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words)
{
wordcount_t i;
for (i = num_words - 1; i >= 0; --i) {
if (left[i] > right[i]) {
return 1;
} else if (left[i] < right[i]) {
return -1;
}
}
return 0;
}
uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right,
wordcount_t num_words)
{
uECC_word_t diff = 0;
wordcount_t i;
for (i = num_words - 1; i >= 0; --i) {
diff |= (left[i] ^ right[i]);
}
return !(diff == 0);
}
uECC_word_t cond_set(uECC_word_t p_true, uECC_word_t p_false, unsigned int cond)
{
return (p_true*(cond)) | (p_false*(!cond));
}
/* Computes result = left - right, returning borrow, in constant time.
* Can modify in place. */
uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, wordcount_t num_words)
{
uECC_word_t borrow = 0;
wordcount_t i;
for (i = 0; i < num_words; ++i) {
uECC_word_t diff = left[i] - right[i] - borrow;
uECC_word_t val = (diff > left[i]);
borrow = cond_set(val, borrow, (diff != left[i]));
result[i] = diff;
}
return borrow;
}
/* Computes result = left + right, returning carry, in constant time.
* Can modify in place. */
static uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, wordcount_t num_words)
{
uECC_word_t carry = 0;
wordcount_t i;
for (i = 0; i < num_words; ++i) {
uECC_word_t sum = left[i] + right[i] + carry;
uECC_word_t val = (sum < left[i]);
carry = cond_set(val, carry, (sum != left[i]));
result[i] = sum;
}
return carry;
}
cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right,
wordcount_t num_words)
{
uECC_word_t tmp[NUM_ECC_WORDS];
uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words);
uECC_word_t equal = uECC_vli_isZero(tmp, num_words);
return (!equal - 2 * neg);
}
/* Computes vli = vli >> 1. */
static void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words)
{
uECC_word_t *end = vli;
uECC_word_t carry = 0;
vli += num_words;
while (vli-- > end) {
uECC_word_t temp = *vli;
*vli = (temp >> 1) | carry;
carry = temp << (uECC_WORD_BITS - 1);
}
}
static void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0,
uECC_word_t *r1, uECC_word_t *r2)
{
uECC_dword_t p = (uECC_dword_t)a * b;
uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
r01 += p;
*r2 += (r01 < p);
*r1 = r01 >> uECC_WORD_BITS;
*r0 = (uECC_word_t)r01;
}
/* Computes result = left * right. Result must be 2 * num_words long. */
static void uECC_vli_mult(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, wordcount_t num_words)
{
uECC_word_t r0 = 0;
uECC_word_t r1 = 0;
uECC_word_t r2 = 0;
wordcount_t i, k;
/* Compute each digit of result in sequence, maintaining the carries. */
for (k = 0; k < num_words; ++k) {
for (i = 0; i <= k; ++i) {
muladd(left[i], right[k - i], &r0, &r1, &r2);
}
result[k] = r0;
r0 = r1;
r1 = r2;
r2 = 0;
}
for (k = num_words; k < num_words * 2 - 1; ++k) {
for (i = (k + 1) - num_words; i < num_words; ++i) {
muladd(left[i], right[k - i], &r0, &r1, &r2);
}
result[k] = r0;
r0 = r1;
r1 = r2;
r2 = 0;
}
result[num_words * 2 - 1] = r0;
}
void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, const uECC_word_t *mod,
wordcount_t num_words)
{
uECC_word_t carry = uECC_vli_add(result, left, right, num_words);
if (carry || uECC_vli_cmp_unsafe(mod, result, num_words) != 1) {
/* result > mod (result = mod + remainder), so subtract mod to get
* remainder. */
uECC_vli_sub(result, result, mod, num_words);
}
}
void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, const uECC_word_t *mod,
wordcount_t num_words)
{
uECC_word_t l_borrow = uECC_vli_sub(result, left, right, num_words);
if (l_borrow) {
/* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,
* we can get the correct result from result + mod (with overflow). */
uECC_vli_add(result, result, mod, num_words);
}
}
/* Computes result = product % mod, where product is 2N words long. */
/* Currently only designed to work for curve_p or curve_n. */
void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
const uECC_word_t *mod, wordcount_t num_words)
{
uECC_word_t mod_multiple[2 * NUM_ECC_WORDS];
uECC_word_t tmp[2 * NUM_ECC_WORDS];
uECC_word_t *v[2] = {tmp, product};
uECC_word_t index;
/* Shift mod so its highest set bit is at the maximum position. */
bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) -
uECC_vli_numBits(mod, num_words);
wordcount_t word_shift = shift / uECC_WORD_BITS;
wordcount_t bit_shift = shift % uECC_WORD_BITS;
uECC_word_t carry = 0;
uECC_vli_clear(mod_multiple, word_shift);
if (bit_shift > 0) {
for(index = 0; index < (uECC_word_t)num_words; ++index) {
mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry;
carry = mod[index] >> (uECC_WORD_BITS - bit_shift);
}
} else {
uECC_vli_set(mod_multiple + word_shift, mod, num_words);
}
for (index = 1; shift >= 0; --shift) {
uECC_word_t borrow = 0;
wordcount_t i;
for (i = 0; i < num_words * 2; ++i) {
uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow;
if (diff != v[index][i]) {
borrow = (diff > v[index][i]);
}
v[1 - index][i] = diff;
}
/* Swap the index if there was no borrow */
index = !(index ^ borrow);
uECC_vli_rshift1(mod_multiple, num_words);
mod_multiple[num_words - 1] |= mod_multiple[num_words] <<
(uECC_WORD_BITS - 1);
uECC_vli_rshift1(mod_multiple + num_words, num_words);
}
uECC_vli_set(result, v[index], num_words);
}
void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, const uECC_word_t *mod,
wordcount_t num_words)
{
uECC_word_t product[2 * NUM_ECC_WORDS];
uECC_vli_mult(product, left, right, num_words);
uECC_vli_mmod(result, product, mod, num_words);
}
void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
const uECC_word_t *right, uECC_Curve curve)
{
uECC_word_t product[2 * NUM_ECC_WORDS];
uECC_vli_mult(product, left, right, curve->num_words);
curve->mmod_fast(result, product);
}
static void uECC_vli_modSquare_fast(uECC_word_t *result,
const uECC_word_t *left,
uECC_Curve curve)
{
uECC_vli_modMult_fast(result, left, left, curve);
}
#define EVEN(vli) (!(vli[0] & 1))
static void vli_modInv_update(uECC_word_t *uv,
const uECC_word_t *mod,
wordcount_t num_words)
{
uECC_word_t carry = 0;
if (!EVEN(uv)) {
carry = uECC_vli_add(uv, uv, mod, num_words);
}
uECC_vli_rshift1(uv, num_words);
if (carry) {
uv[num_words - 1] |= HIGH_BIT_SET;
}
}
void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
const uECC_word_t *mod, wordcount_t num_words)
{
uECC_word_t a[NUM_ECC_WORDS], b[NUM_ECC_WORDS];
uECC_word_t u[NUM_ECC_WORDS], v[NUM_ECC_WORDS];
cmpresult_t cmpResult;
if (uECC_vli_isZero(input, num_words)) {
uECC_vli_clear(result, num_words);
return;
}
uECC_vli_set(a, input, num_words);
uECC_vli_set(b, mod, num_words);
uECC_vli_clear(u, num_words);
u[0] = 1;
uECC_vli_clear(v, num_words);
while ((cmpResult = uECC_vli_cmp_unsafe(a, b, num_words)) != 0) {
if (EVEN(a)) {
uECC_vli_rshift1(a, num_words);
vli_modInv_update(u, mod, num_words);
} else if (EVEN(b)) {
uECC_vli_rshift1(b, num_words);
vli_modInv_update(v, mod, num_words);
} else if (cmpResult > 0) {
uECC_vli_sub(a, a, b, num_words);
uECC_vli_rshift1(a, num_words);
if (uECC_vli_cmp_unsafe(u, v, num_words) < 0) {
uECC_vli_add(u, u, mod, num_words);
}
uECC_vli_sub(u, u, v, num_words);
vli_modInv_update(u, mod, num_words);
} else {
uECC_vli_sub(b, b, a, num_words);
uECC_vli_rshift1(b, num_words);
if (uECC_vli_cmp_unsafe(v, u, num_words) < 0) {
uECC_vli_add(v, v, mod, num_words);
}
uECC_vli_sub(v, v, u, num_words);
vli_modInv_update(v, mod, num_words);
}
}
uECC_vli_set(result, u, num_words);
}
/* ------ Point operations ------ */
void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1,
uECC_word_t * Z1, uECC_Curve curve)
{
/* t1 = X, t2 = Y, t3 = Z */
uECC_word_t t4[NUM_ECC_WORDS];
uECC_word_t t5[NUM_ECC_WORDS];
wordcount_t num_words = curve->num_words;
if (uECC_vli_isZero(Z1, num_words)) {
return;
}
uECC_vli_modSquare_fast(t4, Y1, curve); /* t4 = y1^2 */
uECC_vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */
uECC_vli_modSquare_fast(t4, t4, curve); /* t4 = y1^4 */
uECC_vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */
uECC_vli_modSquare_fast(Z1, Z1, curve); /* t3 = z1^2 */
uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */
uECC_vli_modAdd(Z1, Z1, Z1, curve->p, num_words); /* t3 = 2*z1^2 */
uECC_vli_modSub(Z1, X1, Z1, curve->p, num_words); /* t3 = x1 - z1^2 */
uECC_vli_modMult_fast(X1, X1, Z1, curve); /* t1 = x1^2 - z1^4 */
uECC_vli_modAdd(Z1, X1, X1, curve->p, num_words); /* t3 = 2*(x1^2 - z1^4) */
uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = 3*(x1^2 - z1^4) */
if (uECC_vli_testBit(X1, 0)) {
uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words);
uECC_vli_rshift1(X1, num_words);
X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);
} else {
uECC_vli_rshift1(X1, num_words);
}
/* t1 = 3/2*(x1^2 - z1^4) = B */
uECC_vli_modSquare_fast(Z1, X1, curve); /* t3 = B^2 */
uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - A */
uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - 2A = x3 */
uECC_vli_modSub(t5, t5, Z1, curve->p, num_words); /* t5 = A - x3 */
uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = B * (A - x3) */
/* t4 = B * (A - x3) - y1^4 = y3: */
uECC_vli_modSub(t4, X1, t4, curve->p, num_words);
uECC_vli_set(X1, Z1, num_words);
uECC_vli_set(Z1, Y1, num_words);
uECC_vli_set(Y1, t4, num_words);
}
void x_side_default(uECC_word_t *result,
const uECC_word_t *x,
uECC_Curve curve)
{
uECC_word_t _3[NUM_ECC_WORDS] = {3}; /* -a = 3 */
wordcount_t num_words = curve->num_words;
uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */
uECC_vli_modSub(result, result, _3, curve->p, num_words); /* r = x^2 - 3 */
uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 - 3x */
/* r = x^3 - 3x + b: */
uECC_vli_modAdd(result, result, curve->b, curve->p, num_words);
}
uECC_Curve uECC_secp256r1(void)
{
return &curve_secp256r1;
}
void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int*product)
{
unsigned int tmp[NUM_ECC_WORDS];
int carry;
/* t */
uECC_vli_set(result, product, NUM_ECC_WORDS);
/* s1 */
tmp[0] = tmp[1] = tmp[2] = 0;
tmp[3] = product[11];
tmp[4] = product[12];
tmp[5] = product[13];
tmp[6] = product[14];
tmp[7] = product[15];
carry = uECC_vli_add(tmp, tmp, tmp, NUM_ECC_WORDS);
carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS);
/* s2 */
tmp[3] = product[12];
tmp[4] = product[13];
tmp[5] = product[14];
tmp[6] = product[15];
tmp[7] = 0;
carry += uECC_vli_add(tmp, tmp, tmp, NUM_ECC_WORDS);
carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS);
/* s3 */
tmp[0] = product[8];
tmp[1] = product[9];
tmp[2] = product[10];
tmp[3] = tmp[4] = tmp[5] = 0;
tmp[6] = product[14];
tmp[7] = product[15];
carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS);
/* s4 */
tmp[0] = product[9];
tmp[1] = product[10];
tmp[2] = product[11];
tmp[3] = product[13];
tmp[4] = product[14];
tmp[5] = product[15];
tmp[6] = product[13];
tmp[7] = product[8];
carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS);
/* d1 */
tmp[0] = product[11];
tmp[1] = product[12];
tmp[2] = product[13];
tmp[3] = tmp[4] = tmp[5] = 0;
tmp[6] = product[8];
tmp[7] = product[10];
carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS);
/* d2 */
tmp[0] = product[12];
tmp[1] = product[13];
tmp[2] = product[14];
tmp[3] = product[15];
tmp[4] = tmp[5] = 0;
tmp[6] = product[9];
tmp[7] = product[11];
carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS);
/* d3 */
tmp[0] = product[13];
tmp[1] = product[14];
tmp[2] = product[15];
tmp[3] = product[8];
tmp[4] = product[9];
tmp[5] = product[10];
tmp[6] = 0;
tmp[7] = product[12];
carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS);
/* d4 */
tmp[0] = product[14];
tmp[1] = product[15];
tmp[2] = 0;
tmp[3] = product[9];
tmp[4] = product[10];
tmp[5] = product[11];
tmp[6] = 0;
tmp[7] = product[13];
carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS);
if (carry < 0) {
do {
carry += uECC_vli_add(result, result, curve_secp256r1.p, NUM_ECC_WORDS);
}
while (carry < 0);
} else {
while (carry ||
uECC_vli_cmp_unsafe(curve_secp256r1.p, result, NUM_ECC_WORDS) != 1) {
carry -= uECC_vli_sub(result, result, curve_secp256r1.p, NUM_ECC_WORDS);
}
}
}
uECC_word_t EccPoint_isZero(const uECC_word_t *point, uECC_Curve curve)
{
return uECC_vli_isZero(point, curve->num_words * 2);
}
void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z,
uECC_Curve curve)
{
uECC_word_t t1[NUM_ECC_WORDS];
uECC_vli_modSquare_fast(t1, Z, curve); /* z^2 */
uECC_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */
uECC_vli_modMult_fast(t1, t1, Z, curve); /* z^3 */
uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */
}
/* P = (x1, y1) => 2P, (x2, y2) => P' */
static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1,
uECC_word_t * X2, uECC_word_t * Y2,
const uECC_word_t * const initial_Z,
uECC_Curve curve)
{
uECC_word_t z[NUM_ECC_WORDS];
wordcount_t num_words = curve->num_words;
if (initial_Z) {
uECC_vli_set(z, initial_Z, num_words);
} else {
uECC_vli_clear(z, num_words);
z[0] = 1;
}
uECC_vli_set(X2, X1, num_words);
uECC_vli_set(Y2, Y1, num_words);
apply_z(X1, Y1, z, curve);
curve->double_jacobian(X1, Y1, z, curve);
apply_z(X2, Y2, z, curve);
}
void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1,
uECC_word_t * X2, uECC_word_t * Y2,
uECC_Curve curve)
{
/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
uECC_word_t t5[NUM_ECC_WORDS];
wordcount_t num_words = curve->num_words;
uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */
uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */
uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */
uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */
uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */
uECC_vli_modSquare_fast(t5, Y2, curve); /* t5 = (y2 - y1)^2 = D */
uECC_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */
uECC_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */
uECC_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */
uECC_vli_modMult_fast(Y1, Y1, X2, curve); /* t2 = y1*(C - B) */
uECC_vli_modSub(X2, X1, t5, curve->p, num_words); /* t3 = B - x3 */
uECC_vli_modMult_fast(Y2, Y2, X2, curve); /* t4 = (y2 - y1)*(B - x3) */
uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */
uECC_vli_set(X2, t5, num_words);
}
/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
or P => P - Q, Q => P + Q
*/
static void XYcZ_addC(uECC_word_t * X1, uECC_word_t * Y1,
uECC_word_t * X2, uECC_word_t * Y2,
uECC_Curve curve)
{
/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
uECC_word_t t5[NUM_ECC_WORDS];
uECC_word_t t6[NUM_ECC_WORDS];
uECC_word_t t7[NUM_ECC_WORDS];
wordcount_t num_words = curve->num_words;
uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */
uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */
uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */
uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */
uECC_vli_modAdd(t5, Y2, Y1, curve->p, num_words); /* t5 = y2 + y1 */
uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */
uECC_vli_modSub(t6, X2, X1, curve->p, num_words); /* t6 = C - B */
uECC_vli_modMult_fast(Y1, Y1, t6, curve); /* t2 = y1 * (C - B) = E */
uECC_vli_modAdd(t6, X1, X2, curve->p, num_words); /* t6 = B + C */
uECC_vli_modSquare_fast(X2, Y2, curve); /* t3 = (y2 - y1)^2 = D */
uECC_vli_modSub(X2, X2, t6, curve->p, num_words); /* t3 = D - (B + C) = x3 */
uECC_vli_modSub(t7, X1, X2, curve->p, num_words); /* t7 = B - x3 */
uECC_vli_modMult_fast(Y2, Y2, t7, curve); /* t4 = (y2 - y1)*(B - x3) */
/* t4 = (y2 - y1)*(B - x3) - E = y3: */
uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words);
uECC_vli_modSquare_fast(t7, t5, curve); /* t7 = (y2 + y1)^2 = F */
uECC_vli_modSub(t7, t7, t6, curve->p, num_words); /* t7 = F - (B + C) = x3' */
uECC_vli_modSub(t6, t7, X1, curve->p, num_words); /* t6 = x3' - B */
uECC_vli_modMult_fast(t6, t6, t5, curve); /* t6 = (y2+y1)*(x3' - B) */
/* t2 = (y2+y1)*(x3' - B) - E = y3': */
uECC_vli_modSub(Y1, t6, Y1, curve->p, num_words);
uECC_vli_set(X1, t7, num_words);
}
void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point,
const uECC_word_t * scalar,
const uECC_word_t * initial_Z,
bitcount_t num_bits, uECC_Curve curve)
{
/* R0 and R1 */
uECC_word_t Rx[2][NUM_ECC_WORDS];
uECC_word_t Ry[2][NUM_ECC_WORDS];
uECC_word_t z[NUM_ECC_WORDS];
bitcount_t i;
uECC_word_t nb;
wordcount_t num_words = curve->num_words;
uECC_vli_set(Rx[1], point, num_words);
uECC_vli_set(Ry[1], point + num_words, num_words);
XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z, curve);
for (i = num_bits - 2; i > 0; --i) {
nb = !uECC_vli_testBit(scalar, i);
XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve);
XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve);
}
nb = !uECC_vli_testBit(scalar, 0);
XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve);
/* Find final 1/Z value. */
uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */
uECC_vli_modMult_fast(z, z, Ry[1 - nb], curve); /* Yb * (X1 - X0) */
uECC_vli_modMult_fast(z, z, point, curve); /* xP * Yb * (X1 - X0) */
uECC_vli_modInv(z, z, curve->p, num_words); /* 1 / (xP * Yb * (X1 - X0))*/
/* yP / (xP * Yb * (X1 - X0)) */
uECC_vli_modMult_fast(z, z, point + num_words, curve);
/* Xb * yP / (xP * Yb * (X1 - X0)) */
uECC_vli_modMult_fast(z, z, Rx[1 - nb], curve);
/* End 1/Z calculation */
XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve);
apply_z(Rx[0], Ry[0], z, curve);
uECC_vli_set(result, Rx[0], num_words);
uECC_vli_set(result + num_words, Ry[0], num_words);
}
uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0,
uECC_word_t *k1, uECC_Curve curve)
{
wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
bitcount_t num_n_bits = curve->num_n_bits;
uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) ||
(num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) &&
uECC_vli_testBit(k0, num_n_bits));
uECC_vli_add(k1, k0, curve->n, num_n_words);
return carry;
}
uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
uECC_word_t *private_key,
uECC_Curve curve)
{
uECC_word_t tmp1[NUM_ECC_WORDS];
uECC_word_t tmp2[NUM_ECC_WORDS];
uECC_word_t *p2[2] = {tmp1, tmp2};
uECC_word_t carry;
/* Regularize the bitcount for the private key so that attackers cannot
* use a side channel attack to learn the number of leading zeros. */
carry = regularize_k(private_key, tmp1, tmp2, curve);
EccPoint_mult(result, curve->G, p2[!carry], 0, curve->num_n_bits + 1, curve);
if (EccPoint_isZero(result, curve)) {
return 0;
}
return 1;
}
/* Converts an integer in uECC native format to big-endian bytes. */
void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
const unsigned int *native)
{
wordcount_t i;
for (i = 0; i < num_bytes; ++i) {
unsigned b = num_bytes - 1 - i;
bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE));
}
}
/* Converts big-endian bytes to an integer in uECC native format. */
void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes,
int num_bytes)
{
wordcount_t i;
uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE);
for (i = 0; i < num_bytes; ++i) {
unsigned b = num_bytes - 1 - i;
native[b / uECC_WORD_SIZE] |=
(uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE));
}
}
int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
wordcount_t num_words)
{
uECC_word_t mask = (uECC_word_t)-1;
uECC_word_t tries;
bitcount_t num_bits = uECC_vli_numBits(top, num_words);
if (!g_rng_function) {
return 0;
}
for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) {
return 0;
}
random[num_words - 1] &=
mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits));
if (!uECC_vli_isZero(random, num_words) &&
uECC_vli_cmp(top, random, num_words) == 1) {
return 1;
}
}
return 0;
}
int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve)
{
uECC_word_t tmp1[NUM_ECC_WORDS];
uECC_word_t tmp2[NUM_ECC_WORDS];
wordcount_t num_words = curve->num_words;
/* The point at infinity is invalid. */
if (EccPoint_isZero(point, curve)) {
return -1;
}
/* x and y must be smaller than p. */
if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 ||
uECC_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) {
return -2;
}
uECC_vli_modSquare_fast(tmp1, point + num_words, curve);
curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */
/* Make sure that y^2 == x^3 + ax + b */
if (uECC_vli_equal(tmp1, tmp2, num_words) != 0)
return -3;
return 0;
}
int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve)
{
uECC_word_t _public[NUM_ECC_WORDS * 2];
uECC_vli_bytesToNative(_public, public_key, curve->num_bytes);
uECC_vli_bytesToNative(
_public + curve->num_words,
public_key + curve->num_bytes,
curve->num_bytes);
if (uECC_vli_cmp_unsafe(_public, curve->G, NUM_ECC_WORDS * 2) == 0) {
return -4;
}
return uECC_valid_point(_public, curve);
}
int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key,
uECC_Curve curve)
{
uECC_word_t _private[NUM_ECC_WORDS];
uECC_word_t _public[NUM_ECC_WORDS * 2];
uECC_vli_bytesToNative(
_private,
private_key,
BITS_TO_BYTES(curve->num_n_bits));
/* Make sure the private key is in the range [1, n-1]. */
if (uECC_vli_isZero(_private, BITS_TO_WORDS(curve->num_n_bits))) {
return 0;
}
if (uECC_vli_cmp(curve->n, _private, BITS_TO_WORDS(curve->num_n_bits)) != 1) {
return 0;
}
/* Compute public key. */
if (!EccPoint_compute_public_key(_public, _private, curve)) {
return 0;
}
uECC_vli_nativeToBytes(public_key, curve->num_bytes, _public);
uECC_vli_nativeToBytes(
public_key +
curve->num_bytes, curve->num_bytes, _public + curve->num_words);
return 1;
}

View File

@@ -0,0 +1,200 @@
/* ec_dh.c - TinyCrypt implementation of EC-DH */
/*
* Copyright (c) 2014, Kenneth MacKay
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../include/tinycrypt/constants.h"
#include "../include/tinycrypt/ecc.h"
#include "../include/tinycrypt/ecc_dh.h"
#include <string.h>
#if default_RNG_defined
static uECC_RNG_Function g_rng_function = &default_CSPRNG;
#else
static uECC_RNG_Function g_rng_function = 0;
#endif
int uECC_make_key_with_d(uint8_t *public_key, uint8_t *private_key,
unsigned int *d, uECC_Curve curve)
{
uECC_word_t _private[NUM_ECC_WORDS];
uECC_word_t _public[NUM_ECC_WORDS * 2];
/* This function is designed for test purposes-only (such as validating NIST
* test vectors) as it uses a provided value for d instead of generating
* it uniformly at random. */
memcpy (_private, d, NUM_ECC_BYTES);
/* Computing public-key from private: */
if (EccPoint_compute_public_key(_public, _private, curve)) {
/* Converting buffers to correct bit order: */
uECC_vli_nativeToBytes(private_key,
BITS_TO_BYTES(curve->num_n_bits),
_private);
uECC_vli_nativeToBytes(public_key,
curve->num_bytes,
_public);
uECC_vli_nativeToBytes(public_key + curve->num_bytes,
curve->num_bytes,
_public + curve->num_words);
/* erasing temporary buffer used to store secret: */
memset(_private, 0, NUM_ECC_BYTES);
return 1;
}
return 0;
}
int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve)
{
uECC_word_t _random[NUM_ECC_WORDS * 2];
uECC_word_t _private[NUM_ECC_WORDS];
uECC_word_t _public[NUM_ECC_WORDS * 2];
uECC_word_t tries;
for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
/* Generating _private uniformly at random: */
uECC_RNG_Function rng_function = uECC_get_rng();
if (!rng_function ||
!rng_function((uint8_t *)_random, 2 * NUM_ECC_WORDS*uECC_WORD_SIZE)) {
return 0;
}
/* computing modular reduction of _random (see FIPS 186.4 B.4.1): */
uECC_vli_mmod(_private, _random, curve->n, BITS_TO_WORDS(curve->num_n_bits));
/* Computing public-key from private: */
if (EccPoint_compute_public_key(_public, _private, curve)) {
/* Converting buffers to correct bit order: */
uECC_vli_nativeToBytes(private_key,
BITS_TO_BYTES(curve->num_n_bits),
_private);
uECC_vli_nativeToBytes(public_key,
curve->num_bytes,
_public);
uECC_vli_nativeToBytes(public_key + curve->num_bytes,
curve->num_bytes,
_public + curve->num_words);
/* erasing temporary buffer that stored secret: */
memset(_private, 0, NUM_ECC_BYTES);
return 1;
}
}
return 0;
}
int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key,
uint8_t *secret, uECC_Curve curve)
{
uECC_word_t _public[NUM_ECC_WORDS * 2];
uECC_word_t _private[NUM_ECC_WORDS];
uECC_word_t tmp[NUM_ECC_WORDS];
uECC_word_t *p2[2] = {_private, tmp};
uECC_word_t *initial_Z = 0;
uECC_word_t carry;
wordcount_t num_words = curve->num_words;
wordcount_t num_bytes = curve->num_bytes;
int r;
/* Converting buffers to correct bit order: */
uECC_vli_bytesToNative(_private,
private_key,
BITS_TO_BYTES(curve->num_n_bits));
uECC_vli_bytesToNative(_public,
public_key,
num_bytes);
uECC_vli_bytesToNative(_public + num_words,
public_key + num_bytes,
num_bytes);
/* Regularize the bitcount for the private key so that attackers cannot use a
* side channel attack to learn the number of leading zeros. */
carry = regularize_k(_private, _private, tmp, curve);
/* If an RNG function was specified, try to get a random initial Z value to
* improve protection against side-channel attacks. */
if (g_rng_function) {
if (!uECC_generate_random_int(p2[carry], curve->p, num_words)) {
r = 0;
goto clear_and_out;
}
initial_Z = p2[carry];
}
EccPoint_mult(_public, _public, p2[!carry], initial_Z, curve->num_n_bits + 1,
curve);
uECC_vli_nativeToBytes(secret, num_bytes, _public);
r = !EccPoint_isZero(_public, curve);
clear_and_out:
/* erasing temporary buffer used to store secret: */
memset(p2, 0, sizeof(p2));
__asm__ __volatile__("" :: "g"(p2) : "memory");
memset(tmp, 0, sizeof(tmp));
__asm__ __volatile__("" :: "g"(tmp) : "memory");
memset(_private, 0, sizeof(_private));
__asm__ __volatile__("" :: "g"(_private) : "memory");
return r;
}

View File

@@ -0,0 +1,295 @@
/* ec_dsa.c - TinyCrypt implementation of EC-DSA */
/* Copyright (c) 2014, Kenneth MacKay
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.*/
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../include/tinycrypt/constants.h"
#include "../include/tinycrypt/ecc.h"
#include "../include/tinycrypt/ecc_dsa.h"
#if default_RNG_defined
static uECC_RNG_Function g_rng_function = &default_CSPRNG;
#else
static uECC_RNG_Function g_rng_function = 0;
#endif
static void bits2int(uECC_word_t *native, const uint8_t *bits,
unsigned bits_size, uECC_Curve curve)
{
unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits);
unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits);
int shift;
uECC_word_t carry;
uECC_word_t *ptr;
if (bits_size > num_n_bytes) {
bits_size = num_n_bytes;
}
uECC_vli_clear(native, num_n_words);
uECC_vli_bytesToNative(native, bits, bits_size);
if (bits_size * 8 <= (unsigned)curve->num_n_bits) {
return;
}
shift = bits_size * 8 - curve->num_n_bits;
carry = 0;
ptr = native + num_n_words;
while (ptr-- > native) {
uECC_word_t temp = *ptr;
*ptr = (temp >> shift) | carry;
carry = temp << (uECC_WORD_BITS - shift);
}
/* Reduce mod curve_n */
if (uECC_vli_cmp_unsafe(curve->n, native, num_n_words) != 1) {
uECC_vli_sub(native, native, curve->n, num_n_words);
}
}
int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash,
unsigned hash_size, uECC_word_t *k, uint8_t *signature,
uECC_Curve curve)
{
uECC_word_t tmp[NUM_ECC_WORDS];
uECC_word_t s[NUM_ECC_WORDS];
uECC_word_t *k2[2] = {tmp, s};
uECC_word_t p[NUM_ECC_WORDS * 2];
uECC_word_t carry;
wordcount_t num_words = curve->num_words;
wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
bitcount_t num_n_bits = curve->num_n_bits;
/* Make sure 0 < k < curve_n */
if (uECC_vli_isZero(k, num_words) ||
uECC_vli_cmp(curve->n, k, num_n_words) != 1) {
return 0;
}
carry = regularize_k(k, tmp, s, curve);
EccPoint_mult(p, curve->G, k2[!carry], 0, num_n_bits + 1, curve);
if (uECC_vli_isZero(p, num_words)) {
return 0;
}
/* If an RNG function was specified, get a random number
to prevent side channel analysis of k. */
if (!g_rng_function) {
uECC_vli_clear(tmp, num_n_words);
tmp[0] = 1;
}
else if (!uECC_generate_random_int(tmp, curve->n, num_n_words)) {
return 0;
}
/* Prevent side channel analysis of uECC_vli_modInv() to determine
bits of k / the private key by premultiplying by a random number */
uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */
uECC_vli_modInv(k, k, curve->n, num_n_words); /* k = 1 / k' */
uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */
uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */
/* tmp = d: */
uECC_vli_bytesToNative(tmp, private_key, BITS_TO_BYTES(curve->num_n_bits));
s[num_n_words - 1] = 0;
uECC_vli_set(s, p, num_words);
uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */
bits2int(tmp, message_hash, hash_size, curve);
uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */
uECC_vli_modMult(s, s, k, curve->n, num_n_words); /* s = (e + r*d) / k */
if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) {
return 0;
}
uECC_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s);
return 1;
}
int uECC_sign(const uint8_t *private_key, const uint8_t *message_hash,
unsigned hash_size, uint8_t *signature, uECC_Curve curve)
{
uECC_word_t _random[2*NUM_ECC_WORDS];
uECC_word_t k[NUM_ECC_WORDS];
uECC_word_t tries;
for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
/* Generating _random uniformly at random: */
uECC_RNG_Function rng_function = uECC_get_rng();
if (!rng_function ||
!rng_function((uint8_t *)_random, 2*NUM_ECC_WORDS*uECC_WORD_SIZE)) {
return 0;
}
// computing k as modular reduction of _random (see FIPS 186.4 B.5.1):
uECC_vli_mmod(k, _random, curve->n, BITS_TO_WORDS(curve->num_n_bits));
if (uECC_sign_with_k(private_key, message_hash, hash_size, k, signature,
curve)) {
return 1;
}
}
return 0;
}
static bitcount_t smax(bitcount_t a, bitcount_t b)
{
return (a > b ? a : b);
}
int uECC_verify(const uint8_t *public_key, const uint8_t *message_hash,
unsigned hash_size, const uint8_t *signature,
uECC_Curve curve)
{
uECC_word_t u1[NUM_ECC_WORDS], u2[NUM_ECC_WORDS];
uECC_word_t z[NUM_ECC_WORDS];
uECC_word_t sum[NUM_ECC_WORDS * 2];
uECC_word_t rx[NUM_ECC_WORDS];
uECC_word_t ry[NUM_ECC_WORDS];
uECC_word_t tx[NUM_ECC_WORDS];
uECC_word_t ty[NUM_ECC_WORDS];
uECC_word_t tz[NUM_ECC_WORDS];
const uECC_word_t *points[4];
const uECC_word_t *point;
bitcount_t num_bits;
bitcount_t i;
uECC_word_t _public[NUM_ECC_WORDS * 2];
uECC_word_t r[NUM_ECC_WORDS], s[NUM_ECC_WORDS];
wordcount_t num_words = curve->num_words;
wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
rx[num_n_words - 1] = 0;
r[num_n_words - 1] = 0;
s[num_n_words - 1] = 0;
uECC_vli_bytesToNative(_public, public_key, curve->num_bytes);
uECC_vli_bytesToNative(_public + num_words, public_key + curve->num_bytes,
curve->num_bytes);
uECC_vli_bytesToNative(r, signature, curve->num_bytes);
uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes);
/* r, s must not be 0. */
if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) {
return 0;
}
/* r, s must be < n. */
if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 ||
uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) {
return 0;
}
/* Calculate u1 and u2. */
uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */
u1[num_n_words - 1] = 0;
bits2int(u1, message_hash, hash_size, curve);
uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */
uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */
/* Calculate sum = G + Q. */
uECC_vli_set(sum, _public, num_words);
uECC_vli_set(sum + num_words, _public + num_words, num_words);
uECC_vli_set(tx, curve->G, num_words);
uECC_vli_set(ty, curve->G + num_words, num_words);
uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */
XYcZ_add(tx, ty, sum, sum + num_words, curve);
uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */
apply_z(sum, sum + num_words, z, curve);
/* Use Shamir's trick to calculate u1*G + u2*Q */
points[0] = 0;
points[1] = curve->G;
points[2] = _public;
points[3] = sum;
num_bits = smax(uECC_vli_numBits(u1, num_n_words),
uECC_vli_numBits(u2, num_n_words));
point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) |
((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)];
uECC_vli_set(rx, point, num_words);
uECC_vli_set(ry, point + num_words, num_words);
uECC_vli_clear(z, num_words);
z[0] = 1;
for (i = num_bits - 2; i >= 0; --i) {
uECC_word_t index;
curve->double_jacobian(rx, ry, z, curve);
index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1);
point = points[index];
if (point) {
uECC_vli_set(tx, point, num_words);
uECC_vli_set(ty, point + num_words, num_words);
apply_z(tx, ty, z, curve);
uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */
XYcZ_add(tx, ty, rx, ry, curve);
uECC_vli_modMult_fast(z, z, tz, curve);
}
}
uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */
apply_z(rx, ry, z, curve);
/* v = x1 (mod n) */
if (uECC_vli_cmp_unsafe(curve->n, rx, num_n_words) != 1) {
uECC_vli_sub(rx, rx, curve->n, num_n_words);
}
/* Accept only if v == r. */
return (int)(uECC_vli_equal(rx, r, num_words) == 0);
}

View File

@@ -0,0 +1,105 @@
/* uECC_platform_specific.c - Implementation of platform specific functions*/
/* Copyright (c) 2014, Kenneth MacKay
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.*/
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* uECC_platform_specific.c -- Implementation of platform specific functions
*/
#if defined(unix) || defined(__linux__) || defined(__unix__) || \
defined(__unix) | (defined(__APPLE__) && defined(__MACH__)) || \
defined(uECC_POSIX)
/* Some POSIX-like system with /dev/urandom or /dev/random. */
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
int default_CSPRNG(uint8_t *dest, unsigned int size) {
/* input sanity check: */
if (dest == (uint8_t *) 0 || (size <= 0))
return 0;
int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
if (fd == -1) {
fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
if (fd == -1) {
return 0;
}
}
char *ptr = (char *)dest;
size_t left = (size_t) size;
while (left > 0) {
ssize_t bytes_read = read(fd, ptr, left);
if (bytes_read <= 0) { // read failed
close(fd);
return 0;
}
left -= bytes_read;
ptr += bytes_read;
}
close(fd);
return 1;
}
#endif /* platform */

View File

@@ -0,0 +1,148 @@
/* hmac.c - TinyCrypt implementation of the HMAC algorithm */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../include/tinycrypt/hmac.h"
#include "../include/tinycrypt/constants.h"
#include "../include/tinycrypt/utils.h"
static void rekey(uint8_t *key, const uint8_t *new_key, unsigned int key_size)
{
const uint8_t inner_pad = (uint8_t) 0x36;
const uint8_t outer_pad = (uint8_t) 0x5c;
unsigned int i;
for (i = 0; i < key_size; ++i) {
key[i] = inner_pad ^ new_key[i];
key[i + TC_SHA256_BLOCK_SIZE] = outer_pad ^ new_key[i];
}
for (; i < TC_SHA256_BLOCK_SIZE; ++i) {
key[i] = inner_pad; key[i + TC_SHA256_BLOCK_SIZE] = outer_pad;
}
}
int tc_hmac_set_key(TCHmacState_t ctx, const uint8_t *key,
unsigned int key_size)
{
/* input sanity check: */
if (ctx == (TCHmacState_t) 0 ||
key == (const uint8_t *) 0 ||
key_size == 0) {
return TC_CRYPTO_FAIL;
}
const uint8_t dummy_key[key_size];
struct tc_hmac_state_struct dummy_state;
if (key_size <= TC_SHA256_BLOCK_SIZE) {
/*
* The next three lines consist of dummy calls just to avoid
* certain timing attacks. Without these dummy calls,
* adversaries would be able to learn whether the key_size is
* greater than TC_SHA256_BLOCK_SIZE by measuring the time
* consumed in this process.
*/
(void)tc_sha256_init(&dummy_state.hash_state);
(void)tc_sha256_update(&dummy_state.hash_state,
dummy_key,
key_size);
(void)tc_sha256_final(&dummy_state.key[TC_SHA256_DIGEST_SIZE],
&dummy_state.hash_state);
/* Actual code for when key_size <= TC_SHA256_BLOCK_SIZE: */
rekey(ctx->key, key, key_size);
} else {
(void)tc_sha256_init(&ctx->hash_state);
(void)tc_sha256_update(&ctx->hash_state, key, key_size);
(void)tc_sha256_final(&ctx->key[TC_SHA256_DIGEST_SIZE],
&ctx->hash_state);
rekey(ctx->key,
&ctx->key[TC_SHA256_DIGEST_SIZE],
TC_SHA256_DIGEST_SIZE);
}
return TC_CRYPTO_SUCCESS;
}
int tc_hmac_init(TCHmacState_t ctx)
{
/* input sanity check: */
if (ctx == (TCHmacState_t) 0) {
return TC_CRYPTO_FAIL;
}
(void) tc_sha256_init(&ctx->hash_state);
(void) tc_sha256_update(&ctx->hash_state, ctx->key, TC_SHA256_BLOCK_SIZE);
return TC_CRYPTO_SUCCESS;
}
int tc_hmac_update(TCHmacState_t ctx,
const void *data,
unsigned int data_length)
{
/* input sanity check: */
if (ctx == (TCHmacState_t) 0) {
return TC_CRYPTO_FAIL;
}
(void)tc_sha256_update(&ctx->hash_state, data, data_length);
return TC_CRYPTO_SUCCESS;
}
int tc_hmac_final(uint8_t *tag, unsigned int taglen, TCHmacState_t ctx)
{
/* input sanity check: */
if (tag == (uint8_t *) 0 ||
taglen != TC_SHA256_DIGEST_SIZE ||
ctx == (TCHmacState_t) 0) {
return TC_CRYPTO_FAIL;
}
(void) tc_sha256_final(tag, &ctx->hash_state);
(void)tc_sha256_init(&ctx->hash_state);
(void)tc_sha256_update(&ctx->hash_state,
&ctx->key[TC_SHA256_BLOCK_SIZE],
TC_SHA256_BLOCK_SIZE);
(void)tc_sha256_update(&ctx->hash_state, tag, TC_SHA256_DIGEST_SIZE);
(void)tc_sha256_final(tag, &ctx->hash_state);
/* destroy the current state */
_set(ctx, 0, sizeof(*ctx));
return TC_CRYPTO_SUCCESS;
}

View File

@@ -0,0 +1,212 @@
/* hmac_prng.c - TinyCrypt implementation of HMAC-PRNG */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../include/tinycrypt/hmac_prng.h"
#include "../include/tinycrypt/hmac.h"
#include "../include/tinycrypt/constants.h"
#include "../include/tinycrypt/utils.h"
/*
* min bytes in the seed string.
* MIN_SLEN*8 must be at least the expected security level.
*/
static const unsigned int MIN_SLEN = 32;
/*
* max bytes in the seed string;
* SP800-90A specifies a maximum of 2^35 bits (i.e., 2^32 bytes).
*/
static const unsigned int MAX_SLEN = UINT32_MAX;
/*
* max bytes in the personalization string;
* SP800-90A specifies a maximum of 2^35 bits (i.e., 2^32 bytes).
*/
static const unsigned int MAX_PLEN = UINT32_MAX;
/*
* max bytes in the additional_info string;
* SP800-90A specifies a maximum of 2^35 bits (i.e., 2^32 bytes).
*/
static const unsigned int MAX_ALEN = UINT32_MAX;
/*
* max number of generates between re-seeds;
* TinyCrypt accepts up to (2^32 - 1) which is the maximal value of
* a 32-bit unsigned int variable, while SP800-90A specifies a maximum of 2^48.
*/
static const unsigned int MAX_GENS = UINT32_MAX;
/*
* maximum bytes per generate call;
* SP800-90A specifies a maximum up to 2^19.
*/
static const unsigned int MAX_OUT = (1 << 19);
/*
* Assumes: prng != NULL, e != NULL, len >= 0.
*/
static void update(TCHmacPrng_t prng, const uint8_t *e, unsigned int len)
{
const uint8_t separator0 = 0x00;
const uint8_t separator1 = 0x01;
/* use current state, e and separator 0 to compute a new prng key: */
(void)tc_hmac_init(&prng->h);
(void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v));
(void)tc_hmac_update(&prng->h, &separator0, sizeof(separator0));
(void)tc_hmac_update(&prng->h, e, len);
(void)tc_hmac_final(prng->key, sizeof(prng->key), &prng->h);
/* configure the new prng key into the prng's instance of hmac */
(void)tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key));
/* use the new key to compute a new state variable v */
(void)tc_hmac_init(&prng->h);
(void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v));
(void)tc_hmac_final(prng->v, sizeof(prng->v), &prng->h);
/* use current state, e and separator 1 to compute a new prng key: */
(void)tc_hmac_init(&prng->h);
(void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v));
(void)tc_hmac_update(&prng->h, &separator1, sizeof(separator1));
(void)tc_hmac_update(&prng->h, e, len);
(void)tc_hmac_final(prng->key, sizeof(prng->key), &prng->h);
/* configure the new prng key into the prng's instance of hmac */
(void)tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key));
/* use the new key to compute a new state variable v */
(void)tc_hmac_init(&prng->h);
(void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v));
(void)tc_hmac_final(prng->v, sizeof(prng->v), &prng->h);
}
int tc_hmac_prng_init(TCHmacPrng_t prng,
const uint8_t *personalization,
unsigned int plen)
{
/* input sanity check: */
if (prng == (TCHmacPrng_t) 0 ||
personalization == (uint8_t *) 0 ||
plen > MAX_PLEN) {
return TC_CRYPTO_FAIL;
}
/* put the generator into a known state: */
_set(prng->key, 0x00, sizeof(prng->key));
_set(prng->v, 0x01, sizeof(prng->v));
tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key));
/* update assumes SOME key has been configured into HMAC */
update(prng, personalization, plen);
/* force a reseed before allowing tc_hmac_prng_generate to succeed: */
prng->countdown = 0;
return TC_CRYPTO_SUCCESS;
}
int tc_hmac_prng_reseed(TCHmacPrng_t prng,
const uint8_t *seed,
unsigned int seedlen,
const uint8_t *additional_input,
unsigned int additionallen)
{
/* input sanity check: */
if (prng == (TCHmacPrng_t) 0 ||
seed == (const uint8_t *) 0 ||
seedlen < MIN_SLEN ||
seedlen > MAX_SLEN) {
return TC_CRYPTO_FAIL;
}
if (additional_input != (const uint8_t *) 0) {
/*
* Abort if additional_input is provided but has inappropriate
* length
*/
if (additionallen == 0 ||
additionallen > MAX_ALEN) {
return TC_CRYPTO_FAIL;
} else {
/* call update for the seed and additional_input */
update(prng, seed, seedlen);
update(prng, additional_input, additionallen);
}
} else {
/* call update only for the seed */
update(prng, seed, seedlen);
}
/* ... and enable hmac_prng_generate */
prng->countdown = MAX_GENS;
return TC_CRYPTO_SUCCESS;
}
int tc_hmac_prng_generate(uint8_t *out, unsigned int outlen, TCHmacPrng_t prng)
{
unsigned int bufferlen;
/* input sanity check: */
if (out == (uint8_t *) 0 ||
prng == (TCHmacPrng_t) 0 ||
outlen == 0 ||
outlen > MAX_OUT) {
return TC_CRYPTO_FAIL;
} else if (prng->countdown == 0) {
return TC_HMAC_PRNG_RESEED_REQ;
}
prng->countdown--;
while (outlen != 0) {
/* operate HMAC in OFB mode to create "random" outputs */
(void)tc_hmac_init(&prng->h);
(void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v));
(void)tc_hmac_final(prng->v, sizeof(prng->v), &prng->h);
bufferlen = (TC_SHA256_DIGEST_SIZE > outlen) ?
outlen : TC_SHA256_DIGEST_SIZE;
(void)_copy(out, bufferlen, prng->v, bufferlen);
out += bufferlen;
outlen = (outlen > TC_SHA256_DIGEST_SIZE) ?
(outlen - TC_SHA256_DIGEST_SIZE) : 0;
}
/* block future PRNG compromises from revealing past state */
update(prng, prng->v, TC_SHA256_DIGEST_SIZE);
return TC_CRYPTO_SUCCESS;
}

View File

@@ -0,0 +1,217 @@
/* sha256.c - TinyCrypt SHA-256 crypto hash algorithm implementation */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../include/tinycrypt/sha256.h"
#include "../include/tinycrypt/constants.h"
#include "../include/tinycrypt/utils.h"
static void compress(unsigned int *iv, const uint8_t *data);
int tc_sha256_init(TCSha256State_t s)
{
/* input sanity check: */
if (s == (TCSha256State_t) 0) {
return TC_CRYPTO_FAIL;
}
/*
* Setting the initial state values.
* These values correspond to the first 32 bits of the fractional parts
* of the square roots of the first 8 primes: 2, 3, 5, 7, 11, 13, 17
* and 19.
*/
_set((uint8_t *) s, 0x00, sizeof(*s));
s->iv[0] = 0x6a09e667;
s->iv[1] = 0xbb67ae85;
s->iv[2] = 0x3c6ef372;
s->iv[3] = 0xa54ff53a;
s->iv[4] = 0x510e527f;
s->iv[5] = 0x9b05688c;
s->iv[6] = 0x1f83d9ab;
s->iv[7] = 0x5be0cd19;
return TC_CRYPTO_SUCCESS;
}
int tc_sha256_update(TCSha256State_t s, const uint8_t *data, size_t datalen)
{
/* input sanity check: */
if (s == (TCSha256State_t) 0 ||
data == (void *) 0) {
return TC_CRYPTO_FAIL;
} else if (datalen == 0) {
return TC_CRYPTO_SUCCESS;
}
while (datalen-- > 0) {
s->leftover[s->leftover_offset++] = *(data++);
if (s->leftover_offset >= TC_SHA256_BLOCK_SIZE) {
compress(s->iv, s->leftover);
s->leftover_offset = 0;
s->bits_hashed += (TC_SHA256_BLOCK_SIZE << 3);
}
}
return TC_CRYPTO_SUCCESS;
}
int tc_sha256_final(uint8_t *digest, TCSha256State_t s)
{
unsigned int i;
/* input sanity check: */
if (digest == (uint8_t *) 0 ||
s == (TCSha256State_t) 0) {
return TC_CRYPTO_FAIL;
}
s->bits_hashed += (s->leftover_offset << 3);
s->leftover[s->leftover_offset++] = 0x80; /* always room for one byte */
if (s->leftover_offset > (sizeof(s->leftover) - 8)) {
/* there is not room for all the padding in this block */
_set(s->leftover + s->leftover_offset, 0x00,
sizeof(s->leftover) - s->leftover_offset);
compress(s->iv, s->leftover);
s->leftover_offset = 0;
}
/* add the padding and the length in big-Endian format */
_set(s->leftover + s->leftover_offset, 0x00,
sizeof(s->leftover) - 8 - s->leftover_offset);
s->leftover[sizeof(s->leftover) - 1] = (uint8_t)(s->bits_hashed);
s->leftover[sizeof(s->leftover) - 2] = (uint8_t)(s->bits_hashed >> 8);
s->leftover[sizeof(s->leftover) - 3] = (uint8_t)(s->bits_hashed >> 16);
s->leftover[sizeof(s->leftover) - 4] = (uint8_t)(s->bits_hashed >> 24);
s->leftover[sizeof(s->leftover) - 5] = (uint8_t)(s->bits_hashed >> 32);
s->leftover[sizeof(s->leftover) - 6] = (uint8_t)(s->bits_hashed >> 40);
s->leftover[sizeof(s->leftover) - 7] = (uint8_t)(s->bits_hashed >> 48);
s->leftover[sizeof(s->leftover) - 8] = (uint8_t)(s->bits_hashed >> 56);
/* hash the padding and length */
compress(s->iv, s->leftover);
/* copy the iv out to digest */
for (i = 0; i < TC_SHA256_STATE_BLOCKS; ++i) {
unsigned int t = *((unsigned int *) &s->iv[i]);
*digest++ = (uint8_t)(t >> 24);
*digest++ = (uint8_t)(t >> 16);
*digest++ = (uint8_t)(t >> 8);
*digest++ = (uint8_t)(t);
}
/* destroy the current state */
_set(s, 0, sizeof(*s));
return TC_CRYPTO_SUCCESS;
}
/*
* Initializing SHA-256 Hash constant words K.
* These values correspond to the first 32 bits of the fractional parts of the
* cube roots of the first 64 primes between 2 and 311.
*/
static const unsigned int k256[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
static inline unsigned int ROTR(unsigned int a, unsigned int n)
{
return (((a) >> n) | ((a) << (32 - n)));
}
#define Sigma0(a)(ROTR((a), 2) ^ ROTR((a), 13) ^ ROTR((a), 22))
#define Sigma1(a)(ROTR((a), 6) ^ ROTR((a), 11) ^ ROTR((a), 25))
#define sigma0(a)(ROTR((a), 7) ^ ROTR((a), 18) ^ ((a) >> 3))
#define sigma1(a)(ROTR((a), 17) ^ ROTR((a), 19) ^ ((a) >> 10))
#define Ch(a, b, c)(((a) & (b)) ^ ((~(a)) & (c)))
#define Maj(a, b, c)(((a) & (b)) ^ ((a) & (c)) ^ ((b) & (c)))
static inline unsigned int BigEndian(const uint8_t **c)
{
unsigned int n = 0;
n = (((unsigned int)(*((*c)++))) << 24);
n |= ((unsigned int)(*((*c)++)) << 16);
n |= ((unsigned int)(*((*c)++)) << 8);
n |= ((unsigned int)(*((*c)++)));
return n;
}
static void compress(unsigned int *iv, const uint8_t *data)
{
unsigned int a, b, c, d, e, f, g, h;
unsigned int s0, s1;
unsigned int t1, t2;
unsigned int work_space[16];
unsigned int n;
unsigned int i;
a = iv[0]; b = iv[1]; c = iv[2]; d = iv[3];
e = iv[4]; f = iv[5]; g = iv[6]; h = iv[7];
for (i = 0; i < 16; ++i) {
n = BigEndian(&data);
t1 = work_space[i] = n;
t1 += h + Sigma1(e) + Ch(e, f, g) + k256[i];
t2 = Sigma0(a) + Maj(a, b, c);
h = g; g = f; f = e; e = d + t1;
d = c; c = b; b = a; a = t1 + t2;
}
for ( ; i < 64; ++i) {
s0 = work_space[(i+1)&0x0f];
s0 = sigma0(s0);
s1 = work_space[(i+14)&0x0f];
s1 = sigma1(s1);
t1 = work_space[i&0xf] += s0 + s1 + work_space[(i+9)&0xf];
t1 += h + Sigma1(e) + Ch(e, f, g) + k256[i];
t2 = Sigma0(a) + Maj(a, b, c);
h = g; g = f; f = e; e = d + t1;
d = c; c = b; b = a; a = t1 + t2;
}
iv[0] += a; iv[1] += b; iv[2] += c; iv[3] += d;
iv[4] += e; iv[5] += f; iv[6] += g; iv[7] += h;
}

View File

@@ -0,0 +1,74 @@
/* utils.c - TinyCrypt platform-dependent run-time operations */
/*
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../include/tinycrypt/utils.h"
#include "../include/tinycrypt/constants.h"
#include <string.h>
#define MASK_TWENTY_SEVEN 0x1b
unsigned int _copy(uint8_t *to, unsigned int to_len,
const uint8_t *from, unsigned int from_len)
{
if (from_len <= to_len) {
(void)memcpy(to, from, from_len);
return from_len;
} else {
return TC_CRYPTO_FAIL;
}
}
void _set(void *to, uint8_t val, unsigned int len)
{
(void)memset(to, val, len);
}
/*
* Doubles the value of a byte for values up to 127.
*/
uint8_t _double_byte(uint8_t a)
{
return ((a<<1) ^ ((a>>7) * MASK_TWENTY_SEVEN));
}
int _compare(const uint8_t *a, const uint8_t *b, size_t size)
{
const uint8_t *tempa = a;
const uint8_t *tempb = b;
uint8_t result = 0;
for (unsigned int i = 0; i < size; i++) {
result |= tempa[i] ^ tempb[i];
}
return result;
}

View File

@@ -0,0 +1,116 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_HW_
#define H_BLE_HW_
#ifdef __cplusplus
extern "C" {
#endif
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#if defined(ARCH_sim)
#define BLE_USES_HW_WHITELIST (0)
#else
#define BLE_USES_HW_WHITELIST MYNEWT_VAL(BLE_HW_WHITELIST_ENABLE)
#endif
/* Returns the number of hw whitelist elements */
uint8_t ble_hw_whitelist_size(void);
/* Clear the whitelist */
void ble_hw_whitelist_clear(void);
/* Remove a device from the hw whitelist */
void ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type);
/* Add a device to the hw whitelist */
int ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type);
/* Enable hw whitelisting */
void ble_hw_whitelist_enable(void);
/* Enable hw whitelisting */
void ble_hw_whitelist_disable(void);
/* Boolean function returning true if address matches a whitelist entry */
int ble_hw_whitelist_match(void);
/* Encrypt data */
struct ble_encryption_block;
int ble_hw_encrypt_block(struct ble_encryption_block *ecb);
/* Random number generation */
typedef void (*ble_rng_isr_cb_t)(uint8_t rnum);
int ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias);
/**
* Start the random number generator
*
* @return int
*/
int ble_hw_rng_start(void);
/**
* Stop the random generator
*
* @return int
*/
int ble_hw_rng_stop(void);
/**
* Read the random number generator.
*
* @return uint8_t
*/
uint8_t ble_hw_rng_read(void);
/* Clear the resolving list*/
void ble_hw_resolv_list_clear(void);
/* Add a device to the hw resolving list */
int ble_hw_resolv_list_add(uint8_t *irk);
/* Remove a device from the hw resolving list */
void ble_hw_resolv_list_rmv(int index);
/* Returns the size of the whitelist in HW */
uint8_t ble_hw_resolv_list_size(void);
/* Enable the resolving list */
void ble_hw_resolv_list_enable(void);
/* Disables resolving list devices */
void ble_hw_resolv_list_disable(void);
/* Returns index of resolved address; -1 if not resolved */
int ble_hw_resolv_list_match(void);
/* Returns public device address or -1 if not present */
int ble_hw_get_public_addr(ble_addr_t *addr);
/* Returns random static address or -1 if not present */
int ble_hw_get_static_addr(ble_addr_t *addr);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_HW_ */

View File

@@ -0,0 +1,584 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_
#define H_BLE_LL_
#include "nimble/porting/nimble/include/stats/stats.h"
#include "nimble/porting/nimble/include/os/os_cputime.h"
#include "nimble/nimble/include/nimble/nimble_opt.h"
#include "nimble/nimble/include/nimble/nimble_npl.h"
#include "ble_phy.h"
#ifdef MYNEWT
#include "./ble_ll_ctrl.h"
#include "hal/hal_system.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768
#error 32.768kHz clock required
#endif
#if defined(MYNEWT) && MYNEWT_VAL(BLE_LL_VND_EVENT_ON_ASSERT)
#ifdef NDEBUG
#define BLE_LL_ASSERT(cond) (void(0))
#else
#define BLE_LL_ASSERT(cond) \
if (!(cond)) { \
if (hal_debugger_connected()) { \
assert(0);\
} else {\
ble_ll_hci_ev_send_vendor_err(__FILE__, __LINE__); \
while(1) {}\
}\
}
#endif
#else
#define BLE_LL_ASSERT(cond) assert(cond)
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
#define BLE_LL_BT5_PHY_SUPPORTED (1)
#else
#define BLE_LL_BT5_PHY_SUPPORTED (0)
#endif
/* Controller revision. */
#define BLE_LL_SUB_VERS_NR (0x0000)
/* Timing jitter as per spec is +/16 usecs */
#define BLE_LL_JITTER_USECS (16)
/* Packet queue header definition */
STAILQ_HEAD(ble_ll_pkt_q, os_mbuf_pkthdr);
/*
* Global Link Layer data object. There is only one Link Layer data object
* per controller although there may be many instances of the link layer state
* machine running.
*/
struct ble_ll_obj
{
/* Supported features */
uint64_t ll_supp_features;
/* Current Link Layer state */
uint8_t ll_state;
/* Number of ACL data packets supported */
uint8_t ll_num_acl_pkts;
/* ACL data packet size */
uint16_t ll_acl_pkt_size;
/* Preferred PHY's */
uint8_t ll_pref_tx_phys;
uint8_t ll_pref_rx_phys;
/* Task event queue */
struct ble_npl_eventq ll_evq;
/* Wait for response timer */
struct hal_timer ll_wfr_timer;
/* Packet receive queue (and event). Holds received packets from PHY */
struct ble_npl_event ll_rx_pkt_ev;
struct ble_ll_pkt_q ll_rx_pkt_q;
/* Packet transmit queue */
struct ble_npl_event ll_tx_pkt_ev;
struct ble_ll_pkt_q ll_tx_pkt_q;
/* Data buffer overflow event */
struct ble_npl_event ll_dbuf_overflow_ev;
/* Number of completed packets event */
struct ble_npl_event ll_comp_pkt_ev;
/* HW error callout */
struct ble_npl_callout ll_hw_err_timer;
};
extern struct ble_ll_obj g_ble_ll_data;
/* Link layer statistics */
STATS_SECT_START(ble_ll_stats)
STATS_SECT_ENTRY(hci_cmds)
STATS_SECT_ENTRY(hci_cmd_errs)
STATS_SECT_ENTRY(hci_events_sent)
STATS_SECT_ENTRY(bad_ll_state)
STATS_SECT_ENTRY(bad_acl_hdr)
STATS_SECT_ENTRY(no_bufs)
STATS_SECT_ENTRY(rx_adv_pdu_crc_ok)
STATS_SECT_ENTRY(rx_adv_pdu_crc_err)
STATS_SECT_ENTRY(rx_adv_bytes_crc_ok)
STATS_SECT_ENTRY(rx_adv_bytes_crc_err)
STATS_SECT_ENTRY(rx_data_pdu_crc_ok)
STATS_SECT_ENTRY(rx_data_pdu_crc_err)
STATS_SECT_ENTRY(rx_data_bytes_crc_ok)
STATS_SECT_ENTRY(rx_data_bytes_crc_err)
STATS_SECT_ENTRY(rx_adv_malformed_pkts)
STATS_SECT_ENTRY(rx_adv_ind)
STATS_SECT_ENTRY(rx_adv_direct_ind)
STATS_SECT_ENTRY(rx_adv_nonconn_ind)
STATS_SECT_ENTRY(rx_adv_ext_ind)
STATS_SECT_ENTRY(rx_scan_reqs)
STATS_SECT_ENTRY(rx_scan_rsps)
STATS_SECT_ENTRY(rx_connect_reqs)
STATS_SECT_ENTRY(rx_scan_ind)
STATS_SECT_ENTRY(rx_aux_connect_rsp)
STATS_SECT_ENTRY(adv_txg)
STATS_SECT_ENTRY(adv_late_starts)
STATS_SECT_ENTRY(adv_resched_pdu_fail)
STATS_SECT_ENTRY(adv_drop_event)
STATS_SECT_ENTRY(sched_state_conn_errs)
STATS_SECT_ENTRY(sched_state_adv_errs)
STATS_SECT_ENTRY(scan_starts)
STATS_SECT_ENTRY(scan_stops)
STATS_SECT_ENTRY(scan_req_txf)
STATS_SECT_ENTRY(scan_req_txg)
STATS_SECT_ENTRY(scan_rsp_txg)
STATS_SECT_ENTRY(aux_missed_adv)
STATS_SECT_ENTRY(aux_scheduled)
STATS_SECT_ENTRY(aux_received)
STATS_SECT_ENTRY(aux_fired_for_read)
STATS_SECT_ENTRY(aux_allocated)
STATS_SECT_ENTRY(aux_freed)
STATS_SECT_ENTRY(aux_sched_cb)
STATS_SECT_ENTRY(aux_conn_req_tx)
STATS_SECT_ENTRY(aux_conn_rsp_tx)
STATS_SECT_ENTRY(aux_conn_rsp_err)
STATS_SECT_ENTRY(aux_scan_req_tx)
STATS_SECT_ENTRY(aux_scan_rsp_err)
STATS_SECT_ENTRY(aux_chain_cnt)
STATS_SECT_ENTRY(aux_chain_err)
STATS_SECT_ENTRY(aux_scan_drop)
STATS_SECT_ENTRY(adv_evt_dropped)
STATS_SECT_ENTRY(scan_timer_stopped)
STATS_SECT_ENTRY(scan_timer_restarted)
STATS_SECT_ENTRY(periodic_adv_drop_event)
STATS_SECT_ENTRY(periodic_chain_drop_event)
STATS_SECT_ENTRY(sync_event_failed)
STATS_SECT_ENTRY(sync_received)
STATS_SECT_ENTRY(sync_chain_failed)
STATS_SECT_ENTRY(sync_missed_err)
STATS_SECT_ENTRY(sync_crc_err)
STATS_SECT_ENTRY(sync_rx_buf_err)
STATS_SECT_ENTRY(sync_scheduled)
STATS_SECT_ENTRY(sched_state_sync_errs)
STATS_SECT_ENTRY(sched_invalid_pdu)
STATS_SECT_END
extern STATS_SECT_DECL(ble_ll_stats) ble_ll_stats;
/* States */
#define BLE_LL_STATE_STANDBY (0)
#define BLE_LL_STATE_ADV (1)
#define BLE_LL_STATE_SCANNING (2)
#define BLE_LL_STATE_INITIATING (3)
#define BLE_LL_STATE_CONNECTION (4)
#define BLE_LL_STATE_DTM (5)
#define BLE_LL_STATE_SYNC (6)
/* LL Features */
#define BLE_LL_FEAT_LE_ENCRYPTION (0x0000000001)
#define BLE_LL_FEAT_CONN_PARM_REQ (0x0000000002)
#define BLE_LL_FEAT_EXTENDED_REJ (0x0000000004)
#define BLE_LL_FEAT_SLAVE_INIT (0x0000000008)
#define BLE_LL_FEAT_LE_PING (0x0000000010)
#define BLE_LL_FEAT_DATA_LEN_EXT (0x0000000020)
#define BLE_LL_FEAT_LL_PRIVACY (0x0000000040)
#define BLE_LL_FEAT_EXT_SCAN_FILT (0x0000000080)
#define BLE_LL_FEAT_LE_2M_PHY (0x0000000100)
#define BLE_LL_FEAT_STABLE_MOD_ID_TX (0x0000000200)
#define BLE_LL_FEAT_STABLE_MOD_ID_RX (0x0000000400)
#define BLE_LL_FEAT_LE_CODED_PHY (0x0000000800)
#define BLE_LL_FEAT_EXT_ADV (0x0000001000)
#define BLE_LL_FEAT_PERIODIC_ADV (0x0000002000)
#define BLE_LL_FEAT_CSA2 (0x0000004000)
#define BLE_LL_FEAT_LE_POWER_CLASS_1 (0x0000008000)
#define BLE_LL_FEAT_MIN_USED_CHAN (0x0000010000)
#define BLE_LL_FEAT_CTE_REQ (0x0000020000)
#define BLE_LL_FEAT_CTE_RSP (0x0000040000)
#define BLE_LL_FEAT_CTE_TX (0x0000080000)
#define BLE_LL_FEAT_CTE_RX (0x0000100000)
#define BLE_LL_FEAT_CTE_AOD (0x0000200000)
#define BLE_LL_FEAT_CTE_AOA (0x0000400000)
#define BLE_LL_FEAT_CTE_RECV (0x0000800000)
#define BLE_LL_FEAT_SYNC_TRANS_SEND (0x0001000000)
#define BLE_LL_FEAT_SYNC_TRANS_RECV (0x0002000000)
#define BLE_LL_FEAT_SCA_UPDATE (0x0004000000)
#define BLE_LL_FEAT_REM_PKEY (0x0008000000)
#define BLE_LL_FEAT_CIS_MASTER (0x0010000000)
#define BLE_LL_FEAT_CIS_SLAVE (0x0020000000)
#define BLE_LL_FEAT_ISO_BROADCASTER (0x0040000000)
#define BLE_LL_FEAT_SYNC_RECV (0x0080000000)
#define BLE_LL_FEAT_ISO_HOST_SUPPORT (0x0100000000)
#define BLE_LL_FEAT_POWER_CTRL_REQ (0x0200000000)
#define BLE_LL_FEAT_POWER_CHANGE_IND (0x0400000000)
#define BLE_LL_FEAT_PATH_LOSS_MON (0x0800000000)
/* This is initial mask, so if feature exchange will not happen,
* but host will want to use this procedure, we will try. If not
* succeed, feature bit will be cleared.
* Look at LL Features above to find out what is allowed
*/
#define BLE_LL_CONN_INITIAL_FEATURES (0x00000022)
#define BLE_LL_CONN_CLEAR_FEATURE(connsm, feature) (connsm->conn_features &= ~(feature))
/* All the features which can be controlled by the Host */
#define BLE_LL_HOST_CONTROLLED_FEATURES (BLE_LL_FEAT_ISO_HOST_SUPPORT)
/* LL timing */
#define BLE_LL_IFS (150) /* usecs */
#define BLE_LL_MAFS (300) /* usecs */
/*
* BLE LL device address. Note that element 0 of the array is the LSB and
* is sent over the air first. Byte 5 is the MSB and is the last one sent over
* the air.
*/
#define BLE_DEV_ADDR_LEN (6) /* bytes */
struct ble_dev_addr
{
uint8_t u8[BLE_DEV_ADDR_LEN];
};
#define BLE_IS_DEV_ADDR_STATIC(addr) ((addr->u8[5] & 0xc0) == 0xc0)
#define BLE_IS_DEV_ADDR_RESOLVABLE(addr) ((addr->u8[5] & 0xc0) == 0x40)
#define BLE_IS_DEV_ADDR_UNRESOLVABLE(addr) ((addr->u8[5] & 0xc0) == 0x00)
/*
* LL packet format
*
* -> Preamble (1/2 bytes)
* -> Access Address (4 bytes)
* -> PDU (2 to 257 octets)
* -> CRC (3 bytes)
*/
#define BLE_LL_PREAMBLE_LEN (1)
#define BLE_LL_ACC_ADDR_LEN (4)
#define BLE_LL_CRC_LEN (3)
#define BLE_LL_PDU_HDR_LEN (2)
#define BLE_LL_MAX_PAYLOAD_LEN (255)
#define BLE_LL_MIN_PDU_LEN (BLE_LL_PDU_HDR_LEN)
#define BLE_LL_MAX_PDU_LEN ((BLE_LL_PDU_HDR_LEN) + (BLE_LL_MAX_PAYLOAD_LEN))
#define BLE_LL_CRCINIT_ADV (0x555555)
/* Access address for advertising channels */
#define BLE_ACCESS_ADDR_ADV (0x8E89BED6)
/*
* Advertising PDU format:
* -> 2 byte header
* -> LSB contains pdu type, txadd and rxadd bits.
* -> MSB contains length (6 bits). Length is length of payload. Does
* not include the header length itself.
* -> Payload (max 37 bytes)
*/
#define BLE_ADV_PDU_HDR_TYPE_MASK (0x0F)
#define BLE_ADV_PDU_HDR_CHSEL_MASK (0x20)
#define BLE_ADV_PDU_HDR_TXADD_MASK (0x40)
#define BLE_ADV_PDU_HDR_RXADD_MASK (0x80)
/* Advertising channel PDU types */
#define BLE_ADV_PDU_TYPE_ADV_IND (0)
#define BLE_ADV_PDU_TYPE_ADV_DIRECT_IND (1)
#define BLE_ADV_PDU_TYPE_ADV_NONCONN_IND (2)
#define BLE_ADV_PDU_TYPE_SCAN_REQ (3)
#define BLE_ADV_PDU_TYPE_SCAN_RSP (4)
#define BLE_ADV_PDU_TYPE_CONNECT_IND (5)
#define BLE_ADV_PDU_TYPE_ADV_SCAN_IND (6)
#define BLE_ADV_PDU_TYPE_ADV_EXT_IND (7)
#define BLE_ADV_PDU_TYPE_AUX_ADV_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND
#define BLE_ADV_PDU_TYPE_AUX_SCAN_RSP BLE_ADV_PDU_TYPE_ADV_EXT_IND
#define BLE_ADV_PDU_TYPE_AUX_SYNC_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND
#define BLE_ADV_PDU_TYPE_AUX_CHAIN_IND BLE_ADV_PDU_TYPE_ADV_EXT_IND
#define BLE_ADV_PDU_TYPE_AUX_CONNECT_REQ BLE_ADV_PDU_TYPE_CONNECT_IND
#define BLE_ADV_PDU_TYPE_AUX_SCAN_REQ BLE_ADV_PDU_TYPE_SCAN_REQ
#define BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP (8)
/* Extended Header Length (6b) + AdvMode (2b) */
#define BLE_LL_EXT_ADV_HDR_LEN (1)
#define BLE_LL_EXT_ADV_ADVA_BIT (0)
#define BLE_LL_EXT_ADV_TARGETA_BIT (1)
#define BLE_LL_EXT_ADV_CTE_INFO_BIT (2)
#define BLE_LL_EXT_ADV_DATA_INFO_BIT (3)
#define BLE_LL_EXT_ADV_AUX_PTR_BIT (4)
#define BLE_LL_EXT_ADV_SYNC_INFO_BIT (5)
#define BLE_LL_EXT_ADV_TX_POWER_BIT (6)
#define BLE_LL_EXT_ADV_FLAGS_SIZE (1)
#define BLE_LL_EXT_ADV_ADVA_SIZE (6)
#define BLE_LL_EXT_ADV_TARGETA_SIZE (6)
#define BLE_LL_EXT_ADV_DATA_INFO_SIZE (2)
#define BLE_LL_EXT_ADV_AUX_PTR_SIZE (3)
#define BLE_LL_EXT_ADV_SYNC_INFO_SIZE (18)
#define BLE_LL_EXT_ADV_TX_POWER_SIZE (1)
#define BLE_LL_EXT_ADV_MODE_NON_CONN (0x00)
#define BLE_LL_EXT_ADV_MODE_CONN (0x01)
#define BLE_LL_EXT_ADV_MODE_SCAN (0x02)
/* If Channel Selection Algorithm #2 is supported */
#define BLE_ADV_PDU_HDR_CHSEL (0x20)
/*
* TxAdd and RxAdd bit definitions. A 0 is a public address; a 1 is a
* random address.
*/
#define BLE_ADV_PDU_HDR_TXADD_RAND (0x40)
#define BLE_ADV_PDU_HDR_RXADD_RAND (0x80)
/*
* Data Channel format
*
* -> Header (2 bytes)
* -> LSB contains llid, nesn, sn and md
* -> MSB contains length (8 bits)
* -> Payload (0 to 251)
* -> MIC (0 or 4 bytes)
*/
#define BLE_LL_DATA_HDR_LLID_MASK (0x03)
#define BLE_LL_DATA_HDR_NESN_MASK (0x04)
#define BLE_LL_DATA_HDR_SN_MASK (0x08)
#define BLE_LL_DATA_HDR_MD_MASK (0x10)
#define BLE_LL_DATA_HDR_RSRVD_MASK (0xE0)
#define BLE_LL_DATA_PDU_MAX_PYLD (251)
#define BLE_LL_DATA_MIC_LEN (4)
/* LLID definitions */
#define BLE_LL_LLID_RSRVD (0)
#define BLE_LL_LLID_DATA_FRAG (1)
#define BLE_LL_LLID_DATA_START (2)
#define BLE_LL_LLID_CTRL (3)
/*
* CONNECT_REQ
* -> InitA (6 bytes)
* -> AdvA (6 bytes)
* -> LLData (22 bytes)
* -> Access address (4 bytes)
* -> CRC initialize (3 bytes)
* -> WinSize (1 byte)
* -> WinOffset (2 bytes)
* -> Interval (2 bytes)
* -> Latency (2 bytes)
* -> Timeout (2 bytes)
* -> Channel Map (5 bytes)
* -> Hop Increment (5 bits)
* -> SCA (3 bits)
*
* InitA is the initiators public (TxAdd=0) or random (TxAdd=1) address.
* AdvaA is the advertisers public (RxAdd=0) or random (RxAdd=1) address.
* LLData contains connection request data.
* aa: Link Layer's access address
* crc_init: The CRC initialization value used for CRC calculation.
* winsize: The transmit window size = winsize * 1.25 msecs
* winoffset: The transmit window offset = winoffset * 1.25 msecs
* interval: The connection interval = interval * 1.25 msecs.
* latency: connection slave latency = latency
* timeout: Connection supervision timeout = timeout * 10 msecs.
* chanmap: contains channel mapping indicating used and unused data
* channels. Only bits that are 1 are usable. LSB is channel 0.
* hop_inc: Hop increment used for frequency hopping. Random value in
* range of 5 to 16.
*/
#define BLE_CONNECT_REQ_LEN (34)
#define BLE_CONNECT_REQ_PDU_LEN (BLE_CONNECT_REQ_LEN + BLE_LL_PDU_HDR_LEN)
#define BLE_SCAN_REQ_LEN (12)
#define BLE_SCAN_RSP_MAX_LEN (37)
#define BLE_SCAN_RSP_MAX_EXT_LEN (251)
#define BLE_LL_ADDR_SUBTYPE_IDENTITY (0)
#define BLE_LL_ADDR_SUBTYPE_RPA (1)
#define BLE_LL_ADDR_SUBTYPE_NRPA (2)
/*--- External API ---*/
/* Initialize the Link Layer */
void ble_ll_init(void);
/* Reset the Link Layer */
int ble_ll_reset(void);
int ble_ll_is_valid_public_addr(const uint8_t *addr);
/* 'Boolean' function returning true if address is a valid random address */
int ble_ll_is_valid_random_addr(const uint8_t *addr);
/*
* Check if given own_addr_type is valid for current controller configuration
* given the random address provided (when applicable)
*/
int ble_ll_is_valid_own_addr_type(uint8_t own_addr_type,
const uint8_t *random_addr);
/* Calculate the amount of time in microseconds a PDU with payload length of
* 'payload_len' will take to transmit on a PHY 'phy_mode'. */
uint32_t ble_ll_pdu_tx_time_get(uint16_t payload_len, int phy_mode);
/* Calculate maximum octets of PDU payload which can be transmitted during
* 'usecs' on a PHY 'phy_mode'. */
uint16_t ble_ll_pdu_max_tx_octets_get(uint32_t usecs, int phy_mode);
/* Is this address a resolvable private address? */
int ble_ll_is_rpa(const uint8_t *addr, uint8_t addr_type);
int ble_ll_addr_subtype(const uint8_t *addr, uint8_t addr_type);
/* Is this address an identity address? */
int ble_ll_addr_is_id(uint8_t *addr, uint8_t addr_type);
/* Is 'addr' our device address? 'addr_type' is public (0) or random (!=0) */
int ble_ll_is_our_devaddr(uint8_t *addr, int addr_type);
/* Get identity address 'addr_type' is public (0) or random (!=0) */
uint8_t *ble_ll_get_our_devaddr(uint8_t addr_type);
/**
* Called to put a packet on the Link Layer transmit packet queue.
*
* @param txpdu Pointer to transmit packet
*/
void ble_ll_acl_data_in(struct os_mbuf *txpkt);
/**
* Allocates mbuf for received PDU
*
* This allocated mbuf (may be chained if necessary) that has capacity large
* enough to store received PDU of given length. It does not set mbufs length
* as this has to be done by PHY when copying data.
*
* @param len Length of PDU, including PDU header and excluding MIC (if encrypted)
*
* @return mbuf large enough to store received PDU on success
* NULL on failure (oom)
*/
struct os_mbuf *ble_ll_rxpdu_alloc(uint16_t len);
/* Tell the Link Layer there has been a data buffer overflow */
void ble_ll_data_buffer_overflow(void);
/* Tell the link layer there has been a hardware error */
void ble_ll_hw_error(void);
/*--- PHY interfaces ---*/
struct ble_mbuf_hdr;
/* Called by the PHY when a packet has started */
int ble_ll_rx_start(uint8_t *rxbuf, uint8_t chan, struct ble_mbuf_hdr *hdr);
/* Called by the PHY when a packet reception ends */
int ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr);
/* Helper callback to tx mbuf using ble_phy_tx() */
uint8_t ble_ll_tx_mbuf_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte);
uint8_t ble_ll_tx_flat_mbuf_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte);
/*--- Controller API ---*/
void ble_ll_mbuf_init(struct os_mbuf *m, uint8_t pdulen, uint8_t hdr);
/* Set the link layer state */
void ble_ll_state_set(uint8_t ll_state);
/* Get the link layer state */
uint8_t ble_ll_state_get(void);
/* Send an event to LL task */
void ble_ll_event_send(struct ble_npl_event *ev);
/* Hand received pdu's to LL task */
void ble_ll_rx_pdu_in(struct os_mbuf *rxpdu);
/*
* Set public address
*
* This can be used to set controller public address from vendor specific storage,
* usually should be done in hal_bsp_init().
* Shall be *only* called before LL is initialized, i.e. before sysinit stage.
*/
int ble_ll_set_public_addr(const uint8_t *addr);
/* Set random address */
int ble_ll_set_random_addr(const uint8_t *cmdbuf, uint8_t len, bool hci_adv_ext);
/* Wait for response timer expiration callback */
void ble_ll_wfr_timer_exp(void *arg);
/* Read set of features supported by the Link Layer */
uint64_t ble_ll_read_supp_features(void);
/* Set host supported features */
int ble_ll_set_host_feat(const uint8_t *cmdbuf, uint8_t len);
/* Read set of states supported by the Link Layer */
uint64_t ble_ll_read_supp_states(void);
/* Check if octets and time are valid. Returns 0 if not valid */
int ble_ll_chk_txrx_octets(uint16_t octets);
int ble_ll_chk_txrx_time(uint16_t time);
/* Random numbers */
int ble_ll_rand_init(void);
void ble_ll_rand_sample(uint8_t rnum);
int ble_ll_rand_data_get(uint8_t *buf, uint8_t len);
void ble_ll_rand_prand_get(uint8_t *prand);
int ble_ll_rand_start(void);
static inline int
ble_ll_get_addr_type(uint8_t txrxflag)
{
if (txrxflag) {
return BLE_HCI_ADV_OWN_ADDR_RANDOM;
}
return BLE_HCI_ADV_OWN_ADDR_PUBLIC;
}
/* Convert usecs to ticks and round up to nearest tick */
static inline uint32_t
ble_ll_usecs_to_ticks_round_up(uint32_t usecs)
{
return os_cputime_usecs_to_ticks(usecs + 30);
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
/* LTK 0x4C68384139F574D836BCF34E9DFB01BF */
extern const uint8_t g_bletest_LTK[];
extern uint16_t g_bletest_EDIV;
extern uint64_t g_bletest_RAND;
extern uint64_t g_bletest_SKDm;
extern uint64_t g_bletest_SKDs;
extern uint32_t g_bletest_IVm;
extern uint32_t g_bletest_IVs;
#endif
#if MYNEWT_VAL(BLE_LL_DTM)
void ble_ll_dtm_init(void);
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_LL_ */

View File

@@ -0,0 +1,209 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_ADV_
#define H_BLE_LL_ADV_
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* ADV event timing
* T_advEvent = advInterval + advDelay
*
* advInterval: increments of 625 usecs
* advDelay: RAND[0, 10] msecs
*
*/
#define BLE_LL_ADV_ITVL (625) /* usecs */
#define BLE_LL_ADV_ITVL_MIN (32) /* units */
#define BLE_LL_ADV_ITVL_MAX (16384) /* units */
#define BLE_LL_ADV_ITVL_MS_MIN (20) /* msecs */
#define BLE_LL_ADV_ITVL_MS_MAX (10240) /* msecs */
#define BLE_LL_ADV_ITVL_SCAN_MIN (160) /* units */
#define BLE_LL_ADV_ITVL_SCAN_MS_MIN (100) /* msecs */
#define BLE_LL_ADV_ITVL_NONCONN_MS_MIN (100) /* msecs */
#define BLE_LL_ADV_DELAY_MS_MIN (0) /* msecs */
#define BLE_LL_ADV_DELAY_MS_MAX (10) /* msecs */
#define BLE_LL_ADV_PDU_ITVL_LD_MS_MAX (10) /* msecs */
#define BLE_LL_ADV_PDU_ITVL_HD_MS_MAX (3750) /* usecs */
#define BLE_LL_ADV_STATE_HD_MAX (1280) /* msecs */
#define BLE_LL_ADV_PERIODIC_ITVL (1250) /* usecs */
/* Maximum advertisement data length */
#define BLE_ADV_LEGACY_DATA_MAX_LEN (31)
#define BLE_ADV_LEGACY_MAX_PKT_LEN (37)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
#define BLE_ADV_DATA_MAX_LEN MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)
#else
#define BLE_ADV_DATA_MAX_LEN BLE_ADV_LEGACY_DATA_MAX_LEN
#endif
/*
* ADV_IND
* -> AdvA (6 bytes)
* -> AdvData (0 - 31 bytes)
*
* The advertising address (AdvA) is a public address (TxAdd=0) or random
* address (TxAdd = 1)
*/
#define BLE_ADV_IND_MIN_LEN (6)
#define BLE_ADV_IND_MAX_LEN (37)
/*
* ADV_DIRECT_IND
* -> AdvA (6 bytes)
* -> InitA (6 bytes)
*
* AdvA is the advertisers public address (TxAdd=0) or random address
* (TxAdd = 1).
*
* InitA is the initiators public or random address. This is the address
* to which this packet is addressed.
*
*/
#define BLE_ADV_DIRECT_IND_LEN (12)
/*
* ADV_NONCONN_IND
* -> AdvA (6 bytes)
* -> AdvData (0 - 31 bytes)
*
* The advertising address (AdvA) is a public address (TxAdd=0) or random
* address (TxAdd = 1)
*
*/
#define BLE_ADV_NONCONN_IND_MIN_LEN (6)
#define BLE_ADV_NONCONN_IND_MAX_LEN (37)
/*
* ADV_SCAN_IND
* -> AdvA (6 bytes)
* -> AdvData (0 - 31 bytes)
*
* The advertising address (AdvA) is a public address (TxAdd=0) or random
* address (TxAdd = 1)
*
*/
#define BLE_ADV_SCAN_IND_MIN_LEN (6)
#define BLE_ADV_SCAN_IND_MAX_LEN (37)
/*---- HCI ----*/
struct ble_ll_adv_sm;
struct ble_ll_conn_sm;
/* Start an advertiser */
int ble_ll_adv_start_req(uint8_t adv_chanmask, uint8_t adv_type,
uint8_t *init_addr, uint16_t adv_itvl, void *handle);
/* Start or stop advertising */
int ble_ll_hci_adv_set_enable(const uint8_t *cmdbuf, uint8_t len);
/* Set legacy advertising data */
int ble_ll_hci_set_adv_data(const uint8_t *cmdbuf, uint8_t len);
/* Set scan response data */
int ble_ll_hci_set_scan_rsp_data(const uint8_t *cmd, uint8_t cmd_len);
/* Set advertising parameters */
int ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len);
/* Read advertising channel power */
int ble_ll_adv_read_txpwr(uint8_t *rspbuf, uint8_t *rsplen);
/*---- API used by BLE LL ----*/
/* Send the connection complete event */
void ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm,
struct ble_mbuf_hdr *rxhdr);
/* Returns local resolvable private address */
uint8_t *ble_ll_adv_get_local_rpa(struct ble_ll_adv_sm *advsm);
/* Returns peer resolvable private address */
uint8_t *ble_ll_adv_get_peer_rpa(struct ble_ll_adv_sm *advsm);
/* Called to initialize advertising functionality. */
void ble_ll_adv_init(void);
/* Called when LL wait for response timer expires in advertising state */
void ble_ll_adv_wfr_timer_exp(void);
/* Called to reset the advertiser. */
void ble_ll_adv_reset(void);
/* Called on rx pdu start when in advertising state */
int ble_ll_adv_rx_isr_start(uint8_t pdu_type);
/* Called on rx pdu end when in advertising state */
int ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok);
/* Processes received packets at the link layer task */
void ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf,
struct ble_mbuf_hdr *hdr);
/* Boolean function denoting whether or not the whitelist can be changed */
int ble_ll_adv_can_chg_whitelist(void);
/*
* Called when an advertising event has been removed from the scheduler
* without being run.
*/
void ble_ll_adv_event_rmvd_from_sched(struct ble_ll_adv_sm *advsm);
/*
* Called when a periodic event has been removed from the scheduler
* without being run.
*/
void ble_ll_adv_periodic_rmvd_from_sched(struct ble_ll_adv_sm *advsm);
/* Called to halt currently running advertising event */
void ble_ll_adv_halt(void);
/* Called to determine if advertising is enabled */
uint8_t ble_ll_adv_enabled(void);
int ble_ll_adv_hci_set_random_addr(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_adv_set_random_addr(const uint8_t *addr, uint8_t instance);
int ble_ll_adv_remove(const uint8_t *addr, uint8_t len);
int ble_ll_adv_clear_all(void);
int ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_adv_ext_set_adv_data(const uint8_t *cmdbuf, uint8_t cmdlen);
int ble_ll_adv_ext_set_scan_rsp(const uint8_t *cmdbuf, uint8_t cmdlen);
int ble_ll_adv_ext_set_enable(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_adv_periodic_set_param(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_adv_periodic_set_data(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_adv_periodic_enable(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
/* Called to notify adv code about RPA rotation */
void ble_ll_adv_rpa_timeout(void);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_ADV_ */

View File

@@ -0,0 +1,425 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_CONN_
#define H_BLE_LL_CONN_
#include "nimble/porting/nimble/include/os/os.h"
#include "nimble/nimble/include/nimble/ble.h"
#include "nimble/nimble/include/nimble/hci_common.h"
#include "nimble/nimble/include/nimble/nimble_npl.h"
#include "ble_ll_sched.h"
#include "ble_ll_ctrl.h"
#include "ble_phy.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Roles */
#define BLE_LL_CONN_ROLE_NONE (0)
#define BLE_LL_CONN_ROLE_MASTER (1)
#define BLE_LL_CONN_ROLE_SLAVE (2)
/* Connection states */
#define BLE_LL_CONN_STATE_IDLE (0)
#define BLE_LL_CONN_STATE_CREATED (1)
#define BLE_LL_CONN_STATE_ESTABLISHED (2)
/* Channel map size */
#define BLE_LL_CONN_CHMAP_LEN (5)
/* Definitions for source clock accuracy */
#define BLE_MASTER_SCA_251_500_PPM (0)
#define BLE_MASTER_SCA_151_250_PPM (1)
#define BLE_MASTER_SCA_101_150_PPM (2)
#define BLE_MASTER_SCA_76_100_PPM (3)
#define BLE_MASTER_SCA_51_75_PPM (4)
#define BLE_MASTER_SCA_31_50_PPM (5)
#define BLE_MASTER_SCA_21_30_PPM (6)
#define BLE_MASTER_SCA_0_20_PPM (7)
/* Definition for RSSI when the RSSI is unknown */
#define BLE_LL_CONN_UNKNOWN_RSSI (127)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
/*
* Encryption states for a connection
*
* NOTE: the states are ordered so that we can check to see if the state
* is greater than ENCRYPTED. If so, it means that the start or pause
* encryption procedure is running and we should not send data pdu's.
*/
enum conn_enc_state {
CONN_ENC_S_UNENCRYPTED = 1,
CONN_ENC_S_ENCRYPTED,
CONN_ENC_S_ENC_RSP_WAIT,
CONN_ENC_S_PAUSE_ENC_RSP_WAIT,
CONN_ENC_S_PAUSED,
CONN_ENC_S_START_ENC_REQ_WAIT,
CONN_ENC_S_START_ENC_RSP_WAIT,
CONN_ENC_S_LTK_REQ_WAIT,
CONN_ENC_S_LTK_NEG_REPLY
};
/*
* Note that the LTK is the key, the SDK is the plain text, and the
* session key is the cipher text portion of the encryption block.
*
* NOTE: we have intentionally violated the specification by making the
* transmit and receive packet counters 32-bits as opposed to 39 (as per the
* specification). We do this to save code space, ram and calculation time. The
* only drawback is that any encrypted connection that sends more than 2^32
* packets will suffer a MIC failure and thus be disconnected.
*/
struct ble_ll_conn_enc_data
{
uint8_t enc_state;
uint8_t tx_encrypted;
uint16_t enc_div;
uint32_t tx_pkt_cntr;
uint32_t rx_pkt_cntr;
uint64_t host_rand_num;
uint8_t iv[8];
struct ble_encryption_block enc_block;
};
#endif
/* Connection state machine flags. */
union ble_ll_conn_sm_flags {
struct {
uint32_t pkt_rxd:1;
uint32_t terminate_ind_txd:1;
uint32_t terminate_ind_rxd:1;
uint32_t terminate_ind_rxd_acked:1;
uint32_t allow_slave_latency:1;
uint32_t slave_set_last_anchor:1;
uint32_t awaiting_host_reply:1;
uint32_t terminate_started:1;
uint32_t conn_update_sched:1;
uint32_t host_expects_upd_event:1;
uint32_t version_ind_sent:1;
uint32_t rxd_version_ind:1;
uint32_t chanmap_update_scheduled:1;
uint32_t conn_empty_pdu_txd:1;
uint32_t last_txd_md:1;
uint32_t conn_req_txd:1;
uint32_t send_ltk_req:1;
uint32_t encrypted:1;
uint32_t encrypt_chg_sent:1;
uint32_t le_ping_supp:1;
uint32_t csa2_supp:1;
uint32_t host_phy_update: 1;
uint32_t phy_update_sched: 1;
uint32_t ctrlr_phy_update: 1;
uint32_t phy_update_event: 1;
uint32_t peer_phy_update: 1; /* XXX:combine with ctrlr udpate bit? */
uint32_t aux_conn_req: 1;
uint32_t rxd_features:1;
uint32_t pending_hci_rd_features:1;
uint32_t pending_initiate_dle:1;
} cfbit;
uint32_t conn_flags;
} __attribute__((packed));
/**
* Structure used for PHY data inside a connection.
*
* NOTE: the new phy's are the phys we will change to when a phy update
* procedure is ongoing and the event counter hits the instant.
*
* tx_phy_mode: chip specific phy mode for tx
* rx_phy_mode: chip specific phy mode for rx
* cur_tx_phy: value denoting current tx_phy (not a bitmask!)
* cur_rx_phy: value denoting current rx phy (not a bitmask!)
* new_tx_phy: value denoting new tx_phy (not a bitmask!)
* new_rx_phy: value denoting new rx phy (not a bitmask!)
* req_pref_tx_phy: tx phy sent in a phy request (may be different than host)
* req_pref_rx_phy: rx phy sent in a phy request (may be different than host)
* host_pref_tx_phys: bitmask of preferred transmit PHYs sent by host
* host_pref_rx_phys: bitmask of preferred receive PHYs sent by host
* phy_options: preferred phy options for coded phy
*/
struct ble_ll_conn_phy_data
{
uint32_t tx_phy_mode: 2;
uint32_t rx_phy_mode: 2;
uint32_t cur_tx_phy: 2;
uint32_t cur_rx_phy: 2;
uint32_t new_tx_phy: 2;
uint32_t new_rx_phy: 2;
uint32_t host_pref_tx_phys_mask: 3;
uint32_t host_pref_rx_phys_mask: 3;
uint32_t req_pref_tx_phys_mask: 3;
uint32_t req_pref_rx_phys_mask: 3;
uint32_t phy_options: 2;
} __attribute__((packed));
#define CONN_CUR_TX_PHY_MASK(csm) (1 << ((csm)->phy_data.cur_tx_phy - 1))
#define CONN_CUR_RX_PHY_MASK(csm) (1 << ((csm)->phy_data.cur_rx_phy - 1))
struct hci_conn_update
{
uint16_t handle;
uint16_t conn_itvl_min;
uint16_t conn_itvl_max;
uint16_t conn_latency;
uint16_t supervision_timeout;
uint16_t min_ce_len;
uint16_t max_ce_len;
};
struct hci_ext_conn_params
{
uint16_t scan_itvl;
uint16_t scan_window;
uint16_t conn_itvl_min;
uint16_t conn_itvl_max;
uint16_t conn_latency;
uint16_t supervision_timeout;
uint16_t min_ce_len;
uint16_t max_ce_len;
};
struct hci_ext_create_conn
{
uint8_t filter_policy;
uint8_t own_addr_type;
uint8_t peer_addr_type;
uint8_t peer_addr[BLE_DEV_ADDR_LEN];
uint8_t init_phy_mask;
struct hci_ext_conn_params params[3];
};
/* Connection state machine */
struct ble_ll_conn_sm
{
/* Connection state machine flags */
union ble_ll_conn_sm_flags csmflags;
/* Current connection handle, state and role */
uint16_t conn_handle;
uint8_t conn_state;
uint8_t conn_role; /* Can possibly be 1 bit */
/* RSSI */
int8_t conn_rssi;
/* For privacy */
int8_t rpa_index;
/* Connection data length management */
uint8_t max_tx_octets;
uint8_t max_rx_octets;
uint8_t rem_max_tx_octets;
uint8_t rem_max_rx_octets;
uint8_t eff_max_tx_octets;
uint8_t eff_max_rx_octets;
uint16_t max_tx_time;
uint16_t max_rx_time;
uint16_t rem_max_tx_time;
uint16_t rem_max_rx_time;
uint16_t eff_max_tx_time;
uint16_t eff_max_rx_time;
uint8_t max_tx_octets_phy_mode[BLE_PHY_NUM_MODE];
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
uint16_t host_req_max_tx_time;
#endif
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
struct ble_ll_conn_phy_data phy_data;
uint16_t phy_instant;
uint8_t phy_tx_transition;
#endif
/* Used to calculate data channel index for connection */
uint8_t chanmap[BLE_LL_CONN_CHMAP_LEN];
uint8_t req_chanmap[BLE_LL_CONN_CHMAP_LEN];
uint16_t chanmap_instant;
uint16_t channel_id; /* TODO could be union with hop and last chan used */
uint8_t hop_inc;
uint8_t data_chan_index;
uint8_t last_unmapped_chan;
uint8_t num_used_chans;
#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
uint8_t period_occ_mask; /* mask: period 0 = 0x01, period 3 = 0x08 */
#endif
/* Ack/Flow Control */
uint8_t tx_seqnum; /* note: can be 1 bit */
uint8_t next_exp_seqnum; /* note: can be 1 bit */
uint8_t cons_rxd_bad_crc; /* note: can be 1 bit */
uint8_t last_rxd_sn; /* note: cant be 1 bit given current code */
uint8_t last_rxd_hdr_byte; /* note: possibly can make 1 bit since we
only use the MD bit now */
/* connection event mgmt */
uint8_t reject_reason;
uint8_t host_reply_opcode;
uint8_t master_sca;
uint8_t tx_win_size;
uint8_t cur_ctrl_proc;
uint8_t disconnect_reason;
uint8_t rxd_disconnect_reason;
uint8_t vers_nr;
uint8_t conn_features;
uint8_t remote_features[7];
uint16_t pending_ctrl_procs;
uint16_t event_cntr;
uint16_t completed_pkts;
uint16_t comp_id;
uint16_t sub_vers_nr;
uint16_t auth_pyld_tmo; /* could be ifdef'd. 10 msec units */
uint32_t access_addr;
uint32_t crcinit; /* only low 24 bits used */
/* XXX: do we need ce_end_time? Cant this be sched end time? */
uint32_t ce_end_time; /* cputime at which connection event should end */
uint32_t terminate_timeout;
uint32_t last_scheduled;
/* Connection timing */
uint16_t conn_itvl;
uint16_t slave_latency;
uint16_t supervision_tmo;
uint16_t min_ce_len;
uint16_t max_ce_len;
uint16_t tx_win_off;
uint32_t anchor_point;
uint8_t anchor_point_usecs; /* XXX: can this be uint8_t ?*/
uint8_t conn_itvl_usecs;
uint32_t conn_itvl_ticks;
uint32_t last_anchor_point; /* Slave only */
uint32_t slave_cur_tx_win_usecs;
uint32_t slave_cur_window_widening;
uint32_t last_rxd_pdu_cputime; /* Used exclusively for supervision timer */
/*
* Used to mark that identity address was used as InitA
*/
uint8_t inita_identity_used;
/* address information */
uint8_t own_addr_type;
uint8_t peer_addr_type;
uint8_t peer_addr[BLE_DEV_ADDR_LEN];
/*
* XXX: TODO. Could save memory. Have single event at LL and put these
* on a singly linked list. Only would need list pointer here.
*/
/* Connection end event */
struct ble_npl_event conn_ev_end;
/* Packet transmit queue */
struct os_mbuf *cur_tx_pdu;
STAILQ_HEAD(conn_txq_head, os_mbuf_pkthdr) conn_txq;
/* List entry for active/free connection pools */
union {
SLIST_ENTRY(ble_ll_conn_sm) act_sle;
STAILQ_ENTRY(ble_ll_conn_sm) free_stqe;
};
/* LL control procedure response timer */
struct ble_npl_callout ctrl_proc_rsp_timer;
/* For scheduling connections */
struct ble_ll_sched_item conn_sch;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING)
struct ble_npl_callout auth_pyld_timer;
#endif
/*
* XXX: a note on all these structures for control procedures. First off,
* all of these need to be ifdef'd to save memory. Another thing to
* consider is this: since most control procedures can only run when no
* others are running, can I use just one structure (a union)? Should I
* allocate these from a pool? Not sure what to do. For now, I just use
* a large chunk of memory per connection.
*/
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
struct ble_ll_conn_enc_data enc_data;
#endif
/*
* For connection update procedure. XXX: can make this a pointer and
* malloc it if we want to save space.
*/
struct hci_conn_update conn_param_req;
/* For connection update procedure */
struct ble_ll_conn_upd_req conn_update_req;
/* XXX: for now, just store them all */
struct ble_ll_conn_params conn_cp;
struct ble_ll_scan_sm *scansm;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
struct hci_ext_create_conn initial_params;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
uint8_t sync_transfer_mode;
uint16_t sync_transfer_skip;
uint32_t sync_transfer_sync_timeout;
#endif
};
/* Flags */
#define CONN_F_UPDATE_SCHED(csm) ((csm)->csmflags.cfbit.conn_update_sched)
#define CONN_F_EMPTY_PDU_TXD(csm) ((csm)->csmflags.cfbit.conn_empty_pdu_txd)
#define CONN_F_LAST_TXD_MD(csm) ((csm)->csmflags.cfbit.last_txd_md)
#define CONN_F_CONN_REQ_TXD(csm) ((csm)->csmflags.cfbit.conn_req_txd)
#define CONN_F_ENCRYPTED(csm) ((csm)->csmflags.cfbit.encrypted)
#define CONN_F_ENC_CHANGE_SENT(csm) ((csm)->csmflags.cfbit.encrypt_chg_sent)
#define CONN_F_LE_PING_SUPP(csm) ((csm)->csmflags.cfbit.le_ping_supp)
#define CONN_F_TERMINATE_STARTED(csm) ((csm)->csmflags.cfbit.terminate_started)
#define CONN_F_CSA2_SUPP(csm) ((csm)->csmflags.cfbit.csa2_supp)
#define CONN_F_HOST_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.host_phy_update)
#define CONN_F_PHY_UPDATE_SCHED(csm) ((csm)->csmflags.cfbit.phy_update_sched)
#define CONN_F_CTRLR_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.ctrlr_phy_update)
#define CONN_F_PHY_UPDATE_EVENT(csm) ((csm)->csmflags.cfbit.phy_update_event)
#define CONN_F_PEER_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.peer_phy_update)
#define CONN_F_AUX_CONN_REQ(csm) ((csm)->csmflags.cfbit.aux_conn_req)
/* Role */
#define CONN_IS_MASTER(csm) (csm->conn_role == BLE_LL_CONN_ROLE_MASTER)
#define CONN_IS_SLAVE(csm) (csm->conn_role == BLE_LL_CONN_ROLE_SLAVE)
/*
* Given a handle, returns an active connection state machine (or NULL if the
* handle does not exist
*
*/
struct ble_ll_conn_sm *ble_ll_conn_find_active_conn(uint16_t handle);
/* required for unit testing */
uint8_t ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn, uint16_t latency);
/* used to get anchor point for connection event specified */
void ble_ll_conn_get_anchor(struct ble_ll_conn_sm *connsm, uint16_t conn_event,
uint32_t *anchor, uint8_t *anchor_usecs);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_CONN_ */

View File

@@ -0,0 +1,313 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_CTRL_
#define H_BLE_LL_CTRL_
#ifdef __cplusplus
extern "C" {
#endif
/*
* LL control procedures. This "enumeration" is not in the specification;
* It is used to determine which LL control procedure is currently running
* in a connection and which ones may be pending.
*/
#define BLE_LL_CTRL_PROC_CONN_UPDATE (0)
#define BLE_LL_CTRL_PROC_CHAN_MAP_UPD (1)
#define BLE_LL_CTRL_PROC_ENCRYPT (2)
#define BLE_LL_CTRL_PROC_FEATURE_XCHG (3)
#define BLE_LL_CTRL_PROC_VERSION_XCHG (4)
#define BLE_LL_CTRL_PROC_TERMINATE (5)
#define BLE_LL_CTRL_PROC_CONN_PARAM_REQ (6)
#define BLE_LL_CTRL_PROC_LE_PING (7)
#define BLE_LL_CTRL_PROC_DATA_LEN_UPD (8)
#define BLE_LL_CTRL_PROC_PHY_UPDATE (9)
#define BLE_LL_CTRL_PROC_NUM (10)
#define BLE_LL_CTRL_PROC_IDLE (255)
/* Checks if a particular control procedure is running */
#define IS_PENDING_CTRL_PROC(sm, proc) (sm->pending_ctrl_procs & (1 << proc))
#define CLR_PENDING_CTRL_PROC(sm, proc) (sm->pending_ctrl_procs &= ~(1 << proc))
/* LL control procedure timeout */
#define BLE_LL_CTRL_PROC_TIMEOUT_MS (40000) /* ms */
/*
* LL CTRL PDU format
* -> Opcode (1 byte)
* -> Data (0 - 26 bytes)
*/
#define BLE_LL_CTRL_CONN_UPDATE_IND (0)
#define BLE_LL_CTRL_CHANNEL_MAP_REQ (1)
#define BLE_LL_CTRL_TERMINATE_IND (2)
#define BLE_LL_CTRL_ENC_REQ (3)
#define BLE_LL_CTRL_ENC_RSP (4)
#define BLE_LL_CTRL_START_ENC_REQ (5)
#define BLE_LL_CTRL_START_ENC_RSP (6)
#define BLE_LL_CTRL_UNKNOWN_RSP (7)
#define BLE_LL_CTRL_FEATURE_REQ (8)
#define BLE_LL_CTRL_FEATURE_RSP (9)
#define BLE_LL_CTRL_PAUSE_ENC_REQ (10)
#define BLE_LL_CTRL_PAUSE_ENC_RSP (11)
#define BLE_LL_CTRL_VERSION_IND (12)
#define BLE_LL_CTRL_REJECT_IND (13)
#define BLE_LL_CTRL_SLAVE_FEATURE_REQ (14)
#define BLE_LL_CTRL_CONN_PARM_REQ (15)
#define BLE_LL_CTRL_CONN_PARM_RSP (16)
#define BLE_LL_CTRL_REJECT_IND_EXT (17)
#define BLE_LL_CTRL_PING_REQ (18)
#define BLE_LL_CTRL_PING_RSP (19)
#define BLE_LL_CTRL_LENGTH_REQ (20)
#define BLE_LL_CTRL_LENGTH_RSP (21)
#define BLE_LL_CTRL_PHY_REQ (22)
#define BLE_LL_CTRL_PHY_RSP (23)
#define BLE_LL_CTRL_PHY_UPDATE_IND (24)
#define BLE_LL_CTRL_MIN_USED_CHAN_IND (25)
#define BLE_LL_CTRL_CTE_REQ (26)
#define BLE_LL_CTRL_CTE_RSP (27)
#define BLE_LL_CTRL_PERIODIC_SYNC_IND (28)
#define BLE_LL_CTRL_CLOCK_ACCURACY_REQ (29)
#define BLE_LL_CTRL_CLOCK_ACCURACY_RSP (30)
/* Maximum opcode value */
#define BLE_LL_CTRL_OPCODES (BLE_LL_CTRL_CLOCK_ACCURACY_RSP + 1)
extern const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES];
/* Maximum LL control PDU size */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
#define BLE_LL_CTRL_MAX_PDU_LEN (35)
#else
#define BLE_LL_CTRL_MAX_PDU_LEN (27)
#endif
/* LL control connection update request */
struct ble_ll_conn_upd_req
{
uint8_t winsize;
uint16_t winoffset;
uint16_t interval;
uint16_t latency;
uint16_t timeout;
uint16_t instant;
};
#define BLE_LL_CTRL_CONN_UPD_REQ_LEN (11)
/* LL control channel map request */
struct ble_ll_chan_map_req
{
uint8_t chmap[5];
uint16_t instant;
};
#define BLE_LL_CTRL_CHAN_MAP_LEN (7)
/*
* LL control terminate ind
* -> error code (1 byte)
*/
#define BLE_LL_CTRL_TERMINATE_IND_LEN (1)
/* LL control enc req */
struct ble_ll_enc_req
{
uint8_t rand[8];
uint16_t ediv;
uint8_t skdm[8];
uint32_t ivm;
};
#define BLE_LL_CTRL_ENC_REQ_LEN (22)
/* LL control enc rsp */
struct ble_ll_enc_rsp
{
uint8_t skds[8];
uint32_t ivs;
};
#define BLE_LL_CTRL_ENC_RSP_LEN (12)
/* LL control start/pause enc request and response */
#define BLE_LL_CTRL_START_ENC_REQ_LEN (0)
#define BLE_LL_CTRL_START_ENC_RSP_LEN (0)
#define BLE_LL_CTRL_PAUSE_ENC_REQ_LEN (0)
#define BLE_LL_CTRL_PAUSE_ENC_RSP_LEN (0)
/*
* LL control unknown response
* -> 1 byte which contains the unknown or un-supported opcode.
*/
#define BLE_LL_CTRL_UNK_RSP_LEN (1)
/*
* LL control feature req and LL control feature rsp
* -> 8 bytes of data containing features supported by device.
*/
#define BLE_LL_CTRL_FEATURE_LEN (8)
/*
* LL control version ind
* -> version (1 byte):
* Contains the version number of the bluetooth controller specification.
* -> comp_id (2 bytes)
* Contains the company identifier of the manufacturer of the controller.
* -> sub_ver_num: Contains a unique value for implementation or revision of
* the bluetooth controller.
*/
struct ble_ll_version_ind
{
uint8_t ble_ctrlr_ver;
uint16_t company_id;
uint16_t sub_ver_num;
};
#define BLE_LL_CTRL_VERSION_IND_LEN (5)
/*
* LL control reject ind
* -> error code (1 byte): contains reason why request was rejected.
*/
#define BLE_LL_CTRL_REJ_IND_LEN (1)
/*
* LL control slave feature req
* -> 8 bytes of data containing features supported by device.
*/
#define BLE_LL_CTRL_SLAVE_FEATURE_REQ_LEN (8)
/* LL control connection param req and connection param rsp */
struct ble_ll_conn_params
{
uint16_t interval_min;
uint16_t interval_max;
uint16_t latency;
uint16_t timeout;
uint8_t pref_periodicity;
uint16_t ref_conn_event_cnt;
uint16_t offset0;
uint16_t offset1;
uint16_t offset2;
uint16_t offset3;
uint16_t offset4;
uint16_t offset5;
};
#define BLE_LL_CTRL_CONN_PARAMS_LEN (23)
/* LL control reject ind ext */
struct ble_ll_reject_ind_ext
{
uint8_t reject_opcode;
uint8_t err_code;
};
#define BLE_LL_CTRL_REJECT_IND_EXT_LEN (2)
/* LL control ping req and ping rsp (contain no data) */
#define BLE_LL_CTRL_PING_LEN (0)
/*
* LL control length req and length rsp
* -> max_rx_bytes (2 bytes): defines connMaxRxOctets. Range 27 to 251
* -> max_rx_time (2 bytes): defines connMaxRxTime. Range 328 to 2120 usecs.
* -> max_tx_bytes (2 bytes): defines connMaxTxOctets. Range 27 to 251
* -> max_tx_time (2 bytes): defines connMaxTxTime. Range 328 to 2120 usecs.
*/
struct ble_ll_len_req
{
uint16_t max_rx_bytes;
uint16_t max_rx_time;
uint16_t max_tx_bytes;
uint16_t max_tx_time;
};
#define BLE_LL_CTRL_LENGTH_REQ_LEN (8)
/* PHY request/response */
#define BLE_LL_CTRL_PHY_REQ_LEN (2)
#define BLE_LL_CTRL_PHY_RSP_LEN (2)
#define BLE_LL_CTRL_PHY_UPD_IND_LEN (4)
/* Min used channels */
#define BLE_LL_CTRL_MIN_USED_CHAN_LEN (2)
/* CTE REQ */
#define BLE_LL_CTRL_CTE_REQ_LEN (1)
/* CTE RSP (contains no data) */
#define BLE_LL_CTRL_CTE_RSP_LEN (0)
/* Periodic Sync Transfer IND */
#define BLE_LL_CTRL_PERIODIC_SYNC_IND_LEN (34)
/* Clock accuracy request/response */
#define BLE_LL_CTRL_CLOCK_ACCURACY_REQ_LEN (1)
#define BLE_LL_CTRL_CLOCK_ACCURACY_RSP_LEN (1)
/* API */
struct ble_ll_conn_sm;
void ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc);
void ble_ll_ctrl_proc_stop(struct ble_ll_conn_sm *connsm, int ctrl_proc);
int ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om);
void ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm);
void ble_ll_ctrl_terminate_start(struct ble_ll_conn_sm *connsm);
int ble_ll_ctrl_is_terminate_ind(uint8_t hdr, uint8_t opcode);
uint8_t ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm,
uint8_t *rsp,
struct ble_ll_conn_params *req);
int ble_ll_ctrl_reject_ind_send(struct ble_ll_conn_sm *connsm,
uint8_t rej_opcode, uint8_t err);
int ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm);
int ble_ll_ctrl_enc_allowed_pdu_rx(struct os_mbuf *rxpdu);
int ble_ll_ctrl_enc_allowed_pdu_tx(struct os_mbuf_pkthdr *pkthdr);
int ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm);
int ble_ll_ctrl_is_start_enc_rsp(struct os_mbuf *txpdu);
void ble_ll_hci_ev_datalen_chg(struct ble_ll_conn_sm *connsm);
void ble_ll_hci_ev_rem_conn_parm_req(struct ble_ll_conn_sm *connsm,
struct ble_ll_conn_params *cp);
void ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status);
void ble_ll_hci_ev_rd_rem_used_feat(struct ble_ll_conn_sm *connsm,
uint8_t status);
void ble_ll_hci_ev_rd_rem_ver(struct ble_ll_conn_sm *connsm, uint8_t status);
void ble_ll_hci_ev_encrypt_chg(struct ble_ll_conn_sm *connsm, uint8_t status);
int ble_ll_hci_ev_ltk_req(struct ble_ll_conn_sm *connsm);
int ble_ll_hci_ev_hw_err(uint8_t hw_err);
void ble_ll_hci_ev_databuf_overflow(void);
void ble_ll_hci_ev_le_csa(struct ble_ll_conn_sm *connsm);
void ble_ll_hci_ev_send_scan_req_recv(uint8_t adv_handle, const uint8_t *peer,
uint8_t peer_addr_type);
void ble_ll_hci_ev_send_scan_timeout(void);
void ble_ll_hci_ev_send_adv_set_terminated(uint8_t status, uint8_t adv_handle,
uint16_t conn_handle, uint8_t events);
int ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status);
void ble_ll_calc_session_key(struct ble_ll_conn_sm *connsm);
void ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm);
void ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm);
void ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line);
uint8_t ble_ll_ctrl_phy_tx_transition_get(uint8_t phy_mask);
uint8_t ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_CTRL_ */

View File

@@ -0,0 +1,75 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_HCI_
#define H_BLE_LL_HCI_
#ifdef __cplusplus
extern "C" {
#endif
#include "nimble/nimble/include/nimble/hci_common.h"
/* For supported commands */
#define BLE_LL_SUPP_CMD_LEN (42)
extern const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN];
/* The largest event the controller will send. */
#define BLE_LL_MAX_EVT_LEN MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)
/*
* This determines the number of outstanding commands allowed from the
* host to the controller. NOTE: you cannot change this without modifying
* other portions of the code as we currently use a global os event for
* the command; you would need to allocate a pool of these.
*/
#define BLE_LL_CFG_NUM_HCI_CMD_PKTS (1)
typedef void (*ble_ll_hci_post_cmd_complete_cb)(void);
/* Initialize LL HCI */
void ble_ll_hci_init(void);
/* Used to determine if the LE event is enabled/disabled */
bool ble_ll_hci_is_le_event_enabled(unsigned int subev);
/* Used to determine if event is enabled/disabled */
bool ble_ll_hci_is_event_enabled(unsigned int evcode);
/* Send event from controller to host */
int ble_ll_hci_event_send(struct ble_hci_ev *hci_ev);
/* Sends a command complete with a no-op opcode to host */
void ble_ll_hci_send_noop(void);
/* Checks the preferref phy masks from set default phy and set phy commands */
int ble_ll_hci_chk_phy_masks(uint8_t all_phys, uint8_t tx_phys, uint8_t rx_phys,
uint8_t *txphy, uint8_t *rxphy);
/* Returns true if Extended Advertising HCI commands are in use */
bool ble_ll_hci_adv_mode_ext(void);
/* Get TX power compensation rounded to integer dB */
int8_t ble_ll_get_tx_pwr_compensation(void);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_HCI_ */

View File

@@ -0,0 +1,116 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_RESOLV_
#define H_BLE_LL_RESOLV_
#ifdef __cplusplus
extern "C" {
#endif
/*
* An entry in the resolving list.
* The identity address is stored in little endian format.
* The local rpa is stored in little endian format.
* The IRKs are stored in big endian format.
*
* Note:
* rl_local_irk and rl_peer_irk need to be word aligned
*/
struct ble_ll_resolv_entry
{
uint8_t rl_addr_type;
uint8_t rl_priv_mode;
uint8_t rl_has_local;
uint8_t rl_has_peer;
uint8_t rl_local_irk[16];
uint8_t rl_peer_irk[16];
uint8_t rl_identity_addr[BLE_DEV_ADDR_LEN];
uint8_t rl_local_rpa[BLE_DEV_ADDR_LEN];
uint8_t rl_peer_rpa[BLE_DEV_ADDR_LEN];
};
extern struct ble_ll_resolv_entry g_ble_ll_resolv_list[];
/* Clear the resolving list */
int ble_ll_resolv_list_clr(void);
/* Read the size of the resolving list */
int ble_ll_resolv_list_read_size(uint8_t *rspbuf, uint8_t *rsplen);
/* Add a device to the resolving list */
int ble_ll_resolv_list_add(const uint8_t *cmdbuf, uint8_t len);
/* Remove a device from the resolving list */
int ble_ll_resolv_list_rmv(const uint8_t *cmdbuf, uint8_t len);
/* Address resolution enable command */
int ble_ll_resolv_enable_cmd(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_resolv_peer_addr_rd(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_resolv_local_addr_rd(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
/* Finds 'addr' in resolving list. Doesnt check if address resolution enabled */
struct ble_ll_resolv_entry *
ble_ll_resolv_list_find(const uint8_t *addr, uint8_t addr_type);
/* Returns true if address resolution is enabled */
uint8_t ble_ll_resolv_enabled(void);
/* Reset private address resolution */
void ble_ll_resolv_list_reset(void);
/* Generate local or peer RPA. It is up to caller to make sure required IRK
* is present on RL
*/
void ble_ll_resolv_get_priv_addr(struct ble_ll_resolv_entry *rl, int local,
uint8_t *addr);
void ble_ll_resolv_set_peer_rpa(int index, uint8_t *rpa);
void ble_ll_resolv_set_local_rpa(int index, uint8_t *rpa);
/* Generate a resolvable private address. */
int ble_ll_resolv_gen_rpa(uint8_t *addr, uint8_t addr_type, uint8_t *rpa,
int local);
/* Set the resolvable private address timeout */
int ble_ll_resolv_set_rpa_tmo(const uint8_t *cmdbuf, uint8_t len);
/* Set the privacy mode */
int ble_ll_resolve_set_priv_mode(const uint8_t *cmdbuf, uint8_t len);
/* Get the RPA timeout, in seconds */
uint32_t ble_ll_resolv_get_rpa_tmo(void);
/* Resolve a resolvable private address */
int ble_ll_resolv_rpa(const uint8_t *rpa, const uint8_t *irk);
/* Try to resolve peer RPA and return index on RL if matched */
int ble_ll_resolv_peer_rpa_any(const uint8_t *rpa);
/* Initialize resolv*/
void ble_ll_resolv_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_RFMGMT_
#define H_BLE_LL_RFMGMT_
#ifdef __cplusplus
extern "C" {
#endif
void ble_ll_rfmgmt_init(void);
#if MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME) > 0
void ble_ll_rfmgmt_reset(void);
/* Notify rfmgmt that scan window has changed (only called from ble_ll_scan) */
void ble_ll_rfmgmt_scan_changed(bool enabled, uint32_t next_window);
/* Notify rfmgmt that 1st scheduled item has changed (only called from ble_ll_sched) */
void ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *first);
/* Notify rfmgmt that RF is no longer needed by current event */
void ble_ll_rfmgmt_release(void);
/* Enables RF immediately and returns tick at which RF will be fully enabled */
uint32_t ble_ll_rfmgmt_enable_now(void);
/* Returns true only if RF is currently fully enabled (i.e. not off or enabling) */
bool ble_ll_rfmgmt_is_enabled(void);
#else
static inline void ble_ll_rfmgmt_reset(void) { }
static inline void ble_ll_rfmgmt_scan_changed(bool e, uint32_t n) { }
static inline void ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *f) { }
static inline void ble_ll_rfmgmt_release(void) { }
static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return 0; }
static inline bool ble_ll_rfmgmt_is_enabled(void) { return true; }
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_RFMGMT_ */

View File

@@ -0,0 +1,293 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_SCAN_
#define H_BLE_LL_SCAN_
#include "ble_ll_sched.h"
#include "nimble/porting/nimble/include/hal/hal_timer.h"
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#include "nimble/nimble/include/nimble/nimble_npl.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* SCAN_REQ
* -> ScanA (6 bytes)
* -> AdvA (6 bytes)
*
* ScanA is the scanners public (TxAdd=0) or random (TxAdd = 1) address
* AdvaA is the advertisers public (RxAdd=0) or random (RxAdd=1) address.
*
* Sent by the LL in the Scanning state; received by the LL in the advertising
* state. The advertising address is the intended recipient of this frame.
*/
#define BLE_SCAN_REQ_LEN (12)
/*
* SCAN_RSP
* -> AdvA (6 bytes)
* -> ScanRspData (0 - 31 bytes)
*
* AdvaA is the advertisers public (TxAdd=0) or random (TxAdd=1) address.
* ScanRspData may contain any data from the advertisers host.
*
* Sent by the LL in the advertising state; received by the LL in the
* scanning state.
*/
#define BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN (31)
#define BLE_SCAN_LEGACY_MAX_PKT_LEN (37)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
#define BLE_SCAN_RSP_DATA_MAX_LEN MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)
/* For Bluetooth 5.0 we need state machine for two PHYs*/
#define BLE_LL_SCAN_PHY_NUMBER (2)
#else
#define BLE_LL_SCAN_PHY_NUMBER (1)
#define BLE_SCAN_RSP_DATA_MAX_LEN BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN
#endif
#define PHY_UNCODED (0)
#define PHY_CODED (1)
#define BLE_LL_EXT_ADV_MODE_NON_CONN (0x00)
#define BLE_LL_EXT_ADV_MODE_CONN (0x01)
#define BLE_LL_EXT_ADV_MODE_SCAN (0x02)
/* All values are stored as ticks */
struct ble_ll_scan_timing {
uint32_t interval;
uint32_t window;
uint32_t start_time;
};
struct ble_ll_scan_params
{
uint8_t phy;
uint8_t own_addr_type;
uint8_t scan_filt_policy;
uint8_t configured;
uint8_t scan_type;
uint8_t scan_chan;
struct ble_ll_scan_timing timing;
};
#define BLE_LL_AUX_HAS_ADVA 0x01
#define BLE_LL_AUX_HAS_TARGETA 0x02
#define BLE_LL_AUX_HAS_ADI 0x04
#define BLE_LL_AUX_IS_MATCHED 0x08
#define BLE_LL_AUX_IS_TARGETA_RESOLVED 0x10
#define BLE_LL_AUX_FLAG_HCI_SENT_ANY 0x02
#define BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED 0x04
#define BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED 0x08
#define BLE_LL_AUX_FLAG_SCAN_COMPLETE 0x10
#define BLE_LL_AUX_FLAG_SCAN_ERROR 0x20
#define BLE_LL_AUX_FLAG_AUX_ADV_RECEIVED 0x40
#define BLE_LL_AUX_FLAG_AUX_CHAIN_RECEIVED 0x80
struct ble_ll_aux_data {
uint8_t flags;
/*
* Since aux_data can be accessed from ISR and LL, we have separate copies
* of flags to make sure that ISR does not modify flags while LL uses them.
* ISR updates 'flags_isr' and LL adds these to 'flags_ll' which it then
* uses for further processing allowing to update 'flags_isr' if another
* scan for given 'aux_data' is scheduled. Note that flags must not be unset
* while aux_data is valid.
*/
uint8_t flags_isr;
uint8_t flags_ll;
uint8_t ref_cnt;
uint8_t chan;
uint8_t aux_phy;
uint8_t aux_primary_phy;
uint8_t mode;
uint8_t scanning;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
int8_t rpa_index;
#endif
uint16_t adi;
uint32_t offset;
uint8_t offset_units;
uint8_t adva[6];
uint8_t adva_type;
uint8_t targeta[6];
uint8_t targeta_type;
uint16_t evt_type;
struct ble_ll_sched_item sch;
struct ble_hci_ev *evt;
struct ble_npl_event ev;
};
struct ble_ll_scan_pdu_data {
uint8_t hdr_byte;
/* ScanA for SCAN_REQ and InitA for CONNECT_IND */
union {
uint8_t scana[BLE_DEV_ADDR_LEN];
uint8_t inita[BLE_DEV_ADDR_LEN];
};
uint8_t adva[BLE_DEV_ADDR_LEN];
};
struct ble_ll_scan_sm
{
uint8_t scan_enabled;
uint8_t own_addr_type;
uint8_t scan_filt_dups;
uint8_t scan_rsp_pending;
uint8_t scan_rsp_cons_fails;
uint8_t scan_rsp_cons_ok;
uint8_t scan_peer_rpa[BLE_DEV_ADDR_LEN];
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
ble_npl_time_t scan_nrpa_timer;
uint8_t scan_nrpa[BLE_DEV_ADDR_LEN];
#endif
struct ble_ll_scan_pdu_data pdu_data;
/* XXX: Shall we count backoff per phy? */
uint16_t upper_limit;
uint16_t backoff_count;
uint32_t scan_win_start_time;
struct ble_npl_event scan_sched_ev;
struct hal_timer scan_timer;
struct ble_npl_event scan_interrupted_ev;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
struct hal_timer duration_timer;
struct hal_timer period_timer;
uint32_t duration_ticks;
uint32_t period_ticks;
uint8_t ext_scanning;
#endif
uint8_t restart_timer_needed;
struct ble_ll_aux_data *cur_aux_data;
struct ble_ll_scan_params *scanp;
struct ble_ll_scan_params *scanp_next;
struct ble_ll_scan_params scanp_phys[BLE_LL_SCAN_PHY_NUMBER];
};
/* Scan types */
#define BLE_SCAN_TYPE_PASSIVE (BLE_HCI_SCAN_TYPE_PASSIVE)
#define BLE_SCAN_TYPE_ACTIVE (BLE_HCI_SCAN_TYPE_ACTIVE)
#define BLE_SCAN_TYPE_INITIATE (2)
/*---- HCI ----*/
/* Set scanning parameters */
int ble_ll_scan_set_scan_params(const uint8_t *cmdbuf, uint8_t len);
/* Turn scanning on/off */
int ble_ll_hci_scan_set_enable(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_hci_ext_scan_set_enable(const uint8_t *cmdbuf, uint8_t len);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
int ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len);
#endif
/*--- Controller Internal API ---*/
/* Initialize the scanner */
void ble_ll_scan_init(void);
/* Reset the scanner */
void ble_ll_scan_reset(void);
/* Called when Link Layer starts to receive a PDU and is in scanning state */
int ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint16_t *rxflags);
/* Called when Link Layer has finished receiving a PDU while scanning */
int ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok);
/* Process a scan response PDU */
void ble_ll_scan_rx_pkt_in(uint8_t pdu_type, struct os_mbuf *om,
struct ble_mbuf_hdr *hdr);
/* Boolean function denoting whether or not the whitelist can be changed */
int ble_ll_scan_can_chg_whitelist(void);
/* Boolean function returning true if scanning enabled */
int ble_ll_scan_enabled(void);
/* Boolean function returns true if whitelist is enabled for scanning */
int ble_ll_scan_whitelist_enabled(void);
/* Initialize the scanner when we start initiating */
struct hci_create_conn;
int ble_ll_scan_initiator_start(struct hci_create_conn *hcc,
struct ble_ll_scan_sm **sm);
/* Returns storage for PDU data (for SCAN_REQ or CONNECT_IND) */
struct ble_ll_scan_pdu_data *ble_ll_scan_get_pdu_data(void);
/* Called to set the resolvable private address of the last connected peer */
void ble_ll_scan_set_peer_rpa(uint8_t *rpa);
/* Returns peer RPA of last connection made */
uint8_t *ble_ll_scan_get_peer_rpa(void);
/* Returns the local RPA used by the scanner/initiator */
uint8_t *ble_ll_scan_get_local_rpa(void);
/* Stop the scanning state machine */
void ble_ll_scan_sm_stop(int chk_disable);
/* Resume scanning */
void ble_ll_scan_chk_resume(void);
/* Called when wait for response timer expires in scanning mode */
void ble_ll_scan_wfr_timer_exp(void);
/* Called when scan could be interrupted */
void ble_ll_scan_interrupted(struct ble_ll_scan_sm *scansm);
int ble_ll_scan_adv_decode_addr(uint8_t pdu_type, uint8_t *rxbuf,
struct ble_mbuf_hdr *ble_hdr,
uint8_t **addr, uint8_t *addr_type,
uint8_t **inita, uint8_t *init_addr_type,
int *ext_mode);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
int ble_ll_scan_update_aux_data(struct ble_mbuf_hdr *ble_hdr, uint8_t *rxbuf,
bool *adva_present);
/* Initialize the extended scanner when we start initiating */
struct hci_ext_create_conn;
int ble_ll_scan_ext_initiator_start(struct hci_ext_create_conn *hcc,
struct ble_ll_scan_sm **sm);
/* Called to parse extended advertising*/
struct ble_ll_aux_data *ble_ll_scan_aux_data_ref(struct ble_ll_aux_data *aux_scan);
void ble_ll_scan_aux_data_unref(struct ble_ll_aux_data *aux_scan);
void ble_ll_scan_end_adv_evt(struct ble_ll_aux_data *aux_data);
#endif
/* Called to halt currently running scan */
void ble_ll_scan_halt(void);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_SCAN_ */

View File

@@ -0,0 +1,216 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_SCHED_
#define H_BLE_LL_SCHED_
#ifdef __cplusplus
extern "C" {
#endif
/* Time per BLE scheduler slot */
#define BLE_LL_SCHED_USECS_PER_SLOT (1250)
#define BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT (41) /* 1 tick = 30.517 usecs */
/*
* Worst case time needed for scheduled advertising item. This is the longest
* possible time to receive a scan request and send a scan response (with the
* appropriate IFS time between them). This number is calculated using the
* following formula: IFS + SCAN_REQ + IFS + SCAN_RSP = 150 + 176 + 150 + 376.
* Note: worst case time to tx adv, rx scan req and send scan rsp is 1228 usecs.
* This assumes maximum sized advertising PDU and scan response PDU.
*
* For connectable advertising events no scan request is allowed. In this case
* we just need to receive a connect request PDU: IFS + CONNECT_REQ = 150 + 352.
* Note: worst-case is 376 + 150 + 352 = 878 usecs
*
* NOTE: The advertising PDU transmit time is NOT included here since we know
* how long that will take (worst-case is 376 usecs).
*/
#define BLE_LL_SCHED_ADV_MAX_USECS (852)
#define BLE_LL_SCHED_DIRECT_ADV_MAX_USECS (502)
#define BLE_LL_SCHED_MAX_ADV_PDU_USECS (376)
/*
* This is the offset from the start of the scheduled item until the actual
* tx/rx should occur, in ticks.
*/
extern uint8_t g_ble_ll_sched_offset_ticks;
/*
* This is the number of slots needed to transmit and receive a maximum
* size PDU, including an IFS time before each. The actual time is
* 2120 usecs for tx/rx and 150 for IFS = 4540 usecs.
*/
#define BLE_LL_SCHED_MAX_TXRX_SLOT (4 * BLE_LL_SCHED_USECS_PER_SLOT)
/* BLE scheduler errors */
#define BLE_LL_SCHED_ERR_OVERLAP (1)
/* Types of scheduler events */
#define BLE_LL_SCHED_TYPE_ADV (1)
#define BLE_LL_SCHED_TYPE_SCAN (2)
#define BLE_LL_SCHED_TYPE_CONN (3)
#define BLE_LL_SCHED_TYPE_AUX_SCAN (4)
#define BLE_LL_SCHED_TYPE_DTM (5)
#define BLE_LL_SCHED_TYPE_PERIODIC (6)
#define BLE_LL_SCHED_TYPE_SYNC (7)
/* Return values for schedule callback. */
#define BLE_LL_SCHED_STATE_RUNNING (0)
#define BLE_LL_SCHED_STATE_DONE (1)
/* Callback function */
struct ble_ll_sched_item;
typedef int (*sched_cb_func)(struct ble_ll_sched_item *sch);
typedef void (*sched_remove_cb_func)(struct ble_ll_sched_item *sch);
/*
* Strict connection scheduling (for the master) is different than how
* connections are normally scheduled. With strict connection scheduling we
* introduce the concept of a "period". A period is a collection of slots. Each
* slot is 1.25 msecs in length. The number of slots in a period is determined
* by the syscfg value BLE_LL_CONN_INIT_SLOTS. A collection of periods is called
* an epoch. The length of an epoch is determined by the number of connections
* (BLE_MAX_CONNECTIONS plus BLE_LL_ADD_STRICT_SCHED_PERIODS). Connections
* will be scheduled at period boundaries. Any scanning/initiating/advertising
* will be done in unused periods, if possible.
*/
#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
#define BLE_LL_SCHED_PERIODS (MYNEWT_VAL(BLE_MAX_CONNECTIONS) + \
MYNEWT_VAL(BLE_LL_ADD_STRICT_SCHED_PERIODS))
struct ble_ll_sched_obj
{
uint8_t sch_num_occ_periods;
uint32_t sch_occ_period_mask;
uint32_t sch_ticks_per_period;
uint32_t sch_ticks_per_epoch;
uint32_t sch_epoch_start;
};
extern struct ble_ll_sched_obj g_ble_ll_sched_data;
/*
* XXX: TODO:
* -> How do we know epoch start is up to date? Not wrapped?
* -> for now, only do this with no more than 32 connections.
* -> Do not let initiating occur if no empty sched slots
*/
#endif
/*
* Schedule item
* sched_type: This is the type of the schedule item.
* enqueued: Flag denoting if item is on the scheduler list. 0: no, 1:yes
* remainder: # of usecs from offset till tx/rx should occur
* txrx_offset: Number of ticks from start time until tx/rx should occur.
*
*/
struct ble_ll_sched_item
{
uint8_t sched_type;
uint8_t enqueued;
uint8_t remainder;
uint32_t start_time;
uint32_t end_time;
void *cb_arg;
sched_cb_func sched_cb;
TAILQ_ENTRY(ble_ll_sched_item) link;
};
/* Initialize the scheduler */
int ble_ll_sched_init(void);
/* Remove item(s) from schedule */
int ble_ll_sched_rmv_elem(struct ble_ll_sched_item *sch);
void ble_ll_sched_rmv_elem_type(uint8_t type, sched_remove_cb_func remove_cb);
/* Schedule a new master connection */
struct ble_ll_conn_sm;
int ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len);
/* Schedule a new slave connection */
int ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm);
struct ble_ll_adv_sm;
typedef void ble_ll_sched_adv_new_cb(struct ble_ll_adv_sm *advsm,
uint32_t sch_start, void *arg);
/* Schedule a new advertising event */
int ble_ll_sched_adv_new(struct ble_ll_sched_item *sch,
ble_ll_sched_adv_new_cb cb, void *arg);
/* Schedule periodic advertising event */
int ble_ll_sched_periodic_adv(struct ble_ll_sched_item *sch, uint32_t *start,
bool after_overlap);
int ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch,
uint32_t anchor_point,
uint8_t anchor_point_usecs,
uint32_t window_widening, int8_t phy_mode);
int ble_ll_sched_sync(struct ble_ll_sched_item *sch,
uint32_t beg_cputime, uint32_t rem_usecs, uint32_t offset,
int8_t phy_mode);
/* Reschedule an advertising event */
int ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start,
uint32_t max_delay_ticks);
/* Reschedule and advertising pdu */
int ble_ll_sched_adv_resched_pdu(struct ble_ll_sched_item *sch);
/* Reschedule a connection that had previously been scheduled or that is over */
int ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm * connsm);
/**
* Called to determine when the next scheduled event will occur.
*
* If there are not scheduled events this function returns 0; otherwise it
* returns 1 and *next_event_time is set to the start time of the next event.
*
* @param next_event_time cputime at which next scheduled event will occur
*
* @return int 0: No events are scheduled 1: there is an upcoming event
*/
int ble_ll_sched_next_time(uint32_t *next_event_time);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
struct ble_ll_scan_sm;
struct ble_ll_aux_data;
int ble_ll_sched_aux_scan(struct ble_mbuf_hdr *ble_hdr,
struct ble_ll_scan_sm *scansm,
struct ble_ll_aux_data *aux_scan);
int ble_ll_sched_scan_req_over_aux_ptr(uint32_t chan, uint8_t phy_mode);
#endif
/* Stop the scheduler */
void ble_ll_sched_stop(void);
#if MYNEWT_VAL(BLE_LL_DTM)
int ble_ll_sched_dtm(struct ble_ll_sched_item *sch);
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_LL_SCHED_ */

View File

@@ -0,0 +1,74 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_SYNC_
#define H_BLE_LL_SYNC_
#include <stdint.h>
#include "nimble/nimble/include/nimble/ble.h"
#include "ble_ll_hci.h"
#include "ble_ll_conn.h"
#ifdef __cplusplus
extern "C" {
#endif
struct ble_ll_sync_sm;
int ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb);
int ble_ll_sync_terminate(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_sync_list_add(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_sync_list_clear(void);
int ble_ll_sync_list_size(uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_sync_receive_enable(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_sync_transfer(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
void ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm,
const uint8_t *sync_ind, bool reports_disabled,
uint16_t max_skip, uint32_t sync_timeout);
void ble_ll_sync_transfer_disconnected(struct ble_ll_conn_sm *connsm);
void ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type,
int rpa_index, uint8_t sid,
struct ble_mbuf_hdr *rxhdr,
const uint8_t *syncinfo);
int ble_ll_sync_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr);
int ble_ll_sync_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr);
void ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr);
void ble_ll_sync_wfr_timer_exp(void);
void ble_ll_sync_halt(void);
void ble_ll_sync_rmvd_from_sched(struct ble_ll_sync_sm *sm);
uint32_t ble_ll_sync_get_event_end_time(void);
bool ble_ll_sync_enabled(void);
void ble_ll_sync_reset(void);
void ble_ll_sync_init(void);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_SYNC_ */

View File

@@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_LL_TEST_
#define H_LL_TEST_
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
int ble_ll_csa2_test_all(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,96 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_TRACE_
#define H_BLE_LL_TRACE_
#include "nimble/porting/nimble/include/os/os_trace_api.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BLE_LL_TRACE_ID_SCHED 0
#define BLE_LL_TRACE_ID_RX_START 1
#define BLE_LL_TRACE_ID_RX_END 2
#define BLE_LL_TRACE_ID_WFR_EXP 3
#define BLE_LL_TRACE_ID_CTRL_RX 4
#define BLE_LL_TRACE_ID_CONN_EV_START 5
#define BLE_LL_TRACE_ID_CONN_EV_END 6
#define BLE_LL_TRACE_ID_CONN_END 7
#define BLE_LL_TRACE_ID_CONN_TX 8
#define BLE_LL_TRACE_ID_CONN_RX 9
#define BLE_LL_TRACE_ID_ADV_TXDONE 10
#define BLE_LL_TRACE_ID_ADV_HALT 11
#define BLE_LL_TRACE_ID_AUX_REF 12
#define BLE_LL_TRACE_ID_AUX_UNREF 13
#if MYNEWT_VAL(BLE_LL_SYSVIEW)
extern uint32_t ble_ll_trace_off;
void ble_ll_trace_init(void);
static inline void
ble_ll_trace_u32(unsigned id, uint32_t p1)
{
os_trace_api_u32(ble_ll_trace_off + id, p1);
}
static inline void
ble_ll_trace_u32x2(unsigned id, uint32_t p1, uint32_t p2)
{
os_trace_api_u32x2(ble_ll_trace_off + id, p1, p2);
}
static inline void
ble_ll_trace_u32x3(unsigned id, uint32_t p1, uint32_t p2, uint32_t p3)
{
os_trace_api_u32x3(ble_ll_trace_off + id, p1, p2, p3);
}
#else
static inline void
ble_ll_trace_init(void)
{
}
static inline void
ble_ll_trace_u32(unsigned id, uint32_t p1)
{
}
static inline void
ble_ll_trace_u32x2(unsigned id, uint32_t p1, uint32_t p2)
{
}
static inline void
ble_ll_trace_u32x3(unsigned id, uint32_t p1, uint32_t p2, uint32_t p3)
{
}
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_TRACE_ */

View File

@@ -0,0 +1,29 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <stdint.h>
uint32_t ble_ll_utils_calc_access_addr(void);
uint8_t ble_ll_utils_remapped_channel(uint8_t remap_index, const uint8_t *chanmap);
uint8_t ble_ll_utils_calc_dci_csa2(uint16_t event_cntr, uint16_t channel_id,
uint8_t num_used_chans, const uint8_t *chanmap);
uint8_t ble_ll_utils_calc_num_used_chans(const uint8_t *chanmap);
uint32_t ble_ll_utils_calc_window_widening(uint32_t anchor_point,
uint32_t last_anchor_point,
uint8_t master_sca);

View File

@@ -0,0 +1,52 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_WHITELIST_
#define H_BLE_LL_WHITELIST_
#ifdef __cplusplus
extern "C" {
#endif
/* Clear the whitelist */
int ble_ll_whitelist_clear(void);
/* Read the size of the whitelist */
int ble_ll_whitelist_read_size(uint8_t *rspbuf, uint8_t *rsplen);
/* Add a device to the whitelist */
int ble_ll_whitelist_add(const uint8_t *cmdbuf, uint8_t len);
/* Remove a device fromthe whitelist */
int ble_ll_whitelist_rmv(const uint8_t *cmdbuf, uint8_t len);
/* Enable whitelisting */
void ble_ll_whitelist_enable(void);
/* Disable whitelisting */
void ble_ll_whitelist_disable(void);
/* Boolean function returning true if address matches a whitelist entry */
int ble_ll_whitelist_match(uint8_t *addr, uint8_t addr_type, int is_ident);
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_WHITELIST_ */

View File

@@ -0,0 +1,242 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_PHY_
#define H_BLE_PHY_
#include "nimble/nimble/include/nimble/hci_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Forward declarations */
struct os_mbuf;
/* Channel/Frequency defintions */
#define BLE_PHY_NUM_CHANS (40)
#define BLE_PHY_NUM_DATA_CHANS (37)
#define BLE_PHY_CHAN0_FREQ_MHZ (2402)
#define BLE_PHY_DATA_CHAN0_FREQ_MHZ (2404)
#define BLE_PHY_CHAN_SPACING_MHZ (2)
#define BLE_PHY_NUM_ADV_CHANS (3)
#define BLE_PHY_ADV_CHAN_START (37)
/* Power */
#define BLE_PHY_MAX_PWR_DBM (10)
/* Deviation */
#define BLE_PHY_DEV_KHZ (185)
#define BLE_PHY_BINARY_ZERO (-BLE_PHY_DEV)
#define BLE_PHY_BINARY_ONE (BLE_PHY_DEV)
/* Max. clock drift */
#define BLE_PHY_MAX_DRIFT_PPM (50)
/* Data rate */
#define BLE_PHY_BIT_RATE_BPS (1000000)
/* Macros */
#define BLE_IS_ADV_CHAN(chan) (chan >= BLE_PHY_ADV_CHAN_START)
#define BLE_IS_DATA_CHAN(chan) (chan < BLE_PHY_ADV_CHAN_START)
/* PHY states */
#define BLE_PHY_STATE_IDLE (0)
#define BLE_PHY_STATE_RX (1)
#define BLE_PHY_STATE_TX (2)
/* BLE PHY transitions */
#define BLE_PHY_TRANSITION_NONE (0)
#define BLE_PHY_TRANSITION_RX_TX (1)
#define BLE_PHY_TRANSITION_TX_RX (2)
/* PHY error codes */
#define BLE_PHY_ERR_RADIO_STATE (1)
#define BLE_PHY_ERR_INIT (2)
#define BLE_PHY_ERR_INV_PARAM (3)
#define BLE_PHY_ERR_NO_BUFS (4)
#define BLE_PHY_ERR_TX_LATE (5)
#define BLE_PHY_ERR_RX_LATE (6)
/* Maximun PDU length. Includes LL header of 2 bytes and 255 bytes payload. */
#define BLE_PHY_MAX_PDU_LEN (257)
/* Wait for response timer */
typedef void (*ble_phy_tx_end_func)(void *arg);
/* Initialize the PHY */
int ble_phy_init(void);
/* Reset the PHY */
int ble_phy_reset(void);
/* Set the PHY channel */
int ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit);
/* Set transmit start time */
int ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs);
/* Set receive start time */
int ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs);
/* Set the transmit end callback and argument */
void ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg);
typedef uint8_t (*ble_phy_tx_pducb_t)(uint8_t *dptr, void *pducb_arg,
uint8_t *hdr_byte);
/* Place the PHY into transmit mode */
int ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans);
/* Place the PHY into receive mode */
int ble_phy_rx(void);
/* Copies the received PHY buffer into the allocated pdu */
void ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu);
/* Set the transmit power */
int ble_phy_txpwr_set(int dbm);
/* Get highest allowed power from range */
int ble_phy_txpower_round(int dbm);
/* Get the transmit power */
int ble_phy_txpwr_get(void);
/* Set RX path power compensation value rounded to integer dB */
void ble_phy_set_rx_pwr_compensation(int8_t compensation);
/* Disable the PHY */
void ble_phy_disable(void);
#define BLE_PHY_WFR_ENABLE_RX (0)
#define BLE_PHY_WFR_ENABLE_TXRX (1)
void ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs);
/* Starts rf clock */
void ble_phy_rfclk_enable(void);
/* Stops rf clock */
void ble_phy_rfclk_disable(void);
/*
* Used to restart reception on same channel after wfr timer expiration or
* frame received.
*/
void ble_phy_restart_rx(void);
/* Gets the current state of the PHY */
int ble_phy_state_get(void);
/* Gets current state of transceiver */
uint8_t ble_phy_xcvr_state_get(void);
/* Returns 'true' if a reception has started */
int ble_phy_rx_started(void);
/*
* Returns the maximum supported tx/rx PDU payload size, in bytes, for data
* channel PDUs (this does not apply to advertising channel PDUs). Note
* that the data channel PDU is composed of a 2-byte header, the payload, and
* an optional MIC. The maximum payload is 251 bytes.
*/
uint8_t ble_phy_max_data_pdu_pyld(void);
/* Gets the current access address */
uint32_t ble_phy_access_addr_get(void);
/* Enable encryption */
void ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key,
uint8_t is_master);
/* Disable encryption */
void ble_phy_encrypt_disable(void);
/* Set the packet counters and dir used by LE encyption */
void ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir);
/* Enable phy resolving list */
void ble_phy_resolv_list_enable(void);
/* Disable phy resolving list */
void ble_phy_resolv_list_disable(void);
/*
* PHY mode values for 1M, 2M and Coded S=8 are the same as corresponding values
* of PHY. This makes conversion between 'phy' and 'phy_mode' easier and it also
* means that default coding for Coded will be S=8, unless explicitly translated
* to S=2.
*/
#define BLE_PHY_MODE_CODED_500KBPS (0)
#define BLE_PHY_MODE_1M (1)
#define BLE_PHY_MODE_2M (2)
#define BLE_PHY_MODE_CODED_125KBPS (3)
/* The number of different modes */
#define BLE_PHY_NUM_MODE (4)
/* PHY numbers (compatible with HCI) */
#define BLE_PHY_1M (BLE_HCI_LE_PHY_1M)
#define BLE_PHY_2M (BLE_HCI_LE_PHY_2M)
#define BLE_PHY_CODED (BLE_HCI_LE_PHY_CODED)
/* PHY bitmasks (compatible with HCI) */
#define BLE_PHY_MASK_1M (BLE_HCI_LE_PHY_1M_PREF_MASK)
#define BLE_PHY_MASK_2M (BLE_HCI_LE_PHY_2M_PREF_MASK)
#define BLE_PHY_MASK_CODED (BLE_HCI_LE_PHY_CODED_PREF_MASK)
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY))
uint32_t ble_phy_mode_pdu_start_off(int phy);
void ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode);
#else
#define ble_phy_mode_pdu_start_off(phy) (40)
#endif
int ble_phy_get_cur_phy(void);
static inline int ble_ll_phy_to_phy_mode(int phy, int phy_options)
{
int phy_mode;
/*
* 'phy' value can be used as 'phy_mode' value unless S=2 coding is explicitly
* required. By default we'll use S=2 for Coded.
*/
phy_mode = phy;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
if (phy == BLE_PHY_CODED && phy_options == BLE_HCI_LE_PHY_CODED_S2_PREF) {
phy_mode = BLE_PHY_MODE_CODED_500KBPS;
}
#endif
return phy_mode;
}
#if MYNEWT_VAL(BLE_LL_DTM)
void ble_phy_enable_dtm(void);
void ble_phy_disable_dtm(void);
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_PHY_ */

View File

@@ -0,0 +1,96 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_PHY_TRACE_
#define H_BLE_PHY_TRACE_
#include "nimble/porting/nimble/include/os/os_trace_api.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BLE_PHY_TRACE_ID_START_TX 0
#define BLE_PHY_TRACE_ID_START_RX 1
#define BLE_PHY_TRACE_ID_DISABLE 2
#if MYNEWT_VAL(BLE_PHY_SYSVIEW)
extern uint32_t ble_phy_trace_off;
void ble_phy_trace_init(void);
static inline void
ble_phy_trace_void(unsigned id)
{
os_trace_api_void(ble_phy_trace_off + id);
}
static inline void
ble_phy_trace_u32(unsigned id, uint32_t p1)
{
os_trace_api_u32(ble_phy_trace_off + id, p1);
}
static inline void
ble_phy_trace_u32x2(unsigned id, uint32_t p1, uint32_t p2)
{
os_trace_api_u32x2(ble_phy_trace_off + id, p1, p2);
}
static inline void
ble_phy_trace_u32x3(unsigned id, uint32_t p1, uint32_t p2, uint32_t p3)
{
os_trace_api_u32x3(ble_phy_trace_off + id, p1, p2, p3);
}
#else
static inline void
ble_phy_trace_init(void)
{
}
static inline void
ble_phy_trace_void(unsigned id)
{
}
static inline void
ble_phy_trace_u32(unsigned id, uint32_t p1)
{
}
static inline void
ble_phy_trace_u32x2(unsigned id, uint32_t p1, uint32_t p2)
{
}
static inline void
ble_phy_trace_u32x3(unsigned id, uint32_t p1, uint32_t p2, uint32_t p3)
{
}
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_PHY_TRACE_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,226 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_CONN_PRIV_
#define H_BLE_LL_CONN_PRIV_
#include "../include/controller/ble_ll_conn.h"
#include "../include/controller/ble_ll_hci.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Definitions for min/max RX/TX time/bytes values allowed for connections.
* Source: Core 5.0 specification, Vol 6, Part B, section 4.5.10
*/
#define BLE_LL_CONN_SUPP_TIME_MIN (328) /* usecs */
#define BLE_LL_CONN_SUPP_TIME_MAX (17040) /* usecs */
#define BLE_LL_CONN_SUPP_TIME_MIN_UNCODED (328) /* usecs */
#define BLE_LL_CONN_SUPP_TIME_MAX_UNCODED (2120) /* usecs */
#define BLE_LL_CONN_SUPP_TIME_MIN_CODED (2704) /* usecs */
#define BLE_LL_CONN_SUPP_TIME_MAX_CODED (17040) /* usecs */
#define BLE_LL_CONN_SUPP_BYTES_MIN (27) /* bytes */
#define BLE_LL_CONN_SUPP_BYTES_MAX (251) /* bytes */
/* Connection event timing */
#define BLE_LL_CONN_INITIAL_OFFSET (1250)
#define BLE_LL_CONN_ITVL_USECS (1250)
#define BLE_LL_CONN_TX_WIN_USECS (1250)
#define BLE_LL_CONN_TX_OFF_USECS (1250)
#define BLE_LL_CONN_CE_USECS (625)
#define BLE_LL_CONN_TX_WIN_MIN (1) /* in tx win units */
#define BLE_LL_CONN_SLAVE_LATENCY_MAX (499)
/* Connection handle range */
#define BLE_LL_CONN_MAX_CONN_HANDLE (0x0EFF)
/* Offset (in bytes) of advertising address in connect request */
#define BLE_LL_CONN_REQ_ADVA_OFF (BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN)
/* Default authenticated payload timeout (30 seconds; in 10 msecs increments) */
#define BLE_LL_CONN_DEF_AUTH_PYLD_TMO (3000)
#define BLE_LL_CONN_AUTH_PYLD_OS_TMO(x) ble_npl_time_ms_to_ticks32((x) * 10)
/* Global Link Layer connection parameters */
struct ble_ll_conn_global_params
{
uint8_t master_chan_map[BLE_LL_CONN_CHMAP_LEN];
uint8_t num_used_chans;
uint8_t supp_max_tx_octets;
uint8_t supp_max_rx_octets;
uint8_t conn_init_max_tx_octets;
uint8_t sugg_tx_octets;
uint16_t sugg_tx_time;
uint16_t conn_init_max_tx_time;
uint16_t conn_init_max_tx_time_uncoded;
uint16_t conn_init_max_tx_time_coded;
uint16_t supp_max_tx_time;
uint16_t supp_max_rx_time;
};
extern struct ble_ll_conn_global_params g_ble_ll_conn_params;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
struct ble_ll_conn_sync_transfer_params
{
uint32_t sync_timeout_us;
uint16_t max_skip;
uint8_t mode;
};
extern struct ble_ll_conn_sync_transfer_params g_ble_ll_conn_sync_transfer_params;
#endif
/* Some data structures used by other LL routines */
SLIST_HEAD(ble_ll_conn_active_list, ble_ll_conn_sm);
STAILQ_HEAD(ble_ll_conn_free_list, ble_ll_conn_sm);
extern struct ble_ll_conn_active_list g_ble_ll_conn_active_list;
extern struct ble_ll_conn_free_list g_ble_ll_conn_free_list;
/* Pointer to connection state machine we are trying to create */
extern struct ble_ll_conn_sm *g_ble_ll_conn_create_sm;
/* Generic interface */
struct ble_ll_len_req;
struct ble_mbuf_hdr;
struct ble_ll_adv_sm;
struct hci_create_conn
{
uint16_t scan_itvl;
uint16_t scan_window;
uint8_t filter_policy;
uint8_t peer_addr_type;
uint8_t peer_addr[BLE_DEV_ADDR_LEN];
uint8_t own_addr_type;
uint16_t conn_itvl_min;
uint16_t conn_itvl_max;
uint16_t conn_latency;
uint16_t supervision_timeout;
uint16_t min_ce_len;
uint16_t max_ce_len;
};
void ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm);
void ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err);
void ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om,
uint8_t hdr_byte, uint8_t length);
struct ble_ll_conn_sm *ble_ll_conn_sm_get(void);
void ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm,
struct hci_create_conn *hcc);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
void ble_ll_conn_ext_master_init(struct ble_ll_conn_sm *connsm,
struct hci_ext_create_conn *hcc);
void ble_ll_conn_ext_set_params(struct ble_ll_conn_sm *connsm,
struct hci_ext_conn_params *hcc_params,
int phy);
#endif
struct ble_ll_conn_sm *ble_ll_conn_find_active_conn(uint16_t handle);
void ble_ll_conn_update_eff_data_len(struct ble_ll_conn_sm *connsm);
/* Advertising interface */
int ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat,
struct ble_mbuf_hdr *rxhdr, bool force_csa2);
/* Link Layer interface */
void ble_ll_conn_module_init(void);
void ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, const uint8_t *chanmap);
void ble_ll_conn_module_reset(void);
void ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t len);
int ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa);
int ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr);
void ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr);
void ble_ll_init_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf,
struct ble_mbuf_hdr *ble_hdr);
int ble_ll_init_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *ble_hdr);
int ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok,
struct ble_mbuf_hdr *ble_hdr);
void ble_ll_conn_wfr_timer_exp(void);
void ble_ll_conn_init_wfr_timer_exp(void);
int ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2);
uint32_t ble_ll_conn_get_ce_end_time(void);
void ble_ll_conn_event_halt(void);
void ble_ll_conn_reset_pending_aux_conn_rsp(void);
bool ble_ll_conn_init_pending_aux_conn_rsp(void);
/* HCI */
void ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm,
uint8_t reason);
void ble_ll_auth_pyld_tmo_event_send(struct ble_ll_conn_sm *connsm);
int ble_ll_conn_hci_disconnect_cmd(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_rd_rem_ver_cmd(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_set_chan_class(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_param_rr(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_param_nrr(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb);
void ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm *connsm);
void ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status,
uint8_t *evbuf, struct ble_ll_adv_sm *advsm);
void ble_ll_conn_timeout(struct ble_ll_conn_sm *connsm, uint8_t ble_err);
int ble_ll_conn_hci_chk_conn_params(uint16_t itvl_min, uint16_t itvl_max,
uint16_t latency, uint16_t spvn_tmo);
int ble_ll_conn_hci_read_rem_features(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_rd_rssi(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf,
uint8_t *rsplen);
int ble_ll_conn_hci_rd_chan_map(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_set_data_len(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_le_start_encrypt(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_le_ltk_reply(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_le_ltk_neg_reply(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_wr_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_rd_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING)
void ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm);
#else
#define ble_ll_conn_auth_pyld_timer_start(x)
#endif
int ble_ll_hci_cmd_rx(uint8_t *cmd, void *arg);
int ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg);
int ble_ll_conn_hci_le_rd_phy(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rsp, uint8_t *rsplen);
int ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_chk_phy_upd_start(struct ble_ll_conn_sm *connsm);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
int ble_ll_ext_conn_create(const uint8_t *cmdbuf, uint8_t cmdlen);
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
int ble_ll_set_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_set_default_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len);
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_CONN_PRIV_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,728 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef ESP_PLATFORM
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#include "nimble/porting/nimble/include/sysinit/sysinit.h"
#if MYNEWT_VAL(BLE_LL_DTM)
#include <assert.h>
#include "nimble/porting/nimble/include/os/os.h"
#include "nimble/nimble/porting/nimble/include/stats/stats.h"
#include "../include/controller/ble_ll.h"
#include "../include/controller/ble_phy.h"
#include "../include/controller/ble_ll_sched.h"
#include "../include/controller/ble_ll_rfmgmt.h"
#include "ble_ll_dtm_priv.h"
STATS_SECT_START(ble_ll_dtm_stats)
STATS_SECT_ENTRY(rx_count)
STATS_SECT_ENTRY(tx_failed)
STATS_SECT_ENTRY(rx_failed)
STATS_SECT_END
STATS_SECT_DECL(ble_ll_dtm_stats) ble_ll_dtm_stats;
STATS_NAME_START(ble_ll_dtm_stats)
STATS_NAME(ble_ll_dtm_stats, rx_count)
STATS_NAME(ble_ll_dtm_stats, tx_failed)
STATS_NAME(ble_ll_dtm_stats, rx_failed)
STATS_NAME_END(ble_phy_stats)
struct dtm_ctx {
uint8_t payload_packet;
uint8_t itvl_rem_usec;
uint16_t num_of_packets;
uint32_t itvl_ticks;
#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS)
uint16_t num_of_packets_max;
#endif
int active;
uint8_t rf_channel;
uint8_t phy_mode;
struct os_mbuf *om;
struct ble_npl_event evt;
struct ble_ll_sched_item sch;
uint32_t pdu_start_ticks;
uint8_t pdu_start_usecs;
};
static struct dtm_ctx g_ble_ll_dtm_ctx;
static const uint8_t g_ble_ll_dtm_prbs9_data[] =
{
0xff, 0xc1, 0xfb, 0xe8, 0x4c, 0x90, 0x72, 0x8b,
0xe7, 0xb3, 0x51, 0x89, 0x63, 0xab, 0x23, 0x23,
0x02, 0x84, 0x18, 0x72, 0xaa, 0x61, 0x2f, 0x3b,
0x51, 0xa8, 0xe5, 0x37, 0x49, 0xfb, 0xc9, 0xca,
0x0c, 0x18, 0x53, 0x2c, 0xfd, 0x45, 0xe3, 0x9a,
0xe6, 0xf1, 0x5d, 0xb0, 0xb6, 0x1b, 0xb4, 0xbe,
0x2a, 0x50, 0xea, 0xe9, 0x0e, 0x9c, 0x4b, 0x5e,
0x57, 0x24, 0xcc, 0xa1, 0xb7, 0x59, 0xb8, 0x87,
0xff, 0xe0, 0x7d, 0x74, 0x26, 0x48, 0xb9, 0xc5,
0xf3, 0xd9, 0xa8, 0xc4, 0xb1, 0xd5, 0x91, 0x11,
0x01, 0x42, 0x0c, 0x39, 0xd5, 0xb0, 0x97, 0x9d,
0x28, 0xd4, 0xf2, 0x9b, 0xa4, 0xfd, 0x64, 0x65,
0x06, 0x8c, 0x29, 0x96, 0xfe, 0xa2, 0x71, 0x4d,
0xf3, 0xf8, 0x2e, 0x58, 0xdb, 0x0d, 0x5a, 0x5f,
0x15, 0x28, 0xf5, 0x74, 0x07, 0xce, 0x25, 0xaf,
0x2b, 0x12, 0xe6, 0xd0, 0xdb, 0x2c, 0xdc, 0xc3,
0x7f, 0xf0, 0x3e, 0x3a, 0x13, 0xa4, 0xdc, 0xe2,
0xf9, 0x6c, 0x54, 0xe2, 0xd8, 0xea, 0xc8, 0x88,
0x00, 0x21, 0x86, 0x9c, 0x6a, 0xd8, 0xcb, 0x4e,
0x14, 0x6a, 0xf9, 0x4d, 0xd2, 0x7e, 0xb2, 0x32,
0x03, 0xc6, 0x14, 0x4b, 0x7f, 0xd1, 0xb8, 0xa6,
0x79, 0x7c, 0x17, 0xac, 0xed, 0x06, 0xad, 0xaf,
0x0a, 0x94, 0x7a, 0xba, 0x03, 0xe7, 0x92, 0xd7,
0x15, 0x09, 0x73, 0xe8, 0x6d, 0x16, 0xee, 0xe1,
0x3f, 0x78, 0x1f, 0x9d, 0x09, 0x52, 0x6e, 0xf1,
0x7c, 0x36, 0x2a, 0x71, 0x6c, 0x75, 0x64, 0x44,
0x80, 0x10, 0x43, 0x4e, 0x35, 0xec, 0x65, 0x27,
0x0a, 0xb5, 0xfc, 0x26, 0x69, 0x3f, 0x59, 0x99,
0x01, 0x63, 0x8a, 0xa5, 0xbf, 0x68, 0x5c, 0xd3,
0x3c, 0xbe, 0x0b, 0xd6, 0x76, 0x83, 0xd6, 0x57,
0x05, 0x4a, 0x3d, 0xdd, 0x81, 0x73, 0xc9, 0xeb,
0x8a, 0x84, 0x39, 0xf4, 0x36, 0x0b, 0xf7
};
static const uint8_t g_ble_ll_dtm_prbs15_data[] =
{
0xff, 0x7f, 0xf0, 0x3e, 0x3a, 0x13, 0xa4, 0xdc,
0xe2, 0xf9, 0x6c, 0x54, 0xe2, 0xd8, 0xea, 0xc8,
0x88, 0x00, 0x21, 0x86, 0x9c, 0x6a, 0xd8, 0xcb,
0x4e, 0x14, 0x6a, 0xf9, 0x4d, 0xd2, 0x7e, 0xb2,
0x32, 0x03, 0xc6, 0x14, 0x4b, 0x7f, 0xd1, 0xb8,
0xa6, 0x79, 0x7c, 0x17, 0xac, 0xed, 0x06, 0xad,
0xaf, 0x0a, 0x94, 0x7a, 0xba, 0x03, 0xe7, 0x92,
0xd7, 0x15, 0x09, 0x73, 0xe8, 0x6d, 0x16, 0xee,
0xe1, 0x3f, 0x78, 0x1f, 0x9d, 0x09, 0x52, 0x6e,
0xf1, 0x7c, 0x36, 0x2a, 0x71, 0x6c, 0x75, 0x64,
0x44, 0x80, 0x10, 0x43, 0x4e, 0x35, 0xec, 0x65,
0x27, 0x0a, 0xb5, 0xfc, 0x26, 0x69, 0x3f, 0x59,
0x99, 0x01, 0x63, 0x8a, 0xa5, 0xbf, 0x68, 0x5c,
0xd3, 0x3c, 0xbe, 0x0b, 0xd6, 0x76, 0x83, 0xd6,
0x57, 0x05, 0x4a, 0x3d, 0xdd, 0x81, 0x73, 0xc9,
0xeb, 0x8a, 0x84, 0x39, 0xf4, 0x36, 0x0b, 0xf7,
0xf0, 0x1f, 0xbc, 0x8f, 0xce, 0x04, 0x29, 0xb7,
0x78, 0x3e, 0x1b, 0x95, 0x38, 0xb6, 0x3a, 0x32,
0x22, 0x40, 0x88, 0x21, 0xa7, 0x1a, 0xf6, 0xb2,
0x13, 0x85, 0x5a, 0x7e, 0x93, 0xb4, 0x9f, 0xac,
0xcc, 0x80, 0x31, 0xc5, 0xd2, 0x5f, 0x34, 0xae,
0x69, 0x1e, 0xdf, 0x05, 0x6b, 0xbb, 0x41, 0xeb,
0xab, 0x02, 0xa5, 0x9e, 0xee, 0xc0, 0xb9, 0xe4,
0x75, 0x45, 0xc2, 0x1c, 0x7a, 0x9b, 0x85, 0x7b,
0xf8, 0x0f, 0xde, 0x47, 0x67, 0x82, 0x94, 0x5b,
0x3c, 0x9f, 0x8d, 0x4a, 0x1c, 0x5b, 0x1d, 0x19,
0x11, 0x20, 0xc4, 0x90, 0x53, 0x0d, 0x7b, 0xd9,
0x89, 0x42, 0x2d, 0xbf, 0x49, 0xda, 0x4f, 0x56,
0x66, 0xc0, 0x98, 0x62, 0xe9, 0x2f, 0x1a, 0xd7,
0x34, 0x8f, 0xef, 0x82, 0xb5, 0xdd, 0xa0, 0xf5,
0x55, 0x81, 0x52, 0x4f, 0x77, 0xe0, 0x5c, 0xf2,
0xba, 0x22, 0x61, 0x0e, 0xbd, 0xcd, 0xc2
};
static const uint8_t channel_rf_to_index[] = {
37, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 38, 11 ,12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 39
};
#define BLE_DTM_SYNC_WORD (0x71764129)
#define BLE_DTM_CRC (0x555555)
static void ble_ll_dtm_ctx_free(struct dtm_ctx * ctx);
static void
ble_ll_dtm_set_next(struct dtm_ctx *ctx)
{
struct ble_ll_sched_item *sch = &ctx->sch;
ctx->pdu_start_ticks += ctx->itvl_ticks;
ctx->pdu_start_usecs += ctx->itvl_rem_usec;
if (ctx->pdu_start_usecs >= 31) {
ctx->pdu_start_ticks++;
ctx->pdu_start_usecs -= 31;
}
sch->start_time = ctx->pdu_start_ticks;
sch->remainder = ctx->pdu_start_usecs;
sch->start_time -= g_ble_ll_sched_offset_ticks;
}
static void
ble_ll_dtm_ev_tx_resched_cb(struct ble_npl_event *evt) {
/* It is called in LL context */
struct dtm_ctx *ctx = ble_npl_event_get_arg(evt);
int rc;
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
if (!ctx->active || !ctx->om) {
OS_EXIT_CRITICAL(sr);
return;
}
OS_EXIT_CRITICAL(sr);
#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS)
if (g_ble_ll_dtm_ctx.num_of_packets_max &&
(g_ble_ll_dtm_ctx.num_of_packets == g_ble_ll_dtm_ctx.num_of_packets_max)) {
/*
* XXX do not send more packets, but also do not stop DTM - it shall be
* stopped as usual by HCI command since there is no standard way to
* signal end of test to host.
*/
return;
}
#endif
ble_ll_dtm_set_next(ctx);
rc = ble_ll_sched_dtm(&ctx->sch);
BLE_LL_ASSERT(rc == 0);
}
static int ble_ll_dtm_rx_start(void);
static void
ble_ll_dtm_ev_rx_restart_cb(struct ble_npl_event *evt) {
if (ble_ll_dtm_rx_start() != 0) {
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt);
STATS_INC(ble_ll_dtm_stats, rx_failed);
}
}
static void
ble_ll_dtm_tx_done(void *arg)
{
struct dtm_ctx *ctx;
ctx = arg;
if (!ctx->active) {
return;
}
g_ble_ll_dtm_ctx.num_of_packets++;
/* Reschedule event in LL context */
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &ctx->evt);
ble_ll_state_set(BLE_LL_STATE_STANDBY);
}
static int
ble_ll_dtm_tx_sched_cb(struct ble_ll_sched_item *sch)
{
struct dtm_ctx *ctx = sch->cb_arg;
int rc;
if (!ctx->active) {
return BLE_LL_SCHED_STATE_DONE;
}
rc = ble_phy_setchan(channel_rf_to_index[ctx->rf_channel],
BLE_DTM_SYNC_WORD, BLE_DTM_CRC);
if (rc != 0) {
BLE_LL_ASSERT(0);
return BLE_LL_SCHED_STATE_DONE;
}
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY))
ble_phy_mode_set(ctx->phy_mode, ctx->phy_mode);
#endif
ble_phy_set_txend_cb(ble_ll_dtm_tx_done, ctx);
ble_phy_txpwr_set(0);
sch->start_time += g_ble_ll_sched_offset_ticks;
rc = ble_phy_tx_set_start_time(sch->start_time, sch->remainder);
if (rc) {
goto resched;
}
rc = ble_phy_tx(ble_ll_tx_mbuf_pducb, ctx->om, BLE_PHY_TRANSITION_NONE);
if (rc) {
goto resched;
}
ble_ll_state_set(BLE_LL_STATE_DTM);
return BLE_LL_SCHED_STATE_DONE;
resched:
/* Reschedule from LL task if late for this PDU */
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &ctx->evt);
STATS_INC(ble_ll_dtm_stats, tx_failed);
return BLE_LL_SCHED_STATE_DONE;
}
static void
ble_ll_dtm_calculate_itvl(struct dtm_ctx *ctx, uint8_t len,
uint16_t cmd_interval, int phy_mode)
{
uint32_t l;
uint32_t itvl_usec;
uint32_t itvl_ticks;
/* Calculate interval as per spec Bluetooth 5.0 Vol 6. Part F, 4.1.6 */
l = ble_ll_pdu_tx_time_get(len + BLE_LL_PDU_HDR_LEN, phy_mode);
itvl_usec = ((l + 249 + 624) / 625) * 625;
#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS)
if (cmd_interval > itvl_usec) {
itvl_usec = cmd_interval;
}
#endif
itvl_ticks = os_cputime_usecs_to_ticks(itvl_usec);
ctx->itvl_rem_usec = (itvl_usec - os_cputime_ticks_to_usecs(itvl_ticks));
if (ctx->itvl_rem_usec == 31) {
ctx->itvl_rem_usec = 0;
++itvl_ticks;
}
ctx->itvl_ticks = itvl_ticks;
}
static int
ble_ll_dtm_tx_create_ctx(uint8_t packet_payload, uint8_t len,
uint8_t rf_channel, uint8_t phy_mode,
uint16_t cmd_interval, uint16_t cmd_pkt_count)
{
int rc = 0;
uint8_t byte_pattern;
struct ble_mbuf_hdr *ble_hdr;
struct os_mbuf *m;
struct dtm_ctx *ctx = &g_ble_ll_dtm_ctx;
struct ble_ll_sched_item *sch = &ctx->sch;
/* MSYS is big enough to get continues memory */
m = os_msys_get_pkthdr(len, sizeof(struct ble_mbuf_hdr));
ctx->om = m;
BLE_LL_ASSERT(g_ble_ll_dtm_ctx.om);
ctx->phy_mode = phy_mode;
ctx->rf_channel = rf_channel;
ctx->num_of_packets = 0;
#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS)
ctx->num_of_packets_max = cmd_pkt_count;
#endif
/* Set BLE transmit header */
ble_hdr = BLE_MBUF_HDR_PTR(m);
ble_hdr->txinfo.flags = 0;
ble_hdr->txinfo.offset = 0;
ble_hdr->txinfo.pyld_len = len;
ble_hdr->txinfo.hdr_byte = packet_payload;
switch(packet_payload) {
case 0x00:
if (os_mbuf_copyinto(m, 0, &g_ble_ll_dtm_prbs9_data, len)) {
return 1;
}
goto schedule;
case 0x01:
byte_pattern = 0x0F;
break;
case 0x02:
byte_pattern = 0x55;
break;
case 0x03:
if (os_mbuf_copyinto(m, 0, &g_ble_ll_dtm_prbs15_data, len)) {
return 1;
}
goto schedule;
case 0x04:
byte_pattern = 0xFF;
break;
case 0x05:
byte_pattern = 0x00;
break;
case 0x06:
byte_pattern = 0xF0;
break;
case 0x07:
byte_pattern = 0xAA;
break;
default:
return 1;
}
for (rc = 0; rc < len; rc++) {
if (os_mbuf_copyinto(m, rc, &byte_pattern, 1)) {
return 1;
}
}
schedule:
ble_phy_enable_dtm();
sch->sched_cb = ble_ll_dtm_tx_sched_cb;
sch->cb_arg = ctx;
sch->sched_type = BLE_LL_SCHED_TYPE_DTM;
/* Prepare os_event */
ble_npl_event_init(&ctx->evt, ble_ll_dtm_ev_tx_resched_cb, ctx);
ble_ll_dtm_calculate_itvl(ctx, len, cmd_interval, phy_mode);
ctx->pdu_start_ticks = ble_ll_rfmgmt_enable_now();
ctx->pdu_start_usecs = 0;
ble_ll_dtm_set_next(ctx);
/* Set some start point for TX packets */
rc = ble_ll_sched_dtm(sch);
BLE_LL_ASSERT(rc == 0);
g_ble_ll_dtm_ctx.active = 1;
return 0;
}
static int
ble_ll_dtm_rx_start(void)
{
os_sr_t sr;
int rc;
rc = ble_phy_setchan(channel_rf_to_index[g_ble_ll_dtm_ctx.rf_channel],
BLE_DTM_SYNC_WORD, BLE_DTM_CRC);
if (rc) {
return rc;
}
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY))
ble_phy_mode_set(g_ble_ll_dtm_ctx.phy_mode, g_ble_ll_dtm_ctx.phy_mode);
#endif
OS_ENTER_CRITICAL(sr);
rc = ble_phy_rx_set_start_time(os_cputime_get32(), 0);
OS_EXIT_CRITICAL(sr);
if (rc && rc != BLE_PHY_ERR_RX_LATE) {
return rc;
}
ble_ll_state_set(BLE_LL_STATE_DTM);
return 0;
}
static int
ble_ll_dtm_rx_sched_cb(struct ble_ll_sched_item *sch)
{
if (ble_ll_dtm_rx_start() != 0) {
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt);
STATS_INC(ble_ll_dtm_stats, rx_failed);
}
return BLE_LL_SCHED_STATE_DONE;
}
static int
ble_ll_dtm_rx_create_ctx(uint8_t rf_channel, uint8_t phy_mode)
{
struct ble_ll_sched_item *sch = &g_ble_ll_dtm_ctx.sch;
int rc;
g_ble_ll_dtm_ctx.phy_mode = phy_mode;
g_ble_ll_dtm_ctx.rf_channel = rf_channel;
STATS_CLEAR(ble_ll_dtm_stats, rx_count);
ble_npl_event_init(&g_ble_ll_dtm_ctx.evt, ble_ll_dtm_ev_rx_restart_cb,
NULL);
sch->sched_cb = ble_ll_dtm_rx_sched_cb;
sch->cb_arg = &g_ble_ll_dtm_ctx;
sch->sched_type = BLE_LL_SCHED_TYPE_DTM;
sch->start_time = ble_ll_rfmgmt_enable_now();
rc = ble_ll_sched_dtm(sch);
BLE_LL_ASSERT(rc == 0);
ble_phy_enable_dtm();
g_ble_ll_dtm_ctx.active = 1;
return 0;
}
static void
ble_ll_dtm_ctx_free(struct dtm_ctx * ctx)
{
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
if (!ctx->active) {
OS_EXIT_CRITICAL(sr);
return;
}
ble_ll_sched_rmv_elem(&ctx->sch);
ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt);
ble_phy_disable();
ble_phy_disable_dtm();
ble_ll_state_set(BLE_LL_STATE_STANDBY);
ble_ll_rfmgmt_release();
os_mbuf_free_chain(ctx->om);
memset(ctx, 0, sizeof(*ctx));
OS_EXIT_CRITICAL(sr);
}
static int
ble_ll_dtm_tx_test(uint8_t tx_chan, uint8_t len, uint8_t packet_payload,
uint8_t hci_phy, uint16_t interval, uint16_t pkt_count)
{
uint8_t phy_mode;
if (g_ble_ll_dtm_ctx.active) {
return BLE_ERR_CTLR_BUSY;
}
switch (hci_phy) {
case BLE_HCI_LE_PHY_1M:
phy_mode = BLE_PHY_MODE_1M;
break;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
case BLE_HCI_LE_PHY_2M:
phy_mode = BLE_PHY_MODE_2M;
break;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
case BLE_HCI_LE_PHY_CODED_S8:
phy_mode = BLE_PHY_MODE_CODED_125KBPS;
break;
case BLE_HCI_LE_PHY_CODED_S2:
phy_mode = BLE_PHY_MODE_CODED_500KBPS;
break;
#endif
default:
return BLE_ERR_INV_HCI_CMD_PARMS;
}
if (tx_chan > 0x27 || packet_payload > 0x07) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
if (ble_ll_dtm_tx_create_ctx(packet_payload, len, tx_chan, phy_mode,
interval, pkt_count)) {
return BLE_ERR_UNSPECIFIED;
}
return BLE_ERR_SUCCESS;
}
#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS)
static int
ble_ll_hci_dtm_tx_test_ext(const uint8_t *cmdbuf)
{
const struct ble_hci_le_tx_test_ext_cp *cmd = (const void *) cmdbuf;
return ble_ll_dtm_tx_test(cmd->tx_chan, cmd->test_data_len, cmd->payload,
BLE_HCI_LE_PHY_1M, le16toh(cmd->interval),
le16toh(cmd->pkt_count));
}
static int
ble_ll_hci_dtm_tx_test_v2_ext(const uint8_t *cmdbuf)
{
const struct ble_hci_le_tx_test_v2_ext_cp *cmd = (const void *) cmdbuf;
return ble_ll_dtm_tx_test(cmd->tx_chan, cmd->test_data_len, cmd->payload,
cmd->phy, le16toh(cmd->interval),
le16toh(cmd->pkt_count));
}
#endif
int
ble_ll_hci_dtm_tx_test(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_tx_test_cp *cmd = (const void *) cmdbuf;
#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS)
if (len == sizeof(struct ble_hci_le_tx_test_ext_cp)) {
return ble_ll_hci_dtm_tx_test_ext(cmdbuf);
}
#endif
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
return ble_ll_dtm_tx_test(cmd->tx_chan, cmd->test_data_len, cmd->payload,
BLE_HCI_LE_PHY_1M, 0, 0);
}
int
ble_ll_hci_dtm_tx_test_v2(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_tx_test_v2_cp *cmd = (const void *) cmdbuf;
#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS)
if (len == sizeof(struct ble_hci_le_tx_test_v2_ext_cp)) {
return ble_ll_hci_dtm_tx_test_v2_ext(cmdbuf);
}
#endif
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
return ble_ll_dtm_tx_test(cmd->tx_chan, cmd->test_data_len, cmd->payload,
cmd->phy, 0, 0);
}
static int
ble_ll_dtm_rx_test(uint8_t rx_chan, uint8_t hci_phy)
{
uint8_t phy_mode;
if (g_ble_ll_dtm_ctx.active) {
return BLE_ERR_CTLR_BUSY;
}
switch (hci_phy) {
case BLE_HCI_LE_PHY_1M:
phy_mode = BLE_PHY_MODE_1M;
break;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
case BLE_HCI_LE_PHY_2M:
phy_mode = BLE_PHY_MODE_2M;
break;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
case BLE_HCI_LE_PHY_CODED:
phy_mode = BLE_PHY_MODE_CODED_500KBPS;
break;
#endif
default:
return BLE_ERR_INV_HCI_CMD_PARMS;
}
if (rx_chan > 0x27) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
if (ble_ll_dtm_rx_create_ctx(rx_chan, phy_mode)) {
return BLE_ERR_UNSPECIFIED;
}
return BLE_ERR_SUCCESS;
}
int ble_ll_hci_dtm_rx_test(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_rx_test_cp *cmd = (const void *) cmdbuf;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
return ble_ll_dtm_rx_test(cmd->rx_chan, BLE_HCI_LE_PHY_1M);
}
int ble_ll_hci_dtm_rx_test_v2(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_rx_test_v2_cp *cmd = (const void *) cmdbuf;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* TODO ignoring modulation index */
return ble_ll_dtm_rx_test(cmd->rx_chan, cmd->phy);
}
int ble_ll_dtm_end_test(uint8_t *rsp, uint8_t *rsplen)
{
put_le16(rsp, g_ble_ll_dtm_ctx. num_of_packets);
*rsplen = 2;
ble_ll_dtm_ctx_free(&g_ble_ll_dtm_ctx);
return BLE_ERR_SUCCESS;
}
int ble_ll_dtm_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa)
{
return 0;
}
void
ble_ll_dtm_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
{
if (BLE_MBUF_HDR_CRC_OK(hdr)) {
/* XXX Compare data. */
g_ble_ll_dtm_ctx.num_of_packets++;
STATS_INC(ble_ll_dtm_stats, rx_count);
}
if (ble_ll_dtm_rx_start() != 0) {
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt);
STATS_INC(ble_ll_dtm_stats, rx_failed);
}
}
int
ble_ll_dtm_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
{
struct os_mbuf *rxpdu;
if (!g_ble_ll_dtm_ctx.active) {
return -1;
}
rxpdu = ble_ll_rxpdu_alloc(rxbuf[1] + BLE_LL_PDU_HDR_LEN);
/* Copy the received pdu and hand it up */
if (rxpdu) {
ble_phy_rxpdu_copy(rxbuf, rxpdu);
ble_ll_rx_pdu_in(rxpdu);
}
return 0;
}
void
ble_ll_dtm_wfr_timer_exp(void)
{
/* Should not be needed */
BLE_LL_ASSERT(0);
}
void
ble_ll_dtm_reset(void)
{
ble_ll_dtm_ctx_free(&g_ble_ll_dtm_ctx);
}
void
ble_ll_dtm_init(void)
{
int rc;
rc = stats_init_and_reg(STATS_HDR(ble_ll_dtm_stats),
STATS_SIZE_INIT_PARMS(ble_ll_dtm_stats, STATS_SIZE_32),
STATS_NAME_INIT_PARMS(ble_ll_dtm_stats),
"ble_ll_dtm");
SYSINIT_PANIC_ASSERT(rc == 0);
}
#endif
#endif

View File

@@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_TEST_PRIV_
#define H_BLE_LL_TEST_PRIV_
#include <stdint.h>
#include <stdbool.h>
#include "nimble/ble.h"
int ble_ll_hci_dtm_tx_test(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_hci_dtm_tx_test_v2(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_hci_dtm_rx_test(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_hci_dtm_rx_test_v2(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_dtm_end_test(uint8_t *rsp, uint8_t *rsplen);
int ble_ll_dtm_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa);
int ble_ll_dtm_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr);
void ble_ll_dtm_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr);
void ble_ll_dtm_wfr_timer_exp(void);
void ble_ll_dtm_reset(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,526 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef ESP_PLATFORM
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#include "nimble/nimble/include/nimble/ble.h"
#include "nimble/nimble/include/nimble/hci_common.h"
#include "nimble/nimble/include/nimble/ble_hci_trans.h"
#include "../include/controller/ble_ll.h"
#include "../include/controller/ble_ll_hci.h"
#include "../include/controller/ble_ll_ctrl.h"
#include "ble_ll_conn_priv.h"
#if (BLETEST_CONCURRENT_CONN_TEST == 1)
extern void bletest_ltk_req_reply(uint16_t handle);
#endif
/**
* Send a data length change event for a connection to the host.
*
* @param connsm Pointer to connection state machine
*/
void
ble_ll_hci_ev_datalen_chg(struct ble_ll_conn_sm *connsm)
{
struct ble_hci_ev_le_subev_data_len_chg *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_DATA_LEN_CHG)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_DATA_LEN_CHG;
ev->conn_handle = htole16(connsm->conn_handle);
ev->max_tx_octets = htole16(connsm->eff_max_tx_octets);
ev->max_tx_time = htole16(connsm->eff_max_tx_time);
ev->max_rx_octets = htole16(connsm->eff_max_rx_octets);
ev->max_rx_time = htole16(connsm->eff_max_rx_time);
ble_ll_hci_event_send(hci_ev);
}
}
}
/**
* Send a connection parameter request event for a connection to the host.
*
* @param connsm Pointer to connection state machine
*/
void
ble_ll_hci_ev_rem_conn_parm_req(struct ble_ll_conn_sm *connsm,
struct ble_ll_conn_params *cp)
{
struct ble_hci_ev_le_subev_rem_conn_param_req *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ;
ev->conn_handle = htole16(connsm->conn_handle);
ev->min_interval = htole16(cp->interval_min);
ev->max_interval = htole16(cp->interval_max);
ev->latency = htole16(cp->latency);
ev->timeout = htole16(cp->timeout);
ble_ll_hci_event_send(hci_ev);
}
}
}
/**
* Send a connection update event.
*
* @param connsm Pointer to connection state machine
* @param status The error code.
*/
void
ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status)
{
struct ble_hci_ev_le_subev_conn_upd_complete *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE;
ev->status = status;
ev->conn_handle = htole16(connsm->conn_handle);
ev->conn_itvl = htole16(connsm->conn_itvl);
ev->conn_latency = htole16(connsm->slave_latency);
ev->supervision_timeout = htole16(connsm->supervision_tmo);
ble_ll_hci_event_send(hci_ev);
}
}
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
void
ble_ll_hci_ev_encrypt_chg(struct ble_ll_conn_sm *connsm, uint8_t status)
{
struct ble_hci_ev_enc_key_refresh *ev_key_refresh;
struct ble_hci_ev_enrypt_chg *ev_enc_chf;
struct ble_hci_ev *hci_ev;
if (CONN_F_ENC_CHANGE_SENT(connsm) == 0) {
if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_ENCRYPT_CHG)) {
hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_ENCRYPT_CHG;
hci_ev->length = sizeof(*ev_enc_chf);
ev_enc_chf = (void *) hci_ev->data;
ev_enc_chf->status = status;
ev_enc_chf->connection_handle = htole16(connsm->conn_handle);
ev_enc_chf->enabled = (status == BLE_ERR_SUCCESS) ? 0x01 : 0x00;
ble_ll_hci_event_send(hci_ev);
}
}
CONN_F_ENC_CHANGE_SENT(connsm) = 1;
return;
}
if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_ENC_KEY_REFRESH)) {
hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_ENC_KEY_REFRESH;
hci_ev->length = sizeof(*ev_key_refresh);
ev_key_refresh = (void *) hci_ev->data;
ev_key_refresh->status = status;
ev_key_refresh->conn_handle = htole16(connsm->conn_handle);
ble_ll_hci_event_send(hci_ev);
}
}
}
/**
* Send a long term key request event for a connection to the host.
*
* @param connsm Pointer to connection state machine
*/
int
ble_ll_hci_ev_ltk_req(struct ble_ll_conn_sm *connsm)
{
struct ble_hci_ev_le_subev_lt_key_req *ev;
struct ble_hci_ev *hci_ev;
int rc;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_LT_KEY_REQ)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_LT_KEY_REQ;
ev->conn_handle = htole16(connsm->conn_handle);
ev->rand = htole64(connsm->enc_data.host_rand_num);
ev->div = htole16(connsm->enc_data.enc_div);
ble_ll_hci_event_send(hci_ev);
}
rc = 0;
} else {
rc = -1;
}
#if (BLETEST_CONCURRENT_CONN_TEST == 1)
if (rc == 0) {
bletest_ltk_req_reply(connsm->conn_handle);
}
#endif
return rc;
}
#endif
void
ble_ll_hci_ev_rd_rem_used_feat(struct ble_ll_conn_sm *connsm, uint8_t status)
{
struct ble_hci_ev_le_subev_rd_rem_used_feat *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_RD_REM_USED_FEAT)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_RD_REM_USED_FEAT;
ev->status = status;
ev->conn_handle = htole16(connsm->conn_handle);
ev->features[0] = connsm->conn_features;
memcpy(ev->features + 1, connsm->remote_features, 7);
ble_ll_hci_event_send(hci_ev);
}
}
}
void
ble_ll_hci_ev_rd_rem_ver(struct ble_ll_conn_sm *connsm, uint8_t status)
{
struct ble_hci_ev_rd_rem_ver_info_cmp *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->status = status;
ev->conn_handle = htole16(connsm->conn_handle);
ev->version = connsm->vers_nr;
ev->manufacturer = htole16(connsm->comp_id);
ev->subversion = htole16(connsm->sub_vers_nr);
ble_ll_hci_event_send(hci_ev);
}
}
}
/**
* Send a HW error to the host.
*
* @param hw_err
*
* @return int 0: event masked or event sent, -1 otherwise
*/
int
ble_ll_hci_ev_hw_err(uint8_t hw_err)
{
struct ble_hci_ev_hw_error *ev;
struct ble_hci_ev *hci_ev;
int rc;
rc = 0;
if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_HW_ERROR)) {
hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_HW_ERROR;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->hw_code = hw_err;
ble_ll_hci_event_send(hci_ev);
} else {
rc = -1;
}
}
return rc;
}
void
ble_ll_hci_ev_databuf_overflow(void)
{
struct ble_hci_ev_data_buf_overflow *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_DATA_BUF_OVERFLOW)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_DATA_BUF_OVERFLOW;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->link_type = BLE_HCI_EVENT_ACL_BUF_OVERFLOW;
ble_ll_hci_event_send(hci_ev);
}
}
}
/**
* Send a LE Channel Selection Algorithm event.
*
* @param connsm Pointer to connection state machine
*/
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2)
void
ble_ll_hci_ev_le_csa(struct ble_ll_conn_sm *connsm)
{
struct ble_hci_ev_le_subev_chan_sel_alg *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CHAN_SEL_ALG)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_CHAN_SEL_ALG;
ev->conn_handle = htole16(connsm->conn_handle);
ev->csa = connsm->csmflags.cfbit.csa2_supp ? 0x01 : 0x00;
ble_ll_hci_event_send(hci_ev);
}
}
}
#endif
/**
* Sends the LE Scan Request Received event
*
*/
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
void
ble_ll_hci_ev_send_scan_req_recv(uint8_t adv_handle, const uint8_t *peer,
uint8_t peer_addr_type)
{
struct ble_hci_ev_le_subev_scan_req_rcvd *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD;
ev->adv_handle = adv_handle;
ev->peer_addr_type = peer_addr_type;
memcpy(ev->peer_addr, peer, BLE_DEV_ADDR_LEN);
ble_ll_hci_event_send(hci_ev);
}
}
}
#endif
/**
* Sends the LE Scan Timeout Event
*
*/
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
void
ble_ll_hci_ev_send_scan_timeout(void)
{
struct ble_hci_ev_le_subev_scan_timeout *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_SCAN_TIMEOUT)) {
hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_SCAN_TIMEOUT;
ble_ll_hci_event_send(hci_ev);
}
}
}
#endif
/**
* Sends the LE Advertising Set Terminated event
*
*/
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
void
ble_ll_hci_ev_send_adv_set_terminated(uint8_t status, uint8_t adv_handle,
uint16_t conn_handle, uint8_t events)
{
struct ble_hci_ev_le_subev_adv_set_terminated *ev;
struct ble_hci_ev *hci_ev;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED;
ev->status = status;
ev->adv_handle = adv_handle;
ev->conn_handle = htole16(conn_handle);
ev->num_events = events;
ble_ll_hci_event_send(hci_ev);
}
}
}
#endif
/**
* Send a PHY update complete event
*
* @param connsm Pointer to connection state machine
* @param status error status of event
*/
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
int
ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status)
{
struct ble_hci_ev_le_subev_phy_update_complete *ev;
struct ble_hci_ev *hci_ev;
int rc;
rc = 0;
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PHY_UPDATE_COMPLETE)) {
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_PHY_UPDATE_COMPLETE;
ev->status = status;
ev->conn_handle = htole16(connsm->conn_handle);
ev->tx_phy = connsm->phy_data.cur_tx_phy;
ev->rx_phy = connsm->phy_data.cur_rx_phy;
ble_ll_hci_event_send(hci_ev);
} else {
rc = BLE_ERR_MEM_CAPACITY;
}
}
return rc;
}
#endif
void
ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line)
{
struct ble_hci_ev_vendor_debug *ev;
struct ble_hci_ev *hci_ev;
unsigned int str_len;
bool skip = true;
uint8_t digit;
int max_len;
int i;
/* 6 is for line number ":00000" , we assume files have no more than 64k of
* lines
*/
max_len = BLE_HCI_MAX_DATA_LEN - sizeof(*ev) - 6;
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (hci_ev) {
hci_ev->opcode = BLE_HCI_EVCODE_VENDOR_DEBUG;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
/* Debug id for future use */
ev->id = 0x00;
/* snprintf would be nicer but this is heavy on flash
* len = snprintf((char *) ev->data, max_len, "%s:%u", file, line);
* if (len < 0) {
* len = 0;
* } else if (len > max_len) {
* len = max_len;
* }
*
* hci_ev->length += len;
*/
str_len = strlen(file);
if (str_len > max_len) {
str_len = max_len;
}
memcpy(ev->data, file, str_len);
ev->data[str_len++] = ':';
for (i = 100000; i >= 10; i /= 10) {
digit = (line % i) / (i/10);
if (!digit && skip) {
continue;
}
skip = false;
ev->data[str_len++] = '0' + digit;
}
hci_ev->length += str_len;
ble_ll_hci_event_send(hci_ev);
}
}
#endif

View File

@@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_LL_PRIV_
#define H_BLE_LL_PRIV_
#ifdef __cplusplus
extern "C" {
#endif
#ifdef MYNEWT
#include "syscfg/syscfg.h"
#include "hal/hal_gpio.h"
#define BLE_LL_DEBUG_GPIO_INIT(_name) \
if (MYNEWT_VAL(BLE_LL_DEBUG_GPIO_ ## _name) >= 0) { \
hal_gpio_init_out(MYNEWT_VAL(BLE_LL_DEBUG_GPIO_ ## _name), 0); \
}
#define BLE_LL_DEBUG_GPIO(_name, _val) \
if (MYNEWT_VAL(BLE_LL_DEBUG_GPIO_ ## _name) >= 0) { \
hal_gpio_write(MYNEWT_VAL(BLE_LL_DEBUG_GPIO_ ## _name), !!(_val)); \
}
#else
#define BLE_LL_DEBUG_GPIO_INIT(_name) (void)(0)
#define BLE_LL_DEBUG_GPIO(_name, _val) (void)(0)
#endif
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_LL_PRIV_ */

View File

@@ -0,0 +1,188 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef ESP_PLATFORM
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#include "nimble/porting/nimble/include/os/os.h"
#include "nimble/nimble/include/nimble/ble.h"
#include "nimble/nimble/include/nimble/nimble_opt.h"
#include "../include/controller/ble_hw.h"
#include "../include/controller/ble_ll.h"
#if MYNEWT_VAL(TRNG)
#include "trng/trng.h"
#endif
#if MYNEWT_VAL(TRNG)
static struct trng_dev *g_trng;
#else
/* This is a simple circular buffer for holding N samples of random data */
struct ble_ll_rnum_data
{
uint8_t *rnd_in;
uint8_t *rnd_out;
volatile uint8_t rnd_size;
};
struct ble_ll_rnum_data g_ble_ll_rnum_data;
uint8_t g_ble_ll_rnum_buf[MYNEWT_VAL(BLE_LL_RNG_BUFSIZE)];
#define IS_RNUM_BUF_END(x) \
(x == &g_ble_ll_rnum_buf[MYNEWT_VAL(BLE_LL_RNG_BUFSIZE) - 1])
void
ble_ll_rand_sample(uint8_t rnum)
{
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
if (g_ble_ll_rnum_data.rnd_size < MYNEWT_VAL(BLE_LL_RNG_BUFSIZE)) {
++g_ble_ll_rnum_data.rnd_size;
g_ble_ll_rnum_data.rnd_in[0] = rnum;
if (IS_RNUM_BUF_END(g_ble_ll_rnum_data.rnd_in)) {
g_ble_ll_rnum_data.rnd_in = g_ble_ll_rnum_buf;
} else {
++g_ble_ll_rnum_data.rnd_in;
}
} else {
/* Stop generating random numbers as we are full */
ble_hw_rng_stop();
}
OS_EXIT_CRITICAL(sr);
}
#endif
/* Get 'len' bytes of random data */
int
ble_ll_rand_data_get(uint8_t *buf, uint8_t len)
{
#if MYNEWT_VAL(TRNG)
size_t num;
while (len) {
num = trng_read(g_trng, buf, len);
buf += num;
len -= num;
}
#else
uint8_t rnums;
os_sr_t sr;
while (len != 0) {
OS_ENTER_CRITICAL(sr);
rnums = g_ble_ll_rnum_data.rnd_size;
if (rnums > len) {
rnums = len;
}
len -= rnums;
g_ble_ll_rnum_data.rnd_size -= rnums;
while (rnums) {
buf[0] = g_ble_ll_rnum_data.rnd_out[0];
if (IS_RNUM_BUF_END(g_ble_ll_rnum_data.rnd_out)) {
g_ble_ll_rnum_data.rnd_out = g_ble_ll_rnum_buf;
} else {
++g_ble_ll_rnum_data.rnd_out;
}
++buf;
--rnums;
}
OS_EXIT_CRITICAL(sr);
/* Make sure rng is started! */
ble_hw_rng_start();
/* Wait till bytes are in buffer. */
if (len) {
while ((g_ble_ll_rnum_data.rnd_size < len) &&
(g_ble_ll_rnum_data.rnd_size < MYNEWT_VAL(BLE_LL_RNG_BUFSIZE))) {
/* Spin here */
}
}
}
#endif
return BLE_ERR_SUCCESS;
}
/**
* Called to obtain a "prand" as defined in core V4.2 Vol 6 Part B 1.3.2.2
*
* @param prand
*/
void
ble_ll_rand_prand_get(uint8_t *prand)
{
uint16_t sum;
while (1) {
/* Get 24 bits of random data */
ble_ll_rand_data_get(prand, 3);
/* Prand cannot be all zeros or 1's. */
sum = prand[0] + prand[1] + prand[2];
if ((sum != 0) && (sum != (3 * 0xff))) {
break;
}
}
/* Upper two bits must be 01 */
prand[2] &= ~0xc0;
prand[2] |= 0x40;
}
/**
* Start the generation of random numbers
*
* @return int
*/
int
ble_ll_rand_start(void)
{
#if MYNEWT_VAL(TRNG)
/* Nothing to do - this is handled by driver */
#else
/* Start the generation of numbers if we are not full */
if (g_ble_ll_rnum_data.rnd_size < MYNEWT_VAL(BLE_LL_RNG_BUFSIZE)) {
ble_hw_rng_start();
}
#endif
return 0;
}
/**
* Initialize LL random number generation. Should be called only once on
* initialization.
*
* @return int
*/
int
ble_ll_rand_init(void)
{
#if MYNEWT_VAL(TRNG)
g_trng = (struct trng_dev *) os_dev_open("trng", OS_TIMEOUT_NEVER, NULL);
#else
g_ble_ll_rnum_data.rnd_in = g_ble_ll_rnum_buf;
g_ble_ll_rnum_data.rnd_out = g_ble_ll_rnum_buf;
ble_hw_rng_init(ble_ll_rand_sample, 1);
#endif
return 0;
}
#endif

View File

@@ -0,0 +1,755 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef ESP_PLATFORM
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#include "nimble/porting/nimble/include/os/os.h"
#include "nimble/nimble/include/nimble/ble.h"
#include "nimble/nimble/include/nimble/nimble_opt.h"
#include "../include/controller/ble_ll.h"
#include "../include/controller/ble_ll_resolv.h"
#include "../include/controller/ble_ll_hci.h"
#include "../include/controller/ble_ll_scan.h"
#include "../include/controller/ble_ll_adv.h"
#include "../include/controller/ble_ll_sync.h"
#include "../include/controller/ble_hw.h"
#include "ble_ll_conn_priv.h"
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
struct ble_ll_resolv_data
{
uint8_t addr_res_enabled;
uint8_t rl_size;
uint8_t rl_cnt_hw;
uint8_t rl_cnt;
ble_npl_time_t rpa_tmo;
struct ble_npl_callout rpa_timer;
};
struct ble_ll_resolv_data g_ble_ll_resolv_data;
__attribute__((aligned(4)))
struct ble_ll_resolv_entry g_ble_ll_resolv_list[MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE)];
static int
ble_ll_is_controller_busy(void)
{
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV)
if (ble_ll_sync_enabled()) {
return 1;
}
#endif
return ble_ll_adv_enabled() || ble_ll_scan_enabled() ||
g_ble_ll_conn_create_sm;
}
/**
* Called to determine if a change is allowed to the resolving list at this
* time. We are not allowed to modify the resolving list if address translation
* is enabled and we are either scanning, advertising, or attempting to create
* a connection.
*
* @return int 0: not allowed. 1: allowed.
*/
static int
ble_ll_resolv_list_chg_allowed(void)
{
int rc;
if (g_ble_ll_resolv_data.addr_res_enabled &&
ble_ll_is_controller_busy()) {
rc = 0;
} else {
rc = 1;
}
return rc;
}
/**
* Called to generate a resolvable private address in rl structure
*
* @param rl
* @param local
*/
static void
ble_ll_resolv_gen_priv_addr(struct ble_ll_resolv_entry *rl, int local)
{
uint8_t *irk;
uint8_t *prand;
struct ble_encryption_block ecb;
uint8_t *addr;
BLE_LL_ASSERT(rl != NULL);
if (local) {
addr = rl->rl_local_rpa;
irk = rl->rl_local_irk;
} else {
addr = rl->rl_peer_rpa;
irk = rl->rl_peer_irk;
}
/* Get prand */
prand = addr + 3;
ble_ll_rand_prand_get(prand);
/* Calculate hash, hash = ah(local IRK, prand) */
memcpy(ecb.key, irk, 16);
memset(ecb.plain_text, 0, 13);
ecb.plain_text[13] = prand[2];
ecb.plain_text[14] = prand[1];
ecb.plain_text[15] = prand[0];
/* Calculate hash */
ble_hw_encrypt_block(&ecb);
addr[0] = ecb.cipher_text[15];
addr[1] = ecb.cipher_text[14];
addr[2] = ecb.cipher_text[13];
}
/**
* Called when the Resolvable private address timer expires. This timer
* is used to regenerate local and peers RPA's in the resolving list.
*/
static void
ble_ll_resolv_rpa_timer_cb(struct ble_npl_event *ev)
{
int i;
os_sr_t sr;
struct ble_ll_resolv_entry *rl;
rl = &g_ble_ll_resolv_list[0];
for (i = 0; i < g_ble_ll_resolv_data.rl_cnt; ++i) {
if (rl->rl_has_local) {
OS_ENTER_CRITICAL(sr);
ble_ll_resolv_gen_priv_addr(rl, 1);
OS_EXIT_CRITICAL(sr);
}
if (rl->rl_has_peer) {
OS_ENTER_CRITICAL(sr);
ble_ll_resolv_gen_priv_addr(rl, 0);
OS_EXIT_CRITICAL(sr);
}
++rl;
}
ble_npl_callout_reset(&g_ble_ll_resolv_data.rpa_timer,
g_ble_ll_resolv_data.rpa_tmo);
ble_ll_adv_rpa_timeout();
}
/**
* Called to determine if the IRK is all zero.
*
* @param irk
*
* @return int 0: IRK is zero . 1: IRK has non-zero value.
*/
static int
ble_ll_resolv_irk_nonzero(const uint8_t *irk)
{
int i;
int rc;
rc = 0;
for (i = 0; i < 16; ++i) {
if (*irk != 0) {
rc = 1;
break;
}
++irk;
}
return rc;
}
/**
* Clear the resolving list
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_ll_resolv_list_clr(void)
{
/* Check proper state */
if (!ble_ll_resolv_list_chg_allowed()) {
return BLE_ERR_CMD_DISALLOWED;
}
/* Sets total on list to 0. Clears HW resolve list */
g_ble_ll_resolv_data.rl_cnt_hw = 0;
g_ble_ll_resolv_data.rl_cnt = 0;
ble_hw_resolv_list_clear();
/* stop RPA timer when clearing RL */
ble_npl_callout_stop(&g_ble_ll_resolv_data.rpa_timer);
return BLE_ERR_SUCCESS;
}
/**
* Read the size of the resolving list. This is the total number of resolving
* list entries allowed by the controller.
*
* @param rspbuf Pointer to response buffer
*
* @return int 0: success.
*/
int
ble_ll_resolv_list_read_size(uint8_t *rspbuf, uint8_t *rsplen)
{
struct ble_hci_le_rd_resolv_list_size_rp *rsp = (void *) rspbuf;
rsp->size = g_ble_ll_resolv_data.rl_size;
*rsplen = sizeof(*rsp);
return BLE_ERR_SUCCESS;
}
/**
* Used to determine if the device is on the resolving list.
*
* @param addr
* @param addr_type Public address (0) or random address (1)
*
* @return int 0: device is not on resolving list; otherwise the return value
* is the 'position' of the device in the resolving list (the index of the
* element plus 1).
*/
static int
ble_ll_is_on_resolv_list(const uint8_t *addr, uint8_t addr_type)
{
int i;
struct ble_ll_resolv_entry *rl;
rl = &g_ble_ll_resolv_list[0];
for (i = 0; i < g_ble_ll_resolv_data.rl_cnt; ++i) {
if ((rl->rl_addr_type == addr_type) &&
(!memcmp(&rl->rl_identity_addr[0], addr, BLE_DEV_ADDR_LEN))) {
return i + 1;
}
++rl;
}
return 0;
}
/**
* Used to determine if the device is on the resolving list.
*
* @param addr
* @param addr_type Public address (0) or random address (1)
*
* @return Pointer to resolving list entry or NULL if no entry found.
*/
struct ble_ll_resolv_entry *
ble_ll_resolv_list_find(const uint8_t *addr, uint8_t addr_type)
{
int i;
struct ble_ll_resolv_entry *rl;
rl = &g_ble_ll_resolv_list[0];
for (i = 0; i < g_ble_ll_resolv_data.rl_cnt; ++i) {
if ((rl->rl_addr_type == addr_type) &&
(!memcmp(&rl->rl_identity_addr[0], addr, BLE_DEV_ADDR_LEN))) {
return rl;
}
++rl;
}
return NULL;
}
/**
* Add a device to the resolving list
*
* @return int
*/
int
ble_ll_resolv_list_add(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_add_resolv_list_cp *cmd = (const void *) cmdbuf;
struct ble_ll_resolv_entry *rl;
int rc = BLE_ERR_SUCCESS;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* Must be in proper state */
if (!ble_ll_resolv_list_chg_allowed()) {
return BLE_ERR_CMD_DISALLOWED;
}
/* Check if we have any open entries */
if (g_ble_ll_resolv_data.rl_cnt >= g_ble_ll_resolv_data.rl_size) {
return BLE_ERR_MEM_CAPACITY;
}
/* spec is not clear on how to handle this but make sure host is aware
* that new keys are not used in that case
*/
if (ble_ll_is_on_resolv_list(cmd->peer_id_addr, cmd->peer_addr_type)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* we keep this sorted in a way that entries with peer_irk are first */
if (ble_ll_resolv_irk_nonzero(cmd->peer_irk)) {
memmove(&g_ble_ll_resolv_list[g_ble_ll_resolv_data.rl_cnt_hw + 1],
&g_ble_ll_resolv_list[g_ble_ll_resolv_data.rl_cnt_hw],
(g_ble_ll_resolv_data.rl_cnt - g_ble_ll_resolv_data.rl_cnt_hw) *
sizeof(g_ble_ll_resolv_list[0]));
rl = &g_ble_ll_resolv_list[g_ble_ll_resolv_data.rl_cnt_hw];
} else {
rl = &g_ble_ll_resolv_list[g_ble_ll_resolv_data.rl_cnt];
}
memset (rl, 0, sizeof(*rl));
rl->rl_addr_type = cmd->peer_addr_type;
memcpy(rl->rl_identity_addr, cmd->peer_id_addr, BLE_DEV_ADDR_LEN);
if (ble_ll_resolv_irk_nonzero(cmd->peer_irk)) {
swap_buf(rl->rl_peer_irk, cmd->peer_irk, 16);
rl->rl_has_peer = 1;
/* generate peer RPA now, those will be updated by timer when
* resolution is enabled
*/
ble_ll_resolv_gen_priv_addr(rl, 0);
}
if (ble_ll_resolv_irk_nonzero(cmd->local_irk)) {
swap_buf(rl->rl_local_irk, cmd->local_irk, 16);
rl->rl_has_local = 1;
/* generate local RPA now, those will be updated by timer when
* resolution is enabled
*/
ble_ll_resolv_gen_priv_addr(rl, 1);
}
/* By default use privacy network mode */
rl->rl_priv_mode = BLE_HCI_PRIVACY_NETWORK;
/* Add peers IRKs to HW resolving list. Should always succeed since we
* already checked if there is room for it.
*/
if (rl->rl_has_peer) {
rc = ble_hw_resolv_list_add(rl->rl_peer_irk);
BLE_LL_ASSERT(rc == BLE_ERR_SUCCESS);
g_ble_ll_resolv_data.rl_cnt_hw++;
}
g_ble_ll_resolv_data.rl_cnt++;
/* start RPA timer if this was first element added to RL */
if (g_ble_ll_resolv_data.rl_cnt == 1) {
ble_npl_callout_reset(&g_ble_ll_resolv_data.rpa_timer,
g_ble_ll_resolv_data.rpa_tmo);
}
return rc;
}
/**
* Remove a device from the resolving list
*
* @param cmdbuf
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_ll_resolv_list_rmv(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_rmv_resolve_list_cp *cmd = (const void *) cmdbuf;
int position;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* Must be in proper state */
if (!ble_ll_resolv_list_chg_allowed()) {
return BLE_ERR_CMD_DISALLOWED;
}
/* Remove from IRK records */
position = ble_ll_is_on_resolv_list(cmd->peer_id_addr, cmd->peer_addr_type);
if (position) {
BLE_LL_ASSERT(position <= g_ble_ll_resolv_data.rl_cnt);
memmove(&g_ble_ll_resolv_list[position - 1],
&g_ble_ll_resolv_list[position],
(g_ble_ll_resolv_data.rl_cnt - position) *
sizeof(g_ble_ll_resolv_list[0]));
g_ble_ll_resolv_data.rl_cnt--;
/* Remove from HW list */
if (position <= g_ble_ll_resolv_data.rl_cnt_hw) {
ble_hw_resolv_list_rmv(position - 1);
g_ble_ll_resolv_data.rl_cnt_hw--;
}
/* stop RPA timer if list is empty */
if (g_ble_ll_resolv_data.rl_cnt == 0) {
ble_npl_callout_stop(&g_ble_ll_resolv_data.rpa_timer);
}
return BLE_ERR_SUCCESS;
}
return BLE_ERR_UNK_CONN_ID;
}
/**
* Called to enable or disable address resolution in the controller
*
* @param cmdbuf
*
* @return int
*/
int
ble_ll_resolv_enable_cmd(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_set_addr_res_en_cp *cmd = (const void *) cmdbuf;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
if (ble_ll_is_controller_busy()) {
return BLE_ERR_CMD_DISALLOWED;
}
if (cmd->enable > 1) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
g_ble_ll_resolv_data.addr_res_enabled = cmd->enable;
return BLE_ERR_SUCCESS;
}
int
ble_ll_resolv_peer_addr_rd(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen)
{
const struct ble_hci_le_rd_peer_recolv_addr_cp *cmd = (const void *) cmdbuf;
struct ble_hci_le_rd_peer_recolv_addr_rp *rsp = (void *) rspbuf;
struct ble_ll_resolv_entry *rl;
int rc;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
rl = ble_ll_resolv_list_find(cmd->peer_id_addr, cmd->peer_addr_type);
if (rl) {
memcpy(rsp->rpa, rl->rl_peer_rpa, BLE_DEV_ADDR_LEN);
rc = BLE_ERR_SUCCESS;
} else {
memset(rsp->rpa, 0, BLE_DEV_ADDR_LEN);
rc = BLE_ERR_UNK_CONN_ID;
}
*rsplen = sizeof(*rsp);
return rc;
}
int
ble_ll_resolv_local_addr_rd(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen)
{
const struct ble_hci_le_rd_local_recolv_addr_cp *cmd = (const void *) cmdbuf;
struct ble_hci_le_rd_local_recolv_addr_rp *rsp = (void *) rspbuf;
struct ble_ll_resolv_entry *rl;
int rc;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
rl = ble_ll_resolv_list_find(cmd->peer_id_addr, cmd->peer_addr_type);
if (rl) {
memcpy(rsp->rpa, rl->rl_local_rpa, BLE_DEV_ADDR_LEN);
rc = BLE_ERR_SUCCESS;
} else {
memset(rsp->rpa, 0, BLE_DEV_ADDR_LEN);
rc = BLE_ERR_UNK_CONN_ID;
}
*rsplen = sizeof(*rsp);
return rc;
}
/**
* Set the resolvable private address timeout.
*
* @param cmdbuf
*
* @return int
*/
int
ble_ll_resolv_set_rpa_tmo(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_set_rpa_tmo_cp *cmd = (const void *)cmdbuf;
uint16_t tmo_secs;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
tmo_secs = le16toh(cmd->rpa_timeout);
if (!((tmo_secs > 0) && (tmo_secs <= 0xA1B8))) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
g_ble_ll_resolv_data.rpa_tmo = ble_npl_time_ms_to_ticks32(tmo_secs * 1000);
/* restart timer if there is something on RL */
if (g_ble_ll_resolv_data.rl_cnt) {
ble_npl_callout_reset(&g_ble_ll_resolv_data.rpa_timer,
g_ble_ll_resolv_data.rpa_tmo);
}
return BLE_ERR_SUCCESS;
}
int
ble_ll_resolve_set_priv_mode(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_set_privacy_mode_cp *cmd = (const void *) cmdbuf;
struct ble_ll_resolv_entry *rl;
if (ble_ll_is_controller_busy()) {
return BLE_ERR_CMD_DISALLOWED;
}
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
rl = ble_ll_resolv_list_find(cmd->peer_id_addr, cmd->peer_id_addr_type);
if (!rl) {
return BLE_ERR_UNK_CONN_ID;
}
if (cmd->mode > BLE_HCI_PRIVACY_DEVICE) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
rl->rl_priv_mode = cmd->mode;
return BLE_ERR_SUCCESS;
}
/**
* Returns the Resolvable Private address timeout, in os ticks
*
*
* @return uint32_t
*/
uint32_t
ble_ll_resolv_get_rpa_tmo(void)
{
return g_ble_ll_resolv_data.rpa_tmo;
}
void
ble_ll_resolv_get_priv_addr(struct ble_ll_resolv_entry *rl, int local,
uint8_t *addr)
{
os_sr_t sr;
BLE_LL_ASSERT(rl != NULL);
BLE_LL_ASSERT(addr != NULL);
OS_ENTER_CRITICAL(sr);
if (local) {
BLE_LL_ASSERT(rl->rl_has_local);
memcpy(addr, rl->rl_local_rpa, BLE_DEV_ADDR_LEN);
} else {
BLE_LL_ASSERT(rl->rl_has_peer);
memcpy(addr, rl->rl_peer_rpa, BLE_DEV_ADDR_LEN);
}
OS_EXIT_CRITICAL(sr);
}
void
ble_ll_resolv_set_peer_rpa(int index, uint8_t *rpa)
{
os_sr_t sr;
struct ble_ll_resolv_entry *rl;
OS_ENTER_CRITICAL(sr);
rl = &g_ble_ll_resolv_list[index];
memcpy(rl->rl_peer_rpa, rpa, BLE_DEV_ADDR_LEN);
OS_EXIT_CRITICAL(sr);
}
void
ble_ll_resolv_set_local_rpa(int index, uint8_t *rpa)
{
os_sr_t sr;
struct ble_ll_resolv_entry *rl;
OS_ENTER_CRITICAL(sr);
rl = &g_ble_ll_resolv_list[index];
memcpy(rl->rl_local_rpa, rpa, BLE_DEV_ADDR_LEN);
OS_EXIT_CRITICAL(sr);
}
/**
* Generate a resolvable private address.
*
* @param addr
* @param addr_type
* @param rpa
*
* @return int
*/
int
ble_ll_resolv_gen_rpa(uint8_t *addr, uint8_t addr_type, uint8_t *rpa, int local)
{
struct ble_ll_resolv_entry *rl;
rl = ble_ll_resolv_list_find(addr, addr_type);
if (rl) {
if ((local && rl->rl_has_local) || (!local && rl->rl_has_peer)) {
ble_ll_resolv_get_priv_addr(rl, local, rpa);
return 1;
}
}
return 0;
}
/**
* Resolve a Resolvable Private Address
*
* @param rpa
* @param index
*
* @return int
*/
int
ble_ll_resolv_rpa(const uint8_t *rpa, const uint8_t *irk)
{
int rc;
const uint32_t *irk32;
uint32_t *key32;
uint32_t *pt32;
struct ble_encryption_block ecb;
irk32 = (const uint32_t *)irk;
key32 = (uint32_t *)&ecb.key[0];
key32[0] = irk32[0];
key32[1] = irk32[1];
key32[2] = irk32[2];
key32[3] = irk32[3];
pt32 = (uint32_t *)&ecb.plain_text[0];
pt32[0] = 0;
pt32[1] = 0;
pt32[2] = 0;
pt32[3] = 0;
ecb.plain_text[15] = rpa[3];
ecb.plain_text[14] = rpa[4];
ecb.plain_text[13] = rpa[5];
ble_hw_encrypt_block(&ecb);
if ((ecb.cipher_text[15] == rpa[0]) && (ecb.cipher_text[14] == rpa[1]) &&
(ecb.cipher_text[13] == rpa[2])) {
rc = 1;
} else {
rc = 0;
}
return rc;
}
int
ble_ll_resolv_peer_rpa_any(const uint8_t *rpa)
{
int i;
for (i = 0; i < g_ble_ll_resolv_data.rl_cnt_hw; i++) {
if (ble_ll_resolv_rpa(rpa, g_ble_ll_resolv_list[i].rl_peer_irk)) {
return i;
}
}
return -1;
}
/**
* Returns whether or not address resolution is enabled.
*
* @return uint8_t
*/
uint8_t
ble_ll_resolv_enabled(void)
{
return g_ble_ll_resolv_data.addr_res_enabled;
}
/**
* Called to reset private address resolution module.
*/
void
ble_ll_resolv_list_reset(void)
{
g_ble_ll_resolv_data.addr_res_enabled = 0;
ble_npl_callout_stop(&g_ble_ll_resolv_data.rpa_timer);
ble_ll_resolv_list_clr();
ble_ll_resolv_init();
}
void
ble_ll_resolv_init(void)
{
uint8_t hw_size;
/* Default is 15 minutes */
g_ble_ll_resolv_data.rpa_tmo = ble_npl_time_ms_to_ticks32(15 * 60 * 1000);
hw_size = ble_hw_resolv_list_size();
if (hw_size > MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE)) {
hw_size = MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE);
}
g_ble_ll_resolv_data.rl_size = hw_size;
ble_npl_callout_init(&g_ble_ll_resolv_data.rpa_timer,
&g_ble_ll_data.ll_evq,
ble_ll_resolv_rpa_timer_cb,
NULL);
}
#endif /* if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) */
#endif

View File

@@ -0,0 +1,349 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef ESP_PLATFORM
#include <stdint.h>
#include <stddef.h>
#include <assert.h>
#include <stddef.h>
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#include "nimble/porting/nimble/include/os/os_cputime.h"
#include "../include/controller/ble_phy.h"
#include "../include/controller/ble_ll.h"
#include "../include/controller/ble_ll_sched.h"
#include "../include/controller/ble_ll_rfmgmt.h"
#if MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME) > 0
enum ble_ll_rfmgmt_state {
RFMGMT_STATE_OFF = 0,
RFMGMT_STATE_ENABLING = 1,
RFMGMT_STATE_ENABLED = 2,
};
struct ble_ll_rfmgmt_data {
enum ble_ll_rfmgmt_state state;
uint16_t ticks_to_enabled;
struct hal_timer timer;
bool timer_scheduled;
uint32_t timer_scheduled_at;
bool enable_scan;
bool enable_sched;
uint32_t enable_scan_at;
uint32_t enable_sched_at;
uint32_t enabled_at;
struct ble_npl_event release_ev;
};
static struct ble_ll_rfmgmt_data g_ble_ll_rfmgmt_data;
static void
ble_ll_rfmgmt_enable(void)
{
OS_ASSERT_CRITICAL();
if (g_ble_ll_rfmgmt_data.state == RFMGMT_STATE_OFF) {
g_ble_ll_rfmgmt_data.state = RFMGMT_STATE_ENABLING;
g_ble_ll_rfmgmt_data.enabled_at = os_cputime_get32();
ble_phy_rfclk_enable();
}
}
static void
ble_ll_rfmgmt_disable(void)
{
OS_ASSERT_CRITICAL();
if (g_ble_ll_rfmgmt_data.state != RFMGMT_STATE_OFF) {
ble_phy_rfclk_disable();
g_ble_ll_rfmgmt_data.state = RFMGMT_STATE_OFF;
}
}
static void
ble_ll_rfmgmt_timer_reschedule(void)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
uint32_t enable_at;
/* Figure out when we need to enable RF */
if (rfmgmt->enable_scan && rfmgmt->enable_sched) {
if (CPUTIME_LT(rfmgmt->enable_scan_at, rfmgmt->enable_sched_at)) {
enable_at = rfmgmt->enable_scan_at;
} else {
enable_at = rfmgmt->enable_sched_at;
}
} else if (rfmgmt->enable_scan) {
enable_at = rfmgmt->enable_scan_at;
} else if (rfmgmt->enable_sched) {
enable_at = rfmgmt->enable_sched_at;
} else {
rfmgmt->timer_scheduled = false;
os_cputime_timer_stop(&rfmgmt->timer);
return;
}
if (rfmgmt->timer_scheduled) {
/*
* If there is timer already scheduled at the same time we do not need
* to do anything. Otherwise we need to stop timer and schedule it again
* regardless if it's earlier or later to make sure it fires at the time
* something expects it.
*/
if (rfmgmt->timer_scheduled_at == enable_at) {
return;
}
rfmgmt->timer_scheduled = false;
os_cputime_timer_stop(&rfmgmt->timer);
}
/*
* In case timer was requested to be enabled before current time, just make
* sure it's enabled and assume caller can deal with this. This will happen
* if something is scheduled "now" since "enable_at" is in the past, but in
* such case it's absolutely harmless since we already have clock enabled
* and this will do nothing.
*/
if (CPUTIME_LEQ(enable_at, os_cputime_get32())) {
ble_ll_rfmgmt_enable();
return;
}
rfmgmt->timer_scheduled = true;
rfmgmt->timer_scheduled_at = enable_at;
os_cputime_timer_start(&rfmgmt->timer, enable_at);
}
static void
ble_ll_rfmgmt_timer_exp(void *arg)
{
g_ble_ll_rfmgmt_data.timer_scheduled = false;
ble_ll_rfmgmt_enable();
}
static void
ble_ll_rfmgmt_release_ev(struct ble_npl_event *ev)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
uint32_t now;
bool can_disable;
uint8_t lls;
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
now = os_cputime_get32();
can_disable = true;
lls = ble_ll_state_get();
if (rfmgmt->enable_scan && CPUTIME_GEQ(now, rfmgmt->enable_scan_at)) {
/* Blocked by scan */
can_disable = false;
} else if (rfmgmt->enable_sched && CPUTIME_GEQ(now, rfmgmt->enable_sched_at)) {
/* Blocked by scheduler item */
can_disable = false;
} else if (lls != BLE_LL_STATE_STANDBY) {
/* Blocked by LL state */
can_disable = false;
}
if (can_disable) {
ble_ll_rfmgmt_disable();
}
OS_EXIT_CRITICAL(sr);
}
static uint32_t
ble_ll_rfmgmt_ticks_to_enabled(void)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
uint32_t rem_ticks;
uint32_t now;
switch (rfmgmt->state) {
case RFMGMT_STATE_OFF:
rem_ticks = rfmgmt->ticks_to_enabled;
break;
case RFMGMT_STATE_ENABLING:
now = os_cputime_get32();
if (CPUTIME_LT(now, rfmgmt->enabled_at + rfmgmt->ticks_to_enabled)) {
rem_ticks = rfmgmt->enabled_at + rfmgmt->ticks_to_enabled - now;
break;
}
rfmgmt->state = RFMGMT_STATE_ENABLED;
/* Else falls through. */
/* no break */
case RFMGMT_STATE_ENABLED:
rem_ticks = 0;
break;
default:
BLE_LL_ASSERT(0);
rem_ticks = 0;
break;
}
return rem_ticks;
}
void
ble_ll_rfmgmt_init(void)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
rfmgmt->state = RFMGMT_STATE_OFF;
rfmgmt->ticks_to_enabled =
ble_ll_usecs_to_ticks_round_up(MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME));
rfmgmt->timer_scheduled = false;
os_cputime_timer_init(&rfmgmt->timer, ble_ll_rfmgmt_timer_exp, NULL);
ble_npl_event_init(&rfmgmt->release_ev, ble_ll_rfmgmt_release_ev, NULL);
}
void
ble_ll_rfmgmt_reset(void)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
rfmgmt->timer_scheduled = false;
rfmgmt->timer_scheduled_at = 0;
os_cputime_timer_stop(&rfmgmt->timer);
ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev);
ble_ll_rfmgmt_disable();
rfmgmt->enable_scan = false;
rfmgmt->enable_scan_at = 0;
rfmgmt->enable_sched = false;
rfmgmt->enable_sched_at = 0;
rfmgmt->enabled_at = 0;
}
void
ble_ll_rfmgmt_scan_changed(bool enabled, uint32_t next_window)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
rfmgmt->enable_scan = enabled;
rfmgmt->enable_scan_at = next_window - rfmgmt->ticks_to_enabled;
ble_ll_rfmgmt_timer_reschedule();
OS_EXIT_CRITICAL(sr);
}
void
ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *first)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
rfmgmt->enable_sched = (first != NULL);
if (first) {
rfmgmt->enable_sched_at = first->start_time - rfmgmt->ticks_to_enabled;
}
ble_ll_rfmgmt_timer_reschedule();
OS_EXIT_CRITICAL(sr);
}
void
ble_ll_rfmgmt_release(void)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev);
if (g_ble_ll_rfmgmt_data.state != RFMGMT_STATE_OFF) {
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev);
}
OS_EXIT_CRITICAL(sr);
}
uint32_t
ble_ll_rfmgmt_enable_now(void)
{
struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data;
uint32_t enabled_at;
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
ble_ll_rfmgmt_enable();
if (rfmgmt->state == RFMGMT_STATE_ENABLED) {
enabled_at = os_cputime_get32();
} else {
enabled_at = rfmgmt->enabled_at + rfmgmt->ticks_to_enabled + 1;
}
OS_EXIT_CRITICAL(sr);
return enabled_at;
}
bool
ble_ll_rfmgmt_is_enabled(void)
{
bool ret;
OS_ASSERT_CRITICAL();
ret = ble_ll_rfmgmt_ticks_to_enabled() == 0;
return ret;
}
#else
void
ble_ll_rfmgmt_init(void)
{
static bool enabled = false;
if (!enabled) {
ble_phy_rfclk_enable();
}
enabled = true;
}
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,461 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef ESP_PLATFORM
#include <stdint.h>
#include <string.h>
#include "nimble/nimble/include/nimble/ble.h"
#include "nimble/nimble/include/nimble/nimble_opt.h"
#include "nimble/nimble/include/nimble/hci_common.h"
#include "../include/controller/ble_ll.h"
#include "../include/controller/ble_ll_hci.h"
/* Octet 0 */
#define BLE_SUPP_CMD_DISCONNECT (1 << 5)
#define BLE_LL_SUPP_CMD_OCTET_0 (BLE_SUPP_CMD_DISCONNECT)
/* Octet 5 */
#define BLE_SUPP_CMD_SET_EVENT_MASK (1 << 6)
#define BLE_LL_SUPP_CMD_OCTET_5 (BLE_SUPP_CMD_SET_EVENT_MASK)
/* Octet 10 */
#define BLE_SUPP_CMD_RD_TX_PWR (0 << 2)
#define BLE_LL_SUPP_CMD_OCTET_10 (BLE_SUPP_CMD_RD_TX_PWR)
/* Octet 14 */
#define BLE_SUPP_CMD_RD_LOC_VER (1 << 3)
#define BLE_SUPP_CMD_RD_LOC_SUPP_FEAT (1 << 5)
#define BLE_LL_SUPP_CMD_OCTET_14 \
( \
BLE_SUPP_CMD_RD_LOC_VER | \
BLE_SUPP_CMD_RD_LOC_SUPP_FEAT \
)
/* Octet 15 */
#define BLE_SUPP_CMD_RD_BD_ADDR (1 << 1)
#define BLE_SUPP_CMD_RD_RSSI (1 << 5)
#define BLE_LL_SUPP_CMD_OCTET_15 \
( \
BLE_SUPP_CMD_RD_BD_ADDR | \
BLE_SUPP_CMD_RD_RSSI \
)
/* Octet 25 */
#define BLE_SUPP_CMD_LE_SET_EV_MASK (1 << 0)
#define BLE_SUPP_CMD_LE_RD_BUF_SIZE (1 << 1)
#define BLE_SUPP_CMD_LE_RD_LOC_FEAT (1 << 2)
#define BLE_SUPP_CMD_LE_SET_RAND_ADDR (1 << 4)
#define BLE_SUPP_CMD_LE_SET_ADV_PARAMS (1 << 5)
#define BLE_SUPP_CMD_LE_SET_ADV_TX_PWR (1 << 6)
#define BLE_SUPP_CMD_LE_SET_ADV_DATA (1 << 7)
#define BLE_LL_SUPP_CMD_OCTET_25 \
( \
BLE_SUPP_CMD_LE_SET_EV_MASK | \
BLE_SUPP_CMD_LE_RD_BUF_SIZE | \
BLE_SUPP_CMD_LE_RD_LOC_FEAT | \
BLE_SUPP_CMD_LE_SET_RAND_ADDR | \
BLE_SUPP_CMD_LE_SET_ADV_PARAMS | \
BLE_SUPP_CMD_LE_SET_ADV_TX_PWR | \
BLE_SUPP_CMD_LE_SET_ADV_DATA \
)
/* Octet 26 */
#define BLE_SUPP_CMD_LE_SET_SCAN_RSP_DATA (1 << 0)
#define BLE_SUPP_CMD_LE_SET_ADV_ENABLE (1 << 1)
#define BLE_SUPP_CMD_LE_SET_SCAN_PARAMS (1 << 2)
#define BLE_SUPP_CMD_LE_SET_SCAN_ENABLE (1 << 3)
#define BLE_SUPP_CMD_LE_CREATE_CONN (1 << 4)
#define BLE_SUPP_CMD_LE_CREATE_CONN_CANCEL (1 << 5)
#define BLE_SUPP_CMD_LE_RD_WHITELIST_SIZE (1 << 6)
#define BLE_SUPP_CMD_LE_CLR_WHITELIST (1 << 7)
#define BLE_LL_SUPP_CMD_OCTET_26 \
( \
BLE_SUPP_CMD_LE_SET_SCAN_RSP_DATA | \
BLE_SUPP_CMD_LE_SET_ADV_ENABLE | \
BLE_SUPP_CMD_LE_SET_SCAN_PARAMS | \
BLE_SUPP_CMD_LE_SET_SCAN_ENABLE | \
BLE_SUPP_CMD_LE_CREATE_CONN | \
BLE_SUPP_CMD_LE_CREATE_CONN_CANCEL | \
BLE_SUPP_CMD_LE_RD_WHITELIST_SIZE | \
BLE_SUPP_CMD_LE_CLR_WHITELIST \
)
/* Octet 27 */
#define BLE_SUPP_CMD_LE_ADD_DEV_WHITELIST (1 << 0)
#define BLE_SUPP_CMD_LE_RMV_DEV_WHITELIST (1 << 1)
#define BLE_SUPP_CMD_LE_CONN_UPDATE (1 << 2)
#define BLE_SUPP_CMD_LE_SET_HOST_CHAN_CLASS (1 << 3)
#define BLE_SUPP_CMD_LE_RD_CHAN_MAP (1 << 4)
#define BLE_SUPP_CMD_LE_RD_REM_USED_FEAT (1 << 5)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
#define BLE_SUPP_CMD_LE_ENCRYPT (1 << 6)
#else
#define BLE_SUPP_CMD_LE_ENCRYPT (0 << 6)
#endif
#define BLE_SUPP_CMD_LE_RAND (1 << 7)
#define BLE_LL_SUPP_CMD_OCTET_27 \
( \
BLE_SUPP_CMD_LE_ENCRYPT | \
BLE_SUPP_CMD_LE_RAND | \
BLE_SUPP_CMD_LE_ADD_DEV_WHITELIST | \
BLE_SUPP_CMD_LE_RMV_DEV_WHITELIST | \
BLE_SUPP_CMD_LE_CONN_UPDATE | \
BLE_SUPP_CMD_LE_SET_HOST_CHAN_CLASS | \
BLE_SUPP_CMD_LE_RD_CHAN_MAP | \
BLE_SUPP_CMD_LE_RD_REM_USED_FEAT \
)
/* Octet 28 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
#define BLE_SUPP_CMD_LE_START_ENCRYPT (1 << 0)
#define BLE_SUPP_CMD_LE_LTK_REQ_REPLY (1 << 1)
#define BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY (1 << 2)
#else
#define BLE_SUPP_CMD_LE_START_ENCRYPT (0 << 0)
#define BLE_SUPP_CMD_LE_LTK_REQ_REPLY (0 << 1)
#define BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY (0 << 2)
#endif
#define BLE_SUPP_CMD_LE_READ_SUPP_STATES (1 << 3)
#if MYNEWT_VAL(BLE_LL_DTM)
#define BLE_SUPP_CMD_LE_RX_TEST (1 << 4)
#define BLE_SUPP_CMD_LE_TX_TEST (1 << 5)
#define BLE_SUPP_CMD_LE_TEST_END (1 << 6)
#else
#define BLE_SUPP_CMD_LE_RX_TEST (0 << 4)
#define BLE_SUPP_CMD_LE_TX_TEST (0 << 5)
#define BLE_SUPP_CMD_LE_TEST_END (0 << 6)
#endif
#define BLE_LL_SUPP_CMD_OCTET_28 \
( \
BLE_SUPP_CMD_LE_START_ENCRYPT | \
BLE_SUPP_CMD_LE_LTK_REQ_REPLY | \
BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY | \
BLE_SUPP_CMD_LE_READ_SUPP_STATES | \
BLE_SUPP_CMD_LE_RX_TEST | \
BLE_SUPP_CMD_LE_TX_TEST | \
BLE_SUPP_CMD_LE_TEST_END \
)
/* Octet 33 */
#define BLE_SUPP_CMD_LE_REM_CONN_PRR (1 << 4)
#define BLE_SUPP_CMD_LE_REM_CONN_PRNR (1 << 5)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT)
#define BLE_SUPP_CMD_LE_SET_DATALEN (1 << 6)
#define BLE_SUPP_CMD_LE_RD_SUGG_DATALEN (1 << 7)
#else
#define BLE_SUPP_CMD_LE_SET_DATALEN (0 << 6)
#define BLE_SUPP_CMD_LE_RD_SUGG_DATALEN (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_33 \
( \
BLE_SUPP_CMD_LE_REM_CONN_PRR | \
BLE_SUPP_CMD_LE_REM_CONN_PRNR | \
BLE_SUPP_CMD_LE_SET_DATALEN | \
BLE_SUPP_CMD_LE_RD_SUGG_DATALEN \
)
/* Octet 34 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT)
#define BLE_SUPP_CMD_LE_WR_SUGG_DATALEN (1 << 0)
#else
#define BLE_SUPP_CMD_LE_WR_SUGG_DATALEN (0 << 0)
#endif
#define BLE_SUPP_CMD_LE_READ_LOCAL_P256_PK (0 << 1)
#define BLE_SUPP_CMD_LE_GENERATE_DH_KEY (0 << 2)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
#define BLE_SUPP_CMD_LE_ADD_RESOLV_LIST (1 << 3)
#define BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST (1 << 4)
#define BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST (1 << 5)
#define BLE_SUPP_CMD_LE_RD_RESOLV_SIZE (1 << 6)
#define BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR (1 << 7)
#else
#define BLE_SUPP_CMD_LE_ADD_RESOLV_LIST (0 << 3)
#define BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST (0 << 4)
#define BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST (0 << 5)
#define BLE_SUPP_CMD_LE_RD_RESOLV_SIZE (0 << 6)
#define BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_34 \
( \
BLE_SUPP_CMD_LE_WR_SUGG_DATALEN | \
BLE_SUPP_CMD_LE_READ_LOCAL_P256_PK | \
BLE_SUPP_CMD_LE_GENERATE_DH_KEY | \
BLE_SUPP_CMD_LE_ADD_RESOLV_LIST | \
BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST | \
BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST | \
BLE_SUPP_CMD_LE_RD_RESOLV_SIZE | \
BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR \
)
/* Octet 35 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
#define BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR (1 << 0)
#define BLE_SUPP_CMD_LE_SET_ADDR_RES_EN (1 << 1)
#define BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO (1 << 2)
#else
#define BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR (0 << 0)
#define BLE_SUPP_CMD_LE_SET_ADDR_RES_EN (0 << 1)
#define BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO (0 << 2)
#endif
#define BLE_SUPP_CMD_LE_RD_MAX_DATALEN (1 << 3)
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
#define BLE_SUPP_CMD_LE_READ_PHY (1 << 4)
#define BLE_SUPP_CMD_LE_SET_DEFAULT_PHY (1 << 5)
#define BLE_SUPP_CMD_LE_SET_PHY (1 << 6)
#else
#define BLE_SUPP_CMD_LE_READ_PHY (0 << 4)
#define BLE_SUPP_CMD_LE_SET_DEFAULT_PHY (0 << 5)
#define BLE_SUPP_CMD_LE_SET_PHY (0 << 6)
#endif
#if MYNEWT_VAL(BLE_LL_DTM)
#define BLE_SUPP_CMD_LE_ENHANCED_RX_TEST (1 << 7)
#else
#define BLE_SUPP_CMD_LE_ENHANCED_RX_TEST (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_35 \
( \
BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR | \
BLE_SUPP_CMD_LE_SET_ADDR_RES_EN | \
BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO | \
BLE_SUPP_CMD_LE_RD_MAX_DATALEN | \
BLE_SUPP_CMD_LE_READ_PHY | \
BLE_SUPP_CMD_LE_SET_DEFAULT_PHY | \
BLE_SUPP_CMD_LE_SET_PHY | \
BLE_SUPP_CMD_LE_ENHANCED_RX_TEST \
)
/* Octet 36 */
#if MYNEWT_VAL(BLE_LL_DTM)
#define BLE_SUPP_CMD_LE_ENHANCED_TX_TEST (1 << 0)
#else
#define BLE_SUPP_CMD_LE_ENHANCED_TX_TEST (0 << 0)
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
#define BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR (1 << 1)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM (1 << 2)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA (1 << 3)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP (1 << 4)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE (1 << 5)
#define BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN (1 << 6)
#define BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS (1 << 7)
#else
#define BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR (0 << 1)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM (0 << 2)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA (0 << 3)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP (0 << 4)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE (0 << 5)
#define BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN (0 << 6)
#define BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_36 \
( \
BLE_SUPP_CMD_LE_ENHANCED_TX_TEST | \
BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR | \
BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM | \
BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA | \
BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP | \
BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE | \
BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN | \
BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS \
)
/* Octet 37 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
#define BLE_SUPP_CMD_LE_REMOVE_ADVS (1 << 0)
#define BLE_SUPP_CMD_LE_CLEAR_ADVS (1 << 1)
#else
#define BLE_SUPP_CMD_LE_REMOVE_ADVS (0 << 0)
#define BLE_SUPP_CMD_LE_CLEAR_ADVS (0 << 1)
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV)
#define BLE_SUPP_CMD_LE_SET_PADV_PARAM (1 << 2)
#define BLE_SUPP_CMD_LE_SET_PADV_DATA (1 << 3)
#define BLE_SUPP_CMD_LE_SET_PADV_ENABLE (1 << 4)
#else
#define BLE_SUPP_CMD_LE_SET_PADV_PARAM (0 << 2)
#define BLE_SUPP_CMD_LE_SET_PADV_DATA (0 << 3)
#define BLE_SUPP_CMD_LE_SET_PADV_ENABLE (0 << 4)
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM (1 << 5)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE (1 << 6)
#define BLE_SUPP_CMD_LE_EXT_CREATE_CONN (1 << 7)
#else
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM (0 << 5)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE (0 << 6)
#define BLE_SUPP_CMD_LE_EXT_CREATE_CONN (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_37 \
( \
BLE_SUPP_CMD_LE_REMOVE_ADVS | \
BLE_SUPP_CMD_LE_CLEAR_ADVS | \
BLE_SUPP_CMD_LE_SET_PADV_PARAM | \
BLE_SUPP_CMD_LE_SET_PADV_DATA | \
BLE_SUPP_CMD_LE_SET_PADV_ENABLE | \
BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM | \
BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE | \
BLE_SUPP_CMD_LE_EXT_CREATE_CONN \
)
/* Octet 38 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV)
#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC (1 << 0)
#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C (1 << 1)
#define BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC (1 << 2)
#define BLE_SUPP_CMD_LE_ADD_PADV_LIST (1 << 3)
#define BLE_SUPP_CMD_LE_REMOVE_PADV_LIST (1 << 4)
#define BLE_SUPP_CMD_LE_CLEAR_PADV_LIST (1 << 5)
#define BLE_SUPP_CMD_LE_RD_PADV_LIST_SIZE (1 << 6)
#else
#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC (0 << 0)
#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C (0 << 1)
#define BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC (0 << 2)
#define BLE_SUPP_CMD_LE_ADD_PADV_LIST (0 << 3)
#define BLE_SUPP_CMD_LE_REMOVE_PADV_LIST (0 << 4)
#define BLE_SUPP_CMD_LE_CLEAR_PADV_LIST (0 << 5)
#define BLE_SUPP_CMD_LE_RD_PADV_LIST_SIZE (0 << 6)
#endif
#define BLE_SUPP_CMD_LE_RD_TX_POWER (1 << 7)
#define BLE_LL_SUPP_CMD_OCTET_38 \
( \
BLE_SUPP_CMD_LE_PADV_CREATE_SYNC | \
BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C | \
BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC | \
BLE_SUPP_CMD_LE_ADD_PADV_LIST | \
BLE_SUPP_CMD_LE_REMOVE_PADV_LIST | \
BLE_SUPP_CMD_LE_CLEAR_PADV_LIST | \
BLE_SUPP_CMD_LE_RD_PADV_LIST_SIZE | \
BLE_SUPP_CMD_LE_RD_TX_POWER \
)
/* Octet 39 */
#define BLE_SUPP_CMD_LE_RD_RF_PATH_COMP (1 << 0)
#define BLE_SUPP_CMD_LE_WR_RF_PATH_COMP (1 << 1)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
#define BLE_SUPP_CMD_LE_SET_PRIVACY_MODE (1 << 2)
#else
#define BLE_SUPP_CMD_LE_SET_PRIVACY_MODE (0 << 2)
#endif
#define BLE_LL_SUPP_CMD_OCTET_39 \
( \
BLE_SUPP_CMD_LE_RD_RF_PATH_COMP | \
BLE_SUPP_CMD_LE_WR_RF_PATH_COMP | \
BLE_SUPP_CMD_LE_SET_PRIVACY_MODE \
)
/* Octet 40 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_VERSION) >= 51
#define BLE_SUPP_CMD_LE_PADV_RECV_ENABLE (1 << 5)
#else
#define BLE_SUPP_CMD_LE_PADV_RECV_ENABLE (0 << 5)
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER (1 << 6)
#define BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER (1 << 7)
#else
#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER (0 << 6)
#define BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_40 \
( \
BLE_SUPP_CMD_LE_PADV_RECV_ENABLE | \
BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER | \
BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER \
)
/* Octet 41 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS (1 << 0)
#define BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS (1 << 1)
#else
#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS (0 << 0)
#define BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS (0 << 1)
#endif
#define BLE_LL_SUPP_CMD_OCTET_41 \
( \
BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS | \
BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS \
)
/* Defines the array of supported commands */
const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN] =
{
BLE_LL_SUPP_CMD_OCTET_0, /* Octet 0 */
0,
0,
0,
0,
BLE_LL_SUPP_CMD_OCTET_5,
0,
0,
0, /* Octet 8 */
0,
BLE_LL_SUPP_CMD_OCTET_10,
0,
0,
0,
BLE_LL_SUPP_CMD_OCTET_14,
BLE_LL_SUPP_CMD_OCTET_15,
0, /* Octet 16 */
0,
0,
0,
0,
0,
0,
0,
0, /* Octet 24 */
BLE_LL_SUPP_CMD_OCTET_25,
BLE_LL_SUPP_CMD_OCTET_26,
BLE_LL_SUPP_CMD_OCTET_27,
BLE_LL_SUPP_CMD_OCTET_28,
0,
0,
0,
0, /* Octet 32 */
BLE_LL_SUPP_CMD_OCTET_33,
BLE_LL_SUPP_CMD_OCTET_34,
BLE_LL_SUPP_CMD_OCTET_35,
BLE_LL_SUPP_CMD_OCTET_36,
BLE_LL_SUPP_CMD_OCTET_37,
BLE_LL_SUPP_CMD_OCTET_38,
BLE_LL_SUPP_CMD_OCTET_39,
BLE_LL_SUPP_CMD_OCTET_40, /* Octet 40 */
BLE_LL_SUPP_CMD_OCTET_41,
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef ESP_PLATFORM
#include <stdint.h>
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#include "nimble/porting/nimble/include/os/os_trace_api.h"
#if MYNEWT_VAL(BLE_LL_SYSVIEW)
static os_trace_module_t g_ble_ll_trace_mod;
uint32_t ble_ll_trace_off;
static void
ble_ll_trace_module_send_desc(void)
{
os_trace_module_desc(&g_ble_ll_trace_mod, "0 ll_sched lls=%u cputime=%u start_time=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "1 ll_rx_start lls=%u pdu_type=%x");
os_trace_module_desc(&g_ble_ll_trace_mod, "2 ll_rx_end pdu_type=%x len=%u flags=%x");
os_trace_module_desc(&g_ble_ll_trace_mod, "3 ll_wfr_timer_exp lls=%u xcvr=%u rx_start=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "4 ll_ctrl_rx opcode=%u len=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "5 ll_conn_ev_start conn_handle=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "6 ll_conn_ev_end conn_handle=%u event_cntr=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "7 ll_conn_end conn_handle=%u event_cntr=%u err=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "8 ll_conn_tx len=%u offset=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "9 ll_conn_rx conn_sn=%u pdu_nesn=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "10 ll_adv_txdone inst=%u chanset=%x");
os_trace_module_desc(&g_ble_ll_trace_mod, "11 ll_adv_halt inst=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "12 ll_aux_ref aux=%p ref=%u");
os_trace_module_desc(&g_ble_ll_trace_mod, "13 ll_aux_unref aux=%p ref=%u");
}
void
ble_ll_trace_init(void)
{
ble_ll_trace_off =
os_trace_module_register(&g_ble_ll_trace_mod, "ble_ll", 12,
ble_ll_trace_module_send_desc);
}
#endif
#endif

View File

@@ -0,0 +1,303 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef ESP_PLATFORM
#include <assert.h>
#include <stdlib.h>
#include "nimble/nimble/include/nimble/ble.h"
#include "../include/controller/ble_ll.h"
#include "../include/controller/ble_ll_utils.h"
/* 37 bits require 5 bytes */
#define BLE_LL_CHMAP_LEN (5)
/* Sleep clock accuracy table (in ppm) */
static const uint16_t g_ble_sca_ppm_tbl[8] = {
500, 250, 150, 100, 75, 50, 30, 20
};
uint32_t
ble_ll_utils_calc_access_addr(void)
{
uint32_t aa;
uint16_t aa_low;
uint16_t aa_high;
uint32_t temp;
uint32_t mask;
uint32_t prev_bit;
uint8_t bits_diff;
uint8_t consecutive;
uint8_t transitions;
uint8_t ones;
int tmp;
/* Calculate a random access address */
aa = 0;
while (1) {
/* Get two, 16-bit random numbers */
aa_low = rand() & 0xFFFF;
aa_high = rand() & 0xFFFF;
/* All four bytes cannot be equal */
if (aa_low == aa_high) {
continue;
}
/* Upper 6 bits must have 2 transitions */
tmp = (int16_t)aa_high >> 10;
if (__builtin_popcount(tmp ^ (tmp >> 1)) < 2) {
continue;
}
/* Cannot be access address or be 1 bit different */
aa = aa_high;
aa = (aa << 16) | aa_low;
bits_diff = 0;
temp = aa ^ BLE_ACCESS_ADDR_ADV;
for (mask = 0x00000001; mask != 0; mask <<= 1) {
if (mask & temp) {
++bits_diff;
if (bits_diff > 1) {
break;
}
}
}
if (bits_diff <= 1) {
continue;
}
/* Cannot have more than 24 transitions */
transitions = 0;
consecutive = 1;
ones = 0;
mask = 0x00000001;
while (mask < 0x80000000) {
prev_bit = aa & mask;
mask <<= 1;
if (mask & aa) {
if (prev_bit == 0) {
++transitions;
consecutive = 1;
} else {
++consecutive;
}
} else {
if (prev_bit == 0) {
++consecutive;
} else {
++transitions;
consecutive = 1;
}
}
if (prev_bit) {
ones++;
}
/* 8 lsb should have at least three 1 */
if (mask == 0x00000100 && ones < 3) {
break;
}
/* 16 lsb should have no more than 11 transitions */
if (mask == 0x00010000 && transitions > 11) {
break;
}
/* This is invalid! */
if (consecutive > 6) {
/* Make sure we always detect invalid sequence below */
mask = 0;
break;
}
}
/* Invalid sequence found */
if (mask != 0x80000000) {
continue;
}
/* Cannot be more than 24 transitions */
if (transitions > 24) {
continue;
}
/* We have a valid access address */
break;
}
return aa;
}
uint8_t
ble_ll_utils_remapped_channel(uint8_t remap_index, const uint8_t *chanmap)
{
uint8_t cntr;
uint8_t mask;
uint8_t usable_chans;
uint8_t chan;
int i, j;
/* NOTE: possible to build a map but this would use memory. For now,
* we just calculate
* Iterate through channel map to find this channel
*/
chan = 0;
cntr = 0;
for (i = 0; i < BLE_LL_CHMAP_LEN; i++) {
usable_chans = chanmap[i];
if (usable_chans != 0) {
mask = 0x01;
for (j = 0; j < 8; j++) {
if (usable_chans & mask) {
if (cntr == remap_index) {
return (chan + j);
}
++cntr;
}
mask <<= 1;
}
}
chan += 8;
}
/* we should never reach here */
BLE_LL_ASSERT(0);
return 0;
}
uint8_t
ble_ll_utils_calc_num_used_chans(const uint8_t *chmap)
{
int i;
int j;
uint8_t mask;
uint8_t chanbyte;
uint8_t used_channels;
used_channels = 0;
for (i = 0; i < BLE_LL_CHMAP_LEN; ++i) {
chanbyte = chmap[i];
if (chanbyte) {
if (chanbyte == 0xff) {
used_channels += 8;
} else {
mask = 0x01;
for (j = 0; j < 8; ++j) {
if (chanbyte & mask) {
++used_channels;
}
mask <<= 1;
}
}
}
}
return used_channels;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2)
static uint16_t
ble_ll_utils_csa2_perm(uint16_t in)
{
uint16_t out = 0;
int i;
for (i = 0; i < 8; i++) {
out |= ((in >> i) & 0x00000001) << (7 - i);
}
for (i = 8; i < 16; i++) {
out |= ((in >> i) & 0x00000001) << (15 + 8 - i);
}
return out;
}
static uint16_t
ble_ll_utils_csa2_prng(uint16_t counter, uint16_t ch_id)
{
uint16_t prn_e;
prn_e = counter ^ ch_id;
prn_e = ble_ll_utils_csa2_perm(prn_e);
prn_e = (prn_e * 17) + ch_id;
prn_e = ble_ll_utils_csa2_perm(prn_e);
prn_e = (prn_e * 17) + ch_id;
prn_e = ble_ll_utils_csa2_perm(prn_e);
prn_e = (prn_e * 17) + ch_id;
prn_e = prn_e ^ ch_id;
return prn_e;
}
uint8_t
ble_ll_utils_calc_dci_csa2(uint16_t event_cntr, uint16_t channel_id,
uint8_t num_used_chans, const uint8_t *chanmap)
{
uint16_t channel_unmapped;
uint8_t remap_index;
uint16_t prn_e;
uint8_t bitpos;
prn_e = ble_ll_utils_csa2_prng(event_cntr, channel_id);
channel_unmapped = prn_e % 37;
/*
* If unmapped channel is the channel index of a used channel it is used
* as channel index.
*/
bitpos = 1 << (channel_unmapped & 0x07);
if (chanmap[channel_unmapped >> 3] & bitpos) {
return channel_unmapped;
}
remap_index = (num_used_chans * prn_e) / 0x10000;
return ble_ll_utils_remapped_channel(remap_index, chanmap);
}
#endif
uint32_t
ble_ll_utils_calc_window_widening(uint32_t anchor_point,
uint32_t last_anchor_point,
uint8_t master_sca)
{
uint32_t total_sca_ppm;
uint32_t window_widening;
int32_t time_since_last_anchor;
uint32_t delta_msec;
window_widening = 0;
time_since_last_anchor = (int32_t)(anchor_point - last_anchor_point);
if (time_since_last_anchor > 0) {
delta_msec = os_cputime_ticks_to_usecs(time_since_last_anchor) / 1000;
total_sca_ppm = g_ble_sca_ppm_tbl[master_sca] +
MYNEWT_VAL(BLE_LL_OUR_SCA);
window_widening = (total_sca_ppm * delta_msec) / 1000;
}
return window_widening;
}
#endif

View File

@@ -0,0 +1,297 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef ESP_PLATFORM
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#include "nimble/porting/nimble/include/os/os.h"
#include "nimble/nimble/include/nimble/ble.h"
#include "nimble/nimble/include/nimble/nimble_opt.h"
#if defined(ARDUINO_ARCH_NRF5) && defined(NRF51)
#include "nimble/nimble/drivers/nrf51/include/ble/xcvr.h"
#elif defined(ARDUINO_ARCH_NRF5) && defined(NRF52_SERIES)
#include "nimble/nimble/drivers/nrf52/include/ble/xcvr.h"
#endif
#include "../include/controller/ble_ll_whitelist.h"
#include "../include/controller/ble_ll_hci.h"
#include "../include/controller/ble_ll_adv.h"
#include "../include/controller/ble_ll_scan.h"
#include "../include/controller/ble_hw.h"
#if (MYNEWT_VAL(BLE_LL_WHITELIST_SIZE) < BLE_HW_WHITE_LIST_SIZE)
#define BLE_LL_WHITELIST_SIZE MYNEWT_VAL(BLE_LL_WHITELIST_SIZE)
#else
#define BLE_LL_WHITELIST_SIZE BLE_HW_WHITE_LIST_SIZE
#endif
struct ble_ll_whitelist_entry
{
uint8_t wl_valid;
uint8_t wl_addr_type;
uint8_t wl_dev_addr[BLE_DEV_ADDR_LEN];
};
struct ble_ll_whitelist_entry g_ble_ll_whitelist[BLE_LL_WHITELIST_SIZE];
static int
ble_ll_whitelist_chg_allowed(void)
{
int rc;
/*
* This command is not allowed if:
* -> advertising uses the whitelist and we are currently advertising.
* -> scanning uses the whitelist and is enabled.
* -> initiating uses whitelist and a LE create connection command is in
* progress
*/
rc = 1;
if (!ble_ll_adv_can_chg_whitelist() || !ble_ll_scan_can_chg_whitelist()) {
rc = 0;
}
return rc;
}
/**
* Clear the whitelist.
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_ll_whitelist_clear(void)
{
int i;
struct ble_ll_whitelist_entry *wl;
/* Check proper state */
if (!ble_ll_whitelist_chg_allowed()) {
return BLE_ERR_CMD_DISALLOWED;
}
/* Set the number of entries to 0 */
wl = &g_ble_ll_whitelist[0];
for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) {
wl->wl_valid = 0;
++wl;
}
#if (BLE_USES_HW_WHITELIST == 1)
ble_hw_whitelist_clear();
#endif
return BLE_ERR_SUCCESS;
}
/**
* Read the size of the whitelist. This is the total number of whitelist
* entries allowed by the controller.
*
* @param rspbuf Pointer to response buffer
*
* @return int 0: success.
*/
int
ble_ll_whitelist_read_size(uint8_t *rspbuf, uint8_t *rsplen)
{
struct ble_hci_le_rd_white_list_rp *rsp = (void *) rspbuf;
rsp->size = BLE_LL_WHITELIST_SIZE;
*rsplen = sizeof(*rsp);
return BLE_ERR_SUCCESS;
}
/**
* Searches the whitelist to determine if the address is present in the
* whitelist. This is an internal API that only searches the link layer
* whitelist and does not care about the hardware whitelist
*
* @param addr Device or identity address to check.
* @param addr_type Public address (0) or random address (1)
*
* @return int 0: device is not on whitelist; otherwise the return value
* is the 'position' of the device in the whitelist (the index of the element
* plus 1).
*/
static int
ble_ll_whitelist_search(const uint8_t *addr, uint8_t addr_type)
{
int i;
struct ble_ll_whitelist_entry *wl;
wl = &g_ble_ll_whitelist[0];
for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) {
if ((wl->wl_valid) && (wl->wl_addr_type == addr_type) &&
(!memcmp(&wl->wl_dev_addr[0], addr, BLE_DEV_ADDR_LEN))) {
return i + 1;
}
++wl;
}
return 0;
}
/**
* Is there a match between the device and a device on the whitelist.
*
* NOTE: This API uses the HW, if present, to determine if there was a match
* between a received address and an address in the whitelist. If the HW does
* not support whitelisting this API is the same as the whitelist search API
*
* @param addr
* @param addr_type Public address (0) or random address (1)
* @param is_ident True if addr is an identity address; false otherwise
*
* @return int
*/
int
ble_ll_whitelist_match(uint8_t *addr, uint8_t addr_type, int is_ident)
{
int rc;
#if (BLE_USES_HW_WHITELIST == 1)
/*
* XXX: This should be changed. This is HW specific: some HW may be able
* to both resolve a private address and perform a whitelist check. The
* current BLE hw cannot support this.
*/
if (is_ident) {
rc = ble_ll_whitelist_search(addr, addr_type);
} else {
rc = ble_hw_whitelist_match();
}
#else
rc = ble_ll_whitelist_search(addr, addr_type);
#endif
return rc;
}
/**
* Add a device to the whitelist
*
* @return int
*/
int
ble_ll_whitelist_add(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_add_whte_list_cp *cmd = (const void *) cmdbuf;
struct ble_ll_whitelist_entry *wl;
int rc;
int i;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* Must be in proper state */
if (!ble_ll_whitelist_chg_allowed()) {
return BLE_ERR_CMD_DISALLOWED;
}
/* Check if we have any open entries */
rc = BLE_ERR_SUCCESS;
if (!ble_ll_whitelist_search(cmd->addr, cmd->addr_type)) {
wl = &g_ble_ll_whitelist[0];
for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) {
if (wl->wl_valid == 0) {
memcpy(&wl->wl_dev_addr[0], cmd->addr, BLE_DEV_ADDR_LEN);
wl->wl_addr_type = cmd->addr_type;
wl->wl_valid = 1;
break;
}
++wl;
}
if (i == BLE_LL_WHITELIST_SIZE) {
rc = BLE_ERR_MEM_CAPACITY;
} else {
#if (BLE_USES_HW_WHITELIST == 1)
rc = ble_hw_whitelist_add(cmd->addr, cmd->addr_type);
#endif
}
}
return rc;
}
/**
* Remove a device from the whitelist
*
* @param cmdbuf
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_ll_whitelist_rmv(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_le_rmv_white_list_cp *cmd = (const void *) cmdbuf;
int position;
if (len != sizeof(*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* Must be in proper state */
if (!ble_ll_whitelist_chg_allowed()) {
return BLE_ERR_CMD_DISALLOWED;
}
position = ble_ll_whitelist_search(cmd->addr, cmd->addr_type);
if (position) {
g_ble_ll_whitelist[position - 1].wl_valid = 0;
}
#if (BLE_USES_HW_WHITELIST == 1)
ble_hw_whitelist_rmv(cmd->addr, cmd->addr_type);
#endif
return BLE_ERR_SUCCESS;
}
/**
* Enable whitelisting.
*
* Note: This function has no effect if we are not using HW whitelisting
*/
void
ble_ll_whitelist_enable(void)
{
#if (BLE_USES_HW_WHITELIST == 1)
ble_hw_whitelist_enable();
#endif
}
/**
* Disable whitelisting.
*
* Note: This function has no effect if we are not using HW whitelisting
*/
void
ble_ll_whitelist_disable(void)
{
#if (BLE_USES_HW_WHITELIST == 1)
ble_hw_whitelist_disable();
#endif
}
#endif

View File

@@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#if defined(ARDUINO_ARCH_NRF5) && defined(NRF51)
#ifndef H_BLE_XCVR_
#define H_BLE_XCVR_
#ifdef __cplusplus
extern "C" {
#endif
/* Transceiver specific defintions */
/* NOTE: we have to account for the RTC output compare issue */
#define XCVR_PROC_DELAY_USECS (230)
#define XCVR_RX_START_DELAY_USECS (140)
#define XCVR_TX_START_DELAY_USECS (140)
#define XCVR_TX_SCHED_DELAY_USECS \
(XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
#define XCVR_RX_SCHED_DELAY_USECS \
(XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
/*
* Define HW whitelist size. This is the total possible whitelist size;
* not necessarily the size that will be used (may be smaller)
*/
#define BLE_HW_WHITE_LIST_SIZE (8)
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_XCVR_ */
#endif

View File

@@ -0,0 +1,491 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#if defined(ARDUINO_ARCH_NRF5) && defined(NRF51)
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#include "nimble/porting/nimble/include/os/os.h"
#include "../include/ble/xcvr.h"
#include "nimble/nimble/include/nimble/ble.h"
#include "nimble/nimble/include/nimble/nimble_opt.h"
#include "nrf.h"
#include "nimble/nimble/controller/include/controller/ble_hw.h"
#if MYNEWT
#include "mcu/cmsis_nvic.h"
#else
#include "core_cm0.h"
#include "nimble/porting/npl/freertos/include/nimble/nimble_npl_os.h"
#endif
#include "nimble/porting/nimble/include/os/os_trace_api.h"
/* Total number of resolving list elements */
#define BLE_HW_RESOLV_LIST_SIZE (16)
/* We use this to keep track of which entries are set to valid addresses */
static uint8_t g_ble_hw_whitelist_mask;
/* Random number generator isr callback */
ble_rng_isr_cb_t g_ble_rng_isr_cb;
/* If LL privacy is enabled, allocate memory for AAR */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
/* The NRF51 supports up to 16 IRK entries */
#if (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE) < 16)
#define NRF_IRK_LIST_ENTRIES (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE))
#else
#define NRF_IRK_LIST_ENTRIES (16)
#endif
/* NOTE: each entry is 16 bytes long. */
uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4];
/* Current number of IRK entries */
uint8_t g_nrf_num_irks;
#endif
/* Returns public device address or -1 if not present */
int
ble_hw_get_public_addr(ble_addr_t *addr)
{
uint32_t addr_high;
uint32_t addr_low;
/* Does FICR have a public address */
if ((NRF_FICR->DEVICEADDRTYPE & 1) != 0) {
return -1;
}
/* Copy into device address. We can do this because we know platform */
addr_low = NRF_FICR->DEVICEADDR[0];
addr_high = NRF_FICR->DEVICEADDR[1];
memcpy(addr->val, &addr_low, 4);
memcpy(&addr->val[4], &addr_high, 2);
addr->type = BLE_ADDR_PUBLIC;
return 0;
}
/* Returns random static address or -1 if not present */
int
ble_hw_get_static_addr(ble_addr_t *addr)
{
int rc;
if ((NRF_FICR->DEVICEADDRTYPE & 1) == 1) {
memcpy(addr->val, (void *)&NRF_FICR->DEVICEADDR[0], 4);
memcpy(&addr->val[4], (void *)&NRF_FICR->DEVICEADDR[1], 2);
addr->val[5] |= 0xc0;
addr->type = BLE_ADDR_RANDOM;
rc = 0;
} else {
rc = -1;
}
return rc;
}
/**
* Clear the whitelist
*
* @return int
*/
void
ble_hw_whitelist_clear(void)
{
NRF_RADIO->DACNF = 0;
g_ble_hw_whitelist_mask = 0;
}
/**
* Add a device to the hw whitelist
*
* @param addr
* @param addr_type
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type)
{
int i;
uint32_t mask;
/* Find first ununsed device address match element */
mask = 0x01;
for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
if ((mask & g_ble_hw_whitelist_mask) == 0) {
NRF_RADIO->DAB[i] = get_le32(addr);
NRF_RADIO->DAP[i] = get_le16(addr + 4);
if (addr_type == BLE_ADDR_RANDOM) {
NRF_RADIO->DACNF |= (mask << 8);
}
g_ble_hw_whitelist_mask |= mask;
return BLE_ERR_SUCCESS;
}
mask <<= 1;
}
return BLE_ERR_MEM_CAPACITY;
}
/**
* Remove a device from the hw whitelist
*
* @param addr
* @param addr_type
*
*/
void
ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type)
{
int i;
uint8_t cfg_addr;
uint16_t dap;
uint16_t txadd;
uint32_t dab;
uint32_t mask;
/* Find first ununsed device address match element */
dab = get_le32(addr);
dap = get_le16(addr + 4);
txadd = NRF_RADIO->DACNF >> 8;
mask = 0x01;
for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
if (mask & g_ble_hw_whitelist_mask) {
if ((dab == NRF_RADIO->DAB[i]) && (dap == NRF_RADIO->DAP[i])) {
cfg_addr = txadd & mask;
if (addr_type == BLE_ADDR_RANDOM) {
if (cfg_addr != 0) {
break;
}
} else {
if (cfg_addr == 0) {
break;
}
}
}
}
mask <<= 1;
}
if (i < BLE_HW_WHITE_LIST_SIZE) {
g_ble_hw_whitelist_mask &= ~mask;
NRF_RADIO->DACNF &= ~mask;
}
}
/**
* Returns the size of the whitelist in HW
*
* @return int Number of devices allowed in whitelist
*/
uint8_t
ble_hw_whitelist_size(void)
{
return BLE_HW_WHITE_LIST_SIZE;
}
/**
* Enable the whitelisted devices
*/
void
ble_hw_whitelist_enable(void)
{
/* Enable the configured device addresses */
NRF_RADIO->DACNF |= g_ble_hw_whitelist_mask;
}
/**
* Disables the whitelisted devices
*/
void
ble_hw_whitelist_disable(void)
{
/* Disable all whitelist devices */
NRF_RADIO->DACNF &= 0x0000ff00;
}
/**
* Boolean function which returns true ('1') if there is a match on the
* whitelist.
*
* @return int
*/
int
ble_hw_whitelist_match(void)
{
return (int)NRF_RADIO->EVENTS_DEVMATCH;
}
/* Encrypt data */
int
ble_hw_encrypt_block(struct ble_encryption_block *ecb)
{
int rc;
uint32_t end;
uint32_t err;
/* Stop ECB */
NRF_ECB->TASKS_STOPECB = 1;
/* XXX: does task stop clear these counters? Anyway to do this quicker? */
NRF_ECB->EVENTS_ENDECB = 0;
NRF_ECB->EVENTS_ERRORECB = 0;
NRF_ECB->ECBDATAPTR = (uint32_t)ecb;
/* Start ECB */
NRF_ECB->TASKS_STARTECB = 1;
/* Wait till error or done */
rc = 0;
while (1) {
end = NRF_ECB->EVENTS_ENDECB;
err = NRF_ECB->EVENTS_ERRORECB;
if (end || err) {
if (err) {
rc = -1;
}
break;
}
}
return rc;
}
/**
* Random number generator ISR.
*/
static void
ble_rng_isr(void)
{
uint8_t rnum;
os_trace_isr_enter();
/* No callback? Clear and disable interrupts */
if (g_ble_rng_isr_cb == NULL) {
NRF_RNG->INTENCLR = 1;
NRF_RNG->EVENTS_VALRDY = 0;
(void)NRF_RNG->SHORTS;
os_trace_isr_exit();
return;
}
/* If there is a value ready grab it */
if (NRF_RNG->EVENTS_VALRDY) {
NRF_RNG->EVENTS_VALRDY = 0;
rnum = (uint8_t)NRF_RNG->VALUE;
(*g_ble_rng_isr_cb)(rnum);
}
os_trace_isr_exit();
}
/**
* Initialize the random number generator
*
* @param cb
* @param bias
*
* @return int
*/
int
ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
{
/* Set bias */
if (bias) {
NRF_RNG->CONFIG = 1;
} else {
NRF_RNG->CONFIG = 0;
}
/* If we were passed a function pointer we need to enable the interrupt */
if (cb != NULL) {
#ifndef RIOT_VERSION
NVIC_SetPriority(RNG_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
#endif
#if MYNEWT
NVIC_SetVector(RNG_IRQn, (uint32_t)ble_rng_isr);
#else
ble_npl_hw_set_isr(RNG_IRQn, ble_rng_isr);
#endif
NVIC_EnableIRQ(RNG_IRQn);
g_ble_rng_isr_cb = cb;
}
return 0;
}
/**
* Start the random number generator
*
* @return int
*/
int
ble_hw_rng_start(void)
{
os_sr_t sr;
/* No need for interrupt if there is no callback */
OS_ENTER_CRITICAL(sr);
NRF_RNG->EVENTS_VALRDY = 0;
if (g_ble_rng_isr_cb) {
NRF_RNG->INTENSET = 1;
}
NRF_RNG->TASKS_START = 1;
OS_EXIT_CRITICAL(sr);
return 0;
}
/**
* Stop the random generator
*
* @return int
*/
int
ble_hw_rng_stop(void)
{
os_sr_t sr;
/* No need for interrupt if there is no callback */
OS_ENTER_CRITICAL(sr);
NRF_RNG->INTENCLR = 1;
NRF_RNG->TASKS_STOP = 1;
NRF_RNG->EVENTS_VALRDY = 0;
OS_EXIT_CRITICAL(sr);
return 0;
}
/**
* Read the random number generator.
*
* @return uint8_t
*/
uint8_t
ble_hw_rng_read(void)
{
uint8_t rnum;
/* Wait for a sample */
while (NRF_RNG->EVENTS_VALRDY == 0) {
}
NRF_RNG->EVENTS_VALRDY = 0;
rnum = (uint8_t)NRF_RNG->VALUE;
return rnum;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
/**
* Clear the resolving list
*
* @return int
*/
void
ble_hw_resolv_list_clear(void)
{
g_nrf_num_irks = 0;
}
/**
* Add a device to the hw resolving list
*
* @param irk Pointer to IRK to add
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_hw_resolv_list_add(uint8_t *irk)
{
uint32_t *nrf_entry;
/* Find first ununsed device address match element */
if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) {
return BLE_ERR_MEM_CAPACITY;
}
/* Copy into irk list */
nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks];
memcpy(nrf_entry, irk, 16);
/* Add to total */
++g_nrf_num_irks;
return BLE_ERR_SUCCESS;
}
/**
* Remove a device from the hw resolving list
*
* @param index Index of IRK to remove
*/
void
ble_hw_resolv_list_rmv(int index)
{
uint32_t *irk_entry;
if (index < g_nrf_num_irks) {
--g_nrf_num_irks;
irk_entry = &g_nrf_irk_list[index];
if (g_nrf_num_irks > index) {
memmove(irk_entry, irk_entry + 4, 16 * (g_nrf_num_irks - index));
}
}
}
/**
* Returns the size of the resolving list. NOTE: this returns the maximum
* allowable entries in the HW. Configuration options may limit this.
*
* @return int Number of devices allowed in resolving list
*/
uint8_t
ble_hw_resolv_list_size(void)
{
return BLE_HW_RESOLV_LIST_SIZE;
}
/**
* Called to determine if the address received was resolved.
*
* @return int Negative values indicate unresolved address; positive values
* indicate index in resolving list of resolved address.
*/
int
ble_hw_resolv_list_match(void)
{
uint32_t index;
if (NRF_AAR->EVENTS_END) {
if (NRF_AAR->EVENTS_RESOLVED) {
index = NRF_AAR->STATUS;
return (int)index;
}
}
return -1;
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#if defined(ARDUINO_ARCH_NRF5) && defined(NRF52_SERIES)
#ifndef H_BLE_XCVR_
#define H_BLE_XCVR_
#ifdef __cplusplus
extern "C" {
#endif
#define XCVR_RX_RADIO_RAMPUP_USECS (40)
#define XCVR_TX_RADIO_RAMPUP_USECS (40)
/*
* NOTE: we have to account for the RTC output compare issue. We want it to be
* 5 ticks.
*/
#define XCVR_PROC_DELAY_USECS (153)
#define XCVR_RX_START_DELAY_USECS (XCVR_RX_RADIO_RAMPUP_USECS)
#define XCVR_TX_START_DELAY_USECS (XCVR_TX_RADIO_RAMPUP_USECS)
#define XCVR_TX_SCHED_DELAY_USECS \
(XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
#define XCVR_RX_SCHED_DELAY_USECS \
(XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
/*
* Define HW whitelist size. This is the total possible whitelist size;
* not necessarily the size that will be used (may be smaller)
*/
#define BLE_HW_WHITE_LIST_SIZE (8)
#ifdef __cplusplus
}
#endif
#endif /* H_BLE_XCVR_ */
#endif

View File

@@ -0,0 +1,491 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#if defined(ARDUINO_ARCH_NRF5) && defined(NRF52_SERIES)
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#include "nimble/porting/nimble/include/os/os.h"
#include "../include/ble/xcvr.h"
#include "nimble/nimble/include/nimble/ble.h"
#include "nimble/nimble/include/nimble/nimble_opt.h"
#include "nrf.h"
#include "nimble/nimble/controller/include/controller/ble_hw.h"
#if MYNEWT
#include "mcu/cmsis_nvic.h"
#else
#include "core_cm4.h"
#include "nimble/porting/npl/freertos/include/nimble/nimble_npl_os.h"
#endif
#include "nimble/porting/nimble/include/os/os_trace_api.h"
/* Total number of resolving list elements */
#define BLE_HW_RESOLV_LIST_SIZE (16)
/* We use this to keep track of which entries are set to valid addresses */
static uint8_t g_ble_hw_whitelist_mask;
/* Random number generator isr callback */
ble_rng_isr_cb_t g_ble_rng_isr_cb;
/* If LL privacy is enabled, allocate memory for AAR */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
/* The NRF51 supports up to 16 IRK entries */
#if (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE) < 16)
#define NRF_IRK_LIST_ENTRIES (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE))
#else
#define NRF_IRK_LIST_ENTRIES (16)
#endif
/* NOTE: each entry is 16 bytes long. */
uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4];
/* Current number of IRK entries */
uint8_t g_nrf_num_irks;
#endif
/* Returns public device address or -1 if not present */
int
ble_hw_get_public_addr(ble_addr_t *addr)
{
uint32_t addr_high;
uint32_t addr_low;
/* Does FICR have a public address */
if ((NRF_FICR->DEVICEADDRTYPE & 1) != 0) {
return -1;
}
/* Copy into device address. We can do this because we know platform */
addr_low = NRF_FICR->DEVICEADDR[0];
addr_high = NRF_FICR->DEVICEADDR[1];
memcpy(addr->val, &addr_low, 4);
memcpy(&addr->val[4], &addr_high, 2);
addr->type = BLE_ADDR_PUBLIC;
return 0;
}
/* Returns random static address or -1 if not present */
int
ble_hw_get_static_addr(ble_addr_t *addr)
{
int rc;
if ((NRF_FICR->DEVICEADDRTYPE & 1) == 1) {
memcpy(addr->val, (void *)&NRF_FICR->DEVICEADDR[0], 4);
memcpy(&addr->val[4], (void *)&NRF_FICR->DEVICEADDR[1], 2);
addr->val[5] |= 0xc0;
addr->type = BLE_ADDR_RANDOM;
rc = 0;
} else {
rc = -1;
}
return rc;
}
/**
* Clear the whitelist
*
* @return int
*/
void
ble_hw_whitelist_clear(void)
{
NRF_RADIO->DACNF = 0;
g_ble_hw_whitelist_mask = 0;
}
/**
* Add a device to the hw whitelist
*
* @param addr
* @param addr_type
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type)
{
int i;
uint32_t mask;
/* Find first ununsed device address match element */
mask = 0x01;
for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
if ((mask & g_ble_hw_whitelist_mask) == 0) {
NRF_RADIO->DAB[i] = get_le32(addr);
NRF_RADIO->DAP[i] = get_le16(addr + 4);
if (addr_type == BLE_ADDR_RANDOM) {
NRF_RADIO->DACNF |= (mask << 8);
}
g_ble_hw_whitelist_mask |= mask;
return BLE_ERR_SUCCESS;
}
mask <<= 1;
}
return BLE_ERR_MEM_CAPACITY;
}
/**
* Remove a device from the hw whitelist
*
* @param addr
* @param addr_type
*
*/
void
ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type)
{
int i;
uint8_t cfg_addr;
uint16_t dap;
uint16_t txadd;
uint32_t dab;
uint32_t mask;
/* Find first ununsed device address match element */
dab = get_le32(addr);
dap = get_le16(addr + 4);
txadd = NRF_RADIO->DACNF >> 8;
mask = 0x01;
for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
if (mask & g_ble_hw_whitelist_mask) {
if ((dab == NRF_RADIO->DAB[i]) && (dap == NRF_RADIO->DAP[i])) {
cfg_addr = txadd & mask;
if (addr_type == BLE_ADDR_RANDOM) {
if (cfg_addr != 0) {
break;
}
} else {
if (cfg_addr == 0) {
break;
}
}
}
}
mask <<= 1;
}
if (i < BLE_HW_WHITE_LIST_SIZE) {
g_ble_hw_whitelist_mask &= ~mask;
NRF_RADIO->DACNF &= ~mask;
}
}
/**
* Returns the size of the whitelist in HW
*
* @return int Number of devices allowed in whitelist
*/
uint8_t
ble_hw_whitelist_size(void)
{
return BLE_HW_WHITE_LIST_SIZE;
}
/**
* Enable the whitelisted devices
*/
void
ble_hw_whitelist_enable(void)
{
/* Enable the configured device addresses */
NRF_RADIO->DACNF |= g_ble_hw_whitelist_mask;
}
/**
* Disables the whitelisted devices
*/
void
ble_hw_whitelist_disable(void)
{
/* Disable all whitelist devices */
NRF_RADIO->DACNF &= 0x0000ff00;
}
/**
* Boolean function which returns true ('1') if there is a match on the
* whitelist.
*
* @return int
*/
int
ble_hw_whitelist_match(void)
{
return (int)NRF_RADIO->EVENTS_DEVMATCH;
}
/* Encrypt data */
int
ble_hw_encrypt_block(struct ble_encryption_block *ecb)
{
int rc;
uint32_t end;
uint32_t err;
/* Stop ECB */
NRF_ECB->TASKS_STOPECB = 1;
/* XXX: does task stop clear these counters? Anyway to do this quicker? */
NRF_ECB->EVENTS_ENDECB = 0;
NRF_ECB->EVENTS_ERRORECB = 0;
NRF_ECB->ECBDATAPTR = (uint32_t)ecb;
/* Start ECB */
NRF_ECB->TASKS_STARTECB = 1;
/* Wait till error or done */
rc = 0;
while (1) {
end = NRF_ECB->EVENTS_ENDECB;
err = NRF_ECB->EVENTS_ERRORECB;
if (end || err) {
if (err) {
rc = -1;
}
break;
}
}
return rc;
}
/**
* Random number generator ISR.
*/
static void
ble_rng_isr(void)
{
uint8_t rnum;
os_trace_isr_enter();
/* No callback? Clear and disable interrupts */
if (g_ble_rng_isr_cb == NULL) {
NRF_RNG->INTENCLR = 1;
NRF_RNG->EVENTS_VALRDY = 0;
(void)NRF_RNG->SHORTS;
os_trace_isr_exit();
return;
}
/* If there is a value ready grab it */
if (NRF_RNG->EVENTS_VALRDY) {
NRF_RNG->EVENTS_VALRDY = 0;
rnum = (uint8_t)NRF_RNG->VALUE;
(*g_ble_rng_isr_cb)(rnum);
}
os_trace_isr_exit();
}
/**
* Initialize the random number generator
*
* @param cb
* @param bias
*
* @return int
*/
int
ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
{
/* Set bias */
if (bias) {
NRF_RNG->CONFIG = 1;
} else {
NRF_RNG->CONFIG = 0;
}
/* If we were passed a function pointer we need to enable the interrupt */
if (cb != NULL) {
#ifndef RIOT_VERSION
NVIC_SetPriority(RNG_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
#endif
#if MYNEWT
NVIC_SetVector(RNG_IRQn, (uint32_t)ble_rng_isr);
#else
ble_npl_hw_set_isr(RNG_IRQn, ble_rng_isr);
#endif
NVIC_EnableIRQ(RNG_IRQn);
g_ble_rng_isr_cb = cb;
}
return 0;
}
/**
* Start the random number generator
*
* @return int
*/
int
ble_hw_rng_start(void)
{
os_sr_t sr;
/* No need for interrupt if there is no callback */
OS_ENTER_CRITICAL(sr);
NRF_RNG->EVENTS_VALRDY = 0;
if (g_ble_rng_isr_cb) {
NRF_RNG->INTENSET = 1;
}
NRF_RNG->TASKS_START = 1;
OS_EXIT_CRITICAL(sr);
return 0;
}
/**
* Stop the random generator
*
* @return int
*/
int
ble_hw_rng_stop(void)
{
os_sr_t sr;
/* No need for interrupt if there is no callback */
OS_ENTER_CRITICAL(sr);
NRF_RNG->INTENCLR = 1;
NRF_RNG->TASKS_STOP = 1;
NRF_RNG->EVENTS_VALRDY = 0;
OS_EXIT_CRITICAL(sr);
return 0;
}
/**
* Read the random number generator.
*
* @return uint8_t
*/
uint8_t
ble_hw_rng_read(void)
{
uint8_t rnum;
/* Wait for a sample */
while (NRF_RNG->EVENTS_VALRDY == 0) {
}
NRF_RNG->EVENTS_VALRDY = 0;
rnum = (uint8_t)NRF_RNG->VALUE;
return rnum;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
/**
* Clear the resolving list
*
* @return int
*/
void
ble_hw_resolv_list_clear(void)
{
g_nrf_num_irks = 0;
}
/**
* Add a device to the hw resolving list
*
* @param irk Pointer to IRK to add
*
* @return int 0: success, BLE error code otherwise
*/
int
ble_hw_resolv_list_add(uint8_t *irk)
{
uint32_t *nrf_entry;
/* Find first ununsed device address match element */
if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) {
return BLE_ERR_MEM_CAPACITY;
}
/* Copy into irk list */
nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks];
memcpy(nrf_entry, irk, 16);
/* Add to total */
++g_nrf_num_irks;
return BLE_ERR_SUCCESS;
}
/**
* Remove a device from the hw resolving list
*
* @param index Index of IRK to remove
*/
void
ble_hw_resolv_list_rmv(int index)
{
uint32_t *irk_entry;
if (index < g_nrf_num_irks) {
--g_nrf_num_irks;
irk_entry = &g_nrf_irk_list[index];
if (g_nrf_num_irks > index) {
memmove(irk_entry, irk_entry + 4, 16 * (g_nrf_num_irks - index));
}
}
}
/**
* Returns the size of the resolving list. NOTE: this returns the maximum
* allowable entries in the HW. Configuration options may limit this.
*
* @return int Number of devices allowed in resolving list
*/
uint8_t
ble_hw_resolv_list_size(void)
{
return BLE_HW_RESOLV_LIST_SIZE;
}
/**
* Called to determine if the address received was resolved.
*
* @return int Negative values indicate unresolved address; positive values
* indicate index in resolving list of resolved address.
*/
int
ble_hw_resolv_list_match(void)
{
uint32_t index;
if (NRF_AAR->EVENTS_END) {
if (NRF_AAR->EVENTS_RESOLVED) {
index = NRF_AAR->STATUS;
return (int)index;
}
}
return -1;
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#if defined(ARDUINO_ARCH_NRF5) && defined(NRF52_SERIES)
#include <stdint.h>
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#include "nimble/porting/nimble/include/os/os_trace_api.h"
#if MYNEWT_VAL(BLE_PHY_SYSVIEW)
static os_trace_module_t g_ble_phy_trace_mod;
uint32_t ble_phy_trace_off;
static void
ble_phy_trace_module_send_desc(void)
{
os_trace_module_desc(&g_ble_phy_trace_mod, "0 phy_set_tx cputime=%u usecs=%u");
os_trace_module_desc(&g_ble_phy_trace_mod, "1 phy_set_rx cputime=%u usecs=%u");
os_trace_module_desc(&g_ble_phy_trace_mod, "2 phy_disable");
}
void
ble_phy_trace_init(void)
{
ble_phy_trace_off =
os_trace_module_register(&g_ble_phy_trace_mod, "ble_phy", 3,
ble_phy_trace_module_send_desc);
}
#endif
#endif

View File

@@ -0,0 +1,194 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_ATT_
#define H_BLE_ATT_
/**
* @brief Bluetooth Attribute Protocol (ATT)
* @defgroup bt_att Bluetooth Attribute Protocol (ATT)
* @ingroup bt_host
* @{
*/
#include "nimble/porting/nimble/include/os/queue.h"
#ifdef __cplusplus
extern "C" {
#endif
struct os_mbuf;
#define BLE_ATT_UUID_PRIMARY_SERVICE 0x2800
#define BLE_ATT_UUID_SECONDARY_SERVICE 0x2801
#define BLE_ATT_UUID_INCLUDE 0x2802
#define BLE_ATT_UUID_CHARACTERISTIC 0x2803
#define BLE_ATT_ERR_INVALID_HANDLE 0x01
#define BLE_ATT_ERR_READ_NOT_PERMITTED 0x02
#define BLE_ATT_ERR_WRITE_NOT_PERMITTED 0x03
#define BLE_ATT_ERR_INVALID_PDU 0x04
#define BLE_ATT_ERR_INSUFFICIENT_AUTHEN 0x05
#define BLE_ATT_ERR_REQ_NOT_SUPPORTED 0x06
#define BLE_ATT_ERR_INVALID_OFFSET 0x07
#define BLE_ATT_ERR_INSUFFICIENT_AUTHOR 0x08
#define BLE_ATT_ERR_PREPARE_QUEUE_FULL 0x09
#define BLE_ATT_ERR_ATTR_NOT_FOUND 0x0a
#define BLE_ATT_ERR_ATTR_NOT_LONG 0x0b
#define BLE_ATT_ERR_INSUFFICIENT_KEY_SZ 0x0c
#define BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN 0x0d
#define BLE_ATT_ERR_UNLIKELY 0x0e
#define BLE_ATT_ERR_INSUFFICIENT_ENC 0x0f
#define BLE_ATT_ERR_UNSUPPORTED_GROUP 0x10
#define BLE_ATT_ERR_INSUFFICIENT_RES 0x11
#define BLE_ATT_OP_ERROR_RSP 0x01
#define BLE_ATT_OP_MTU_REQ 0x02
#define BLE_ATT_OP_MTU_RSP 0x03
#define BLE_ATT_OP_FIND_INFO_REQ 0x04
#define BLE_ATT_OP_FIND_INFO_RSP 0x05
#define BLE_ATT_OP_FIND_TYPE_VALUE_REQ 0x06
#define BLE_ATT_OP_FIND_TYPE_VALUE_RSP 0x07
#define BLE_ATT_OP_READ_TYPE_REQ 0x08
#define BLE_ATT_OP_READ_TYPE_RSP 0x09
#define BLE_ATT_OP_READ_REQ 0x0a
#define BLE_ATT_OP_READ_RSP 0x0b
#define BLE_ATT_OP_READ_BLOB_REQ 0x0c
#define BLE_ATT_OP_READ_BLOB_RSP 0x0d
#define BLE_ATT_OP_READ_MULT_REQ 0x0e
#define BLE_ATT_OP_READ_MULT_RSP 0x0f
#define BLE_ATT_OP_READ_GROUP_TYPE_REQ 0x10
#define BLE_ATT_OP_READ_GROUP_TYPE_RSP 0x11
#define BLE_ATT_OP_WRITE_REQ 0x12
#define BLE_ATT_OP_WRITE_RSP 0x13
#define BLE_ATT_OP_PREP_WRITE_REQ 0x16
#define BLE_ATT_OP_PREP_WRITE_RSP 0x17
#define BLE_ATT_OP_EXEC_WRITE_REQ 0x18
#define BLE_ATT_OP_EXEC_WRITE_RSP 0x19
#define BLE_ATT_OP_NOTIFY_REQ 0x1b
#define BLE_ATT_OP_INDICATE_REQ 0x1d
#define BLE_ATT_OP_INDICATE_RSP 0x1e
#define BLE_ATT_OP_WRITE_CMD 0x52
#define BLE_ATT_ATTR_MAX_LEN 512
#define BLE_ATT_F_READ 0x01
#define BLE_ATT_F_WRITE 0x02
#define BLE_ATT_F_READ_ENC 0x04
#define BLE_ATT_F_READ_AUTHEN 0x08
#define BLE_ATT_F_READ_AUTHOR 0x10
#define BLE_ATT_F_WRITE_ENC 0x20
#define BLE_ATT_F_WRITE_AUTHEN 0x40
#define BLE_ATT_F_WRITE_AUTHOR 0x80
#define HA_FLAG_PERM_RW (BLE_ATT_F_READ | BLE_ATT_F_WRITE)
#define BLE_ATT_ACCESS_OP_READ 1
#define BLE_ATT_ACCESS_OP_WRITE 2
/** Default ATT MTU. Also the minimum. */
#define BLE_ATT_MTU_DFLT 23
/**
* An ATT MTU of 527 allows the largest ATT command (signed write) to contain a
* 512-byte attribute value.
*/
#define BLE_ATT_MTU_MAX 527
/**
* Reads a locally registered attribute. If the specified attribute handle
* corresponds to a GATT characteristic value or descriptor, the read is
* performed by calling the registered GATT access callback.
*
* @param attr_handle The 16-bit handle of the attribute to read.
* @param out_om On success, this is made to point to a
* newly-allocated mbuf containing the
* attribute data read.
*
* @return 0 on success;
* NimBLE host ATT return code if the attribute
* access callback reports failure;
* NimBLE host core return code on unexpected
* error.
*/
int ble_att_svr_read_local(uint16_t attr_handle, struct os_mbuf **out_om);
/**
* Writes a locally registered attribute. This function consumes the supplied
* mbuf regardless of the outcome. If the specified attribute handle
* corresponds to a GATT characteristic value or descriptor, the write is
* performed by calling the registered GATT access callback.
*
* @param attr_handle The 16-bit handle of the attribute to write.
* @param om The value to write to the attribute.
*
* @return 0 on success;
* NimBLE host ATT return code if the attribute
* access callback reports failure;
* NimBLE host core return code on unexpected
* error.
*/
int ble_att_svr_write_local(uint16_t attr_handle, struct os_mbuf *om);
/**
* Retrieves the ATT MTU of the specified connection. If an MTU exchange for
* this connection has occurred, the MTU is the lower of the two peers'
* preferred values. Otherwise, the MTU is the default value of 23.
*
* @param conn_handle The handle of the connection to query.
*
* @return The specified connection's ATT MTU, or 0 if
* there is no such connection.
*/
uint16_t ble_att_mtu(uint16_t conn_handle);
/**
* Retrieves the preferred ATT MTU. This is the value indicated by the device
* during an ATT MTU exchange.
*
* @return The preferred ATT MTU.
*/
uint16_t ble_att_preferred_mtu(void);
/**
* Sets the preferred ATT MTU; the device will indicate this value in all
* subsequent ATT MTU exchanges. The ATT MTU of a connection is equal to the
* lower of the two peers' preferred MTU values. The ATT MTU is what dictates
* the maximum size of any message sent during a GATT procedure.
*
* The specified MTU must be within the following range: [23, BLE_ATT_MTU_MAX].
* 23 is a minimum imposed by the Bluetooth specification; BLE_ATT_MTU_MAX is a
* NimBLE compile-time setting.
*
* @param mtu The preferred ATT MTU.
*
* @return 0 on success;
* BLE_HS_EINVAL if the specified value is not
* within the allowed range.
*/
int ble_att_set_preferred_mtu(uint16_t mtu);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif

View File

@@ -0,0 +1,117 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_EDDYSTONE_
#define H_BLE_EDDYSTONE_
/**
* @brief Eddystone - BLE beacon from Google
* @defgroup bt_eddystone Eddystone - BLE beacon from Google
* @ingroup bt_host
* @{
*/
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
struct ble_hs_adv_fields;
#define BLE_EDDYSTONE_MAX_UUIDS16 3
#define BLE_EDDYSTONE_URL_MAX_LEN 17
#define BLE_EDDYSTONE_URL_SCHEME_HTTP_WWW 0
#define BLE_EDDYSTONE_URL_SCHEME_HTTPS_WWW 1
#define BLE_EDDYSTONE_URL_SCHEME_HTTP 2
#define BLE_EDDYSTONE_URL_SCHEME_HTTPS 3
#define BLE_EDDYSTONE_URL_SUFFIX_COM_SLASH 0x00
#define BLE_EDDYSTONE_URL_SUFFIX_ORG_SLASH 0x01
#define BLE_EDDYSTONE_URL_SUFFIX_EDU_SLASH 0x02
#define BLE_EDDYSTONE_URL_SUFFIX_NET_SLASH 0x03
#define BLE_EDDYSTONE_URL_SUFFIX_INFO_SLASH 0x04
#define BLE_EDDYSTONE_URL_SUFFIX_BIZ_SLASH 0x05
#define BLE_EDDYSTONE_URL_SUFFIX_GOV_SLASH 0x06
#define BLE_EDDYSTONE_URL_SUFFIX_COM 0x07
#define BLE_EDDYSTONE_URL_SUFFIX_ORG 0x08
#define BLE_EDDYSTONE_URL_SUFFIX_EDU 0x09
#define BLE_EDDYSTONE_URL_SUFFIX_NET 0x0a
#define BLE_EDDYSTONE_URL_SUFFIX_INFO 0x0b
#define BLE_EDDYSTONE_URL_SUFFIX_BIZ 0x0c
#define BLE_EDDYSTONE_URL_SUFFIX_GOV 0x0d
#define BLE_EDDYSTONE_URL_SUFFIX_NONE 0xff
/**
* Configures the device to advertise Eddystone UID beacons.
*
* @param adv_fields The base advertisement fields to transform into
* an eddystone beacon. All configured fields
* are preserved; you probably want to clear
* this struct before calling this function.
* @param uid The 16-byte UID to advertise.
* @param measured_power The Measured Power (RSSI value at 0 Meter).
*
* @return 0 on success;
* BLE_HS_EBUSY if advertising is in progress;
* BLE_HS_EMSGSIZE if the specified data is too
* large to fit in an advertisement;
* Other nonzero on failure.
*/
int ble_eddystone_set_adv_data_uid(struct ble_hs_adv_fields *adv_fields,
void *uid, int8_t measured_power);
/**
* Configures the device to advertise Eddystone URL beacons.
*
* @param adv_fields The base advertisement fields to transform into
* an eddystone beacon. All configured fields
* are preserved; you probably want to clear
* this struct before calling this function.
* @param url_scheme The prefix of the URL; one of the
* BLE_EDDYSTONE_URL_SCHEME values.
* @param url_body The middle of the URL. Don't include the
* suffix if there is a suitable suffix code.
* @param url_body_len The string length of the url_body argument.
* @param url_suffix The suffix of the URL; one of the
* BLE_EDDYSTONE_URL_SUFFIX values; use
* BLE_EDDYSTONE_URL_SUFFIX_NONE if the suffix
* is embedded in the body argument.
* @param measured_power The Measured Power (RSSI value at 0 Meter).
*
* @return 0 on success;
* BLE_HS_EBUSY if advertising is in progress;
* BLE_HS_EMSGSIZE if the specified data is too
* large to fit in an advertisement;
* Other nonzero on failure.
*/
int ble_eddystone_set_adv_data_url(struct ble_hs_adv_fields *adv_fields,
uint8_t url_scheme, char *url_body,
uint8_t url_body_len, uint8_t suffix,
int8_t measured_power);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,902 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_GATT_
#define H_BLE_GATT_
/**
* @brief Bluetooth Generic Attribute Profile (GATT)
* @defgroup bt_gatt Bluetooth Generic Attribute Profile (GATT)
* @ingroup bt_host
* @{
*/
#include <inttypes.h>
#include "ble_att.h"
#include "ble_uuid.h"
#ifdef __cplusplus
extern "C" {
#endif
struct ble_hs_conn;
struct ble_att_error_rsp;
struct ble_hs_cfg;
#define BLE_GATT_REGISTER_OP_SVC 1
#define BLE_GATT_REGISTER_OP_CHR 2
#define BLE_GATT_REGISTER_OP_DSC 3
#define BLE_GATT_SVC_UUID16 0x1801
#define BLE_GATT_DSC_CLT_CFG_UUID16 0x2902
#define BLE_GATT_CHR_PROP_BROADCAST 0x01
#define BLE_GATT_CHR_PROP_READ 0x02
#define BLE_GATT_CHR_PROP_WRITE_NO_RSP 0x04
#define BLE_GATT_CHR_PROP_WRITE 0x08
#define BLE_GATT_CHR_PROP_NOTIFY 0x10
#define BLE_GATT_CHR_PROP_INDICATE 0x20
#define BLE_GATT_CHR_PROP_AUTH_SIGN_WRITE 0x40
#define BLE_GATT_CHR_PROP_EXTENDED 0x80
#define BLE_GATT_ACCESS_OP_READ_CHR 0
#define BLE_GATT_ACCESS_OP_WRITE_CHR 1
#define BLE_GATT_ACCESS_OP_READ_DSC 2
#define BLE_GATT_ACCESS_OP_WRITE_DSC 3
#define BLE_GATT_CHR_F_BROADCAST 0x0001
#define BLE_GATT_CHR_F_READ 0x0002
#define BLE_GATT_CHR_F_WRITE_NO_RSP 0x0004
#define BLE_GATT_CHR_F_WRITE 0x0008
#define BLE_GATT_CHR_F_NOTIFY 0x0010
#define BLE_GATT_CHR_F_INDICATE 0x0020
#define BLE_GATT_CHR_F_AUTH_SIGN_WRITE 0x0040
#define BLE_GATT_CHR_F_RELIABLE_WRITE 0x0080
#define BLE_GATT_CHR_F_AUX_WRITE 0x0100
#define BLE_GATT_CHR_F_READ_ENC 0x0200
#define BLE_GATT_CHR_F_READ_AUTHEN 0x0400
#define BLE_GATT_CHR_F_READ_AUTHOR 0x0800
#define BLE_GATT_CHR_F_WRITE_ENC 0x1000
#define BLE_GATT_CHR_F_WRITE_AUTHEN 0x2000
#define BLE_GATT_CHR_F_WRITE_AUTHOR 0x4000
#define BLE_GATT_SVC_TYPE_END 0
#define BLE_GATT_SVC_TYPE_PRIMARY 1
#define BLE_GATT_SVC_TYPE_SECONDARY 2
/*** @client. */
struct ble_gatt_error {
uint16_t status;
uint16_t att_handle;
};
struct ble_gatt_svc {
uint16_t start_handle;
uint16_t end_handle;
ble_uuid_any_t uuid;
};
struct ble_gatt_attr {
uint16_t handle;
uint16_t offset;
struct os_mbuf *om;
};
struct ble_gatt_chr {
uint16_t def_handle;
uint16_t val_handle;
uint8_t properties;
ble_uuid_any_t uuid;
};
struct ble_gatt_dsc {
uint16_t handle;
ble_uuid_any_t uuid;
};
typedef int ble_gatt_mtu_fn(uint16_t conn_handle,
const struct ble_gatt_error *error,
uint16_t mtu, void *arg);
typedef int ble_gatt_disc_svc_fn(uint16_t conn_handle,
const struct ble_gatt_error *error,
const struct ble_gatt_svc *service,
void *arg);
/**
* The host will free the attribute mbuf automatically after the callback is
* executed. The application can take ownership of the mbuf and prevent it
* from being freed by assigning NULL to attr->om.
*/
typedef int ble_gatt_attr_fn(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg);
/**
* The host will free the attribute mbufs automatically after the callback is
* executed. The application can take ownership of the mbufs and prevent them
* from being freed by assigning NULL to each attribute's om field.
*/
typedef int ble_gatt_reliable_attr_fn(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attrs,
uint8_t num_attrs, void *arg);
typedef int ble_gatt_chr_fn(uint16_t conn_handle,
const struct ble_gatt_error *error,
const struct ble_gatt_chr *chr, void *arg);
typedef int ble_gatt_dsc_fn(uint16_t conn_handle,
const struct ble_gatt_error *error,
uint16_t chr_val_handle,
const struct ble_gatt_dsc *dsc,
void *arg);
/**
* Initiates GATT procedure: Exchange MTU.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_exchange_mtu(uint16_t conn_handle,
ble_gatt_mtu_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Discover All Primary Services.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*/
int ble_gattc_disc_all_svcs(uint16_t conn_handle,
ble_gatt_disc_svc_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Discover Primary Service by Service UUID.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param service_uuid128 The 128-bit UUID of the service to discover.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_disc_svc_by_uuid(uint16_t conn_handle, const ble_uuid_t *uuid,
ble_gatt_disc_svc_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Find Included Services.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param start_handle The handle to begin the search at (generally
* the service definition handle).
* @param end_handle The handle to end the search at (generally the
* last handle in the service).
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_find_inc_svcs(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle,
ble_gatt_disc_svc_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Discover All Characteristics of a Service.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param start_handle The handle to begin the search at (generally
* the service definition handle).
* @param end_handle The handle to end the search at (generally the
* last handle in the service).
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle, ble_gatt_chr_fn *cb,
void *cb_arg);
/**
* Initiates GATT procedure: Discover Characteristics by UUID.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param start_handle The handle to begin the search at (generally
* the service definition handle).
* @param end_handle The handle to end the search at (generally the
* last handle in the service).
* @param chr_uuid128 The 128-bit UUID of the characteristic to
* discover.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle, const ble_uuid_t *uuid,
ble_gatt_chr_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Discover All Characteristic Descriptors.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param chr_val_handle The handle of the characteristic value
* attribute.
* @param chr_end_handle The last handle in the characteristic
* definition.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle,
ble_gatt_dsc_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Read Characteristic Value.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to read.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_read(uint16_t conn_handle, uint16_t attr_handle,
ble_gatt_attr_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Read Using Characteristic UUID.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param start_handle The first handle to search (generally the
* handle of the service definition).
* @param end_handle The last handle to search (generally the
* last handle in the service definition).
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_read_by_uuid(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle, const ble_uuid_t *uuid,
ble_gatt_attr_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Read Long Characteristic Values.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param handle The handle of the characteristic value to read.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_read_long(uint16_t conn_handle, uint16_t handle, uint16_t offset,
ble_gatt_attr_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Read Multiple Characteristic Values.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param handles An array of 16-bit attribute handles to read.
* @param num_handles The number of entries in the "handles" array.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles,
uint8_t num_handles, ble_gatt_attr_fn *cb,
void *cb_arg);
/**
* Initiates GATT procedure: Write Without Response. This function consumes
* the supplied mbuf regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to write
* to.
* @param txom The value to write to the characteristic.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
struct os_mbuf *om);
/**
* Initiates GATT procedure: Write Without Response. This function consumes
* the supplied mbuf regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to write
* to.
* @param value The value to write to the characteristic.
* @param value_len The number of bytes to write.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_write_no_rsp_flat(uint16_t conn_handle, uint16_t attr_handle,
const void *data, uint16_t data_len);
/**
* Initiates GATT procedure: Write Characteristic Value. This function
* consumes the supplied mbuf regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to write
* to.
* @param txom The value to write to the characteristic.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle,
struct os_mbuf *om,
ble_gatt_attr_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Write Characteristic Value (flat buffer version).
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to write
* to.
* @param value The value to write to the characteristic.
* @param value_len The number of bytes to write.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_write_flat(uint16_t conn_handle, uint16_t attr_handle,
const void *data, uint16_t data_len,
ble_gatt_attr_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Write Long Characteristic Values. This function
* consumes the supplied mbuf regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attr_handle The handle of the characteristic value to write
* to.
* @param txom The value to write to the characteristic.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle,
uint16_t offset, struct os_mbuf *om,
ble_gatt_attr_fn *cb, void *cb_arg);
/**
* Initiates GATT procedure: Reliable Writes. This function consumes the
* supplied mbufs regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param attrs An array of attribute descriptors; specifies
* which characteristics to write to and what
* data to write to them. The mbuf pointer in
* each attribute is set to NULL by this
* function.
* @param num_attrs The number of characteristics to write; equal
* to the number of elements in the 'attrs'
* array.
* @param cb The function to call to report procedure status
* updates; null for no callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*/
int ble_gattc_write_reliable(uint16_t conn_handle,
struct ble_gatt_attr *attrs,
int num_attrs, ble_gatt_reliable_attr_fn *cb,
void *cb_arg);
/**
* Sends a "free-form" characteristic notification. This function consumes the
* supplied mbuf regardless of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param chr_val_handle The attribute handle to indicate in the
* outgoing notification.
* @param txom The value to write to the characteristic.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_notify_custom(uint16_t conn_handle, uint16_t att_handle,
struct os_mbuf *om);
/**
* Sends a characteristic notification. The content of the message is read
* from the specified characteristic.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param chr_val_handle The value attribute handle of the
* characteristic to include in the outgoing
* notification.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle);
/**
* Sends a "free-form" characteristic indication. The provided mbuf contains
* the indication payload. This function consumes the supplied mbuf regardless
* of the outcome.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param chr_val_handle The value attribute handle of the
* characteristic to include in the outgoing
* indication.
* @param txom The data to include in the indication.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle,
struct os_mbuf *txom);
/**
* Sends a characteristic indication. The content of the message is read from
* the specified characteristic.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param chr_val_handle The value attribute handle of the
* characteristic to include in the outgoing
* indication.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle);
int ble_gattc_init(void);
/*** @server. */
struct ble_gatt_access_ctxt;
typedef int ble_gatt_access_fn(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
typedef uint16_t ble_gatt_chr_flags;
struct ble_gatt_chr_def {
/**
* Pointer to characteristic UUID; use BLE_UUIDxx_DECLARE macros to declare
* proper UUID; NULL if there are no more characteristics in the service.
*/
const ble_uuid_t *uuid;
/**
* Callback that gets executed when this characteristic is read or
* written.
*/
ble_gatt_access_fn *access_cb;
/** Optional argument for callback. */
void *arg;
/**
* Array of this characteristic's descriptors. NULL if no descriptors.
* Do not include CCCD; it gets added automatically if this
* characteristic's notify or indicate flag is set.
*/
struct ble_gatt_dsc_def *descriptors;
/** Specifies the set of permitted operations for this characteristic. */
ble_gatt_chr_flags flags;
/** Specifies minimum required key size to access this characteristic. */
uint8_t min_key_size;
/**
* At registration time, this is filled in with the characteristic's value
* attribute handle.
*/
uint16_t *val_handle;
};
struct ble_gatt_svc_def {
/**
* One of the following:
* o BLE_GATT_SVC_TYPE_PRIMARY - primary service
* o BLE_GATT_SVC_TYPE_SECONDARY - secondary service
* o 0 - No more services in this array.
*/
uint8_t type;
/**
* Pointer to service UUID; use BLE_UUIDxx_DECLARE macros to declare
* proper UUID; NULL if there are no more characteristics in the service.
*/
const ble_uuid_t *uuid;
/**
* Array of pointers to other service definitions. These services are
* reported as "included services" during service discovery. Terminate the
* array with NULL.
*/
const struct ble_gatt_svc_def **includes;
/**
* Array of characteristic definitions corresponding to characteristics
* belonging to this service.
*/
const struct ble_gatt_chr_def *characteristics;
};
struct ble_gatt_dsc_def {
/**
* Pointer to descriptor UUID; use BLE_UUIDxx_DECLARE macros to declare
* proper UUID; NULL if there are no more characteristics in the service.
*/
const ble_uuid_t *uuid;
/** Specifies the set of permitted operations for this descriptor. */
uint8_t att_flags;
/** Specifies minimum required key size to access this descriptor. */
uint8_t min_key_size;
/** Callback that gets executed when the descriptor is read or written. */
ble_gatt_access_fn *access_cb;
/** Optional argument for callback. */
void *arg;
};
/**
* Context for an access to a GATT characteristic or descriptor. When a client
* reads or writes a locally registered characteristic or descriptor, an
* instance of this struct gets passed to the application callback.
*/
struct ble_gatt_access_ctxt {
/**
* Indicates the gatt operation being performed. This is equal to one of
* the following values:
* o BLE_GATT_ACCESS_OP_READ_CHR
* o BLE_GATT_ACCESS_OP_WRITE_CHR
* o BLE_GATT_ACCESS_OP_READ_DSC
* o BLE_GATT_ACCESS_OP_WRITE_DSC
*/
uint8_t op;
/**
* A container for the GATT access data.
* o For reads: The application populates this with the value of the
* characteristic or descriptor being read.
* o For writes: This is already populated with the value being written
* by the peer. If the application wishes to retain this mbuf for
* later use, the access callback must set this pointer to NULL to
* prevent the stack from freeing it.
*/
struct os_mbuf *om;
/**
* The GATT operation being performed dictates which field in this union is
* valid. If a characteristic is being accessed, the chr field is valid.
* Otherwise a descriptor is being accessed, in which case the dsc field
* is valid.
*/
union {
/**
* The characteristic definition corresponding to the characteristic
* being accessed. This is what the app registered at startup.
*/
const struct ble_gatt_chr_def *chr;
/**
* The descriptor definition corresponding to the descriptor being
* accessed. This is what the app registered at startup.
*/
const struct ble_gatt_dsc_def *dsc;
};
};
/**
* Context passed to the registration callback; represents the GATT service,
* characteristic, or descriptor being registered.
*/
struct ble_gatt_register_ctxt {
/**
* Indicates the gatt registration operation just performed. This is
* equal to one of the following values:
* o BLE_GATT_REGISTER_OP_SVC
* o BLE_GATT_REGISTER_OP_CHR
* o BLE_GATT_REGISTER_OP_DSC
*/
uint8_t op;
/**
* The value of the op field determines which field in this union is valid.
*/
union {
/** Service; valid if op == BLE_GATT_REGISTER_OP_SVC. */
struct {
/** The ATT handle of the service definition attribute. */
uint16_t handle;
/**
* The service definition representing the service being
* registered.
*/
const struct ble_gatt_svc_def *svc_def;
} svc;
/** Characteristic; valid if op == BLE_GATT_REGISTER_OP_CHR. */
struct {
/** The ATT handle of the characteristic definition attribute. */
uint16_t def_handle;
/** The ATT handle of the characteristic value attribute. */
uint16_t val_handle;
/**
* The characteristic definition representing the characteristic
* being registered.
*/
const struct ble_gatt_chr_def *chr_def;
/**
* The service definition corresponding to the characteristic's
* parent service.
*/
const struct ble_gatt_svc_def *svc_def;
} chr;
/** Descriptor; valid if op == BLE_GATT_REGISTER_OP_DSC. */
struct {
/** The ATT handle of the descriptor definition attribute. */
uint16_t handle;
/**
* The descriptor definition corresponding to the descriptor being
* registered.
*/
const struct ble_gatt_dsc_def *dsc_def;
/**
* The characteristic definition corresponding to the descriptor's
* parent characteristic.
*/
const struct ble_gatt_chr_def *chr_def;
/**
* The service definition corresponding to the descriptor's
* grandparent service
*/
const struct ble_gatt_svc_def *svc_def;
} dsc;
};
};
typedef void ble_gatt_register_fn(struct ble_gatt_register_ctxt *ctxt,
void *arg);
/**
* Queues a set of service definitions for registration. All services queued
* in this manner get registered when ble_gatts_start() is called.
*
* @param svcs An array of service definitions to queue for
* registration. This array must be
* terminated with an entry whose 'type'
* equals 0.
*
* @return 0 on success;
* BLE_HS_ENOMEM on heap exhaustion.
*/
int ble_gatts_add_svcs(const struct ble_gatt_svc_def *svcs);
/**
* Set visibility of local GATT service. Invisible services are not removed
* from database but are not discoverable by peer devices. Service Changed
* should be handled by application when needed by calling
* ble_svc_gatt_changed().
*
* @param handle Handle of service
* @param visible non-zero if service should be visible
*
* @return 0 on success;
* BLE_HS_ENOENT if service wasn't found.
*/
int ble_gatts_svc_set_visibility(uint16_t handle, int visible);
/**
* Adjusts a host configuration object's settings to accommodate the specified
* service definition array. This function adds the counts to the appropriate
* fields in the supplied configuration object without clearing them first, so
* it can be called repeatedly with different inputs to calculate totals. Be
* sure to zero the GATT server settings prior to the first call to this
* function.
*
* @param defs The service array containing the resource
* definitions to be counted.
*
* @return 0 on success;
* BLE_HS_EINVAL if the svcs array contains an
* invalid resource definition.
*/
int ble_gatts_count_cfg(const struct ble_gatt_svc_def *defs);
/**
* Send notification (or indication) to any connected devices that have
* subscribed for notification (or indication) for specified characteristic.
*
* @param chr_val_handle Characteristic value handle
*/
void ble_gatts_chr_updated(uint16_t chr_val_handle);
/**
* Retrieves the attribute handle associated with a local GATT service.
*
* @param uuid The UUID of the service to look up.
* @param out_handle On success, populated with the handle of the
* service attribute. Pass null if you don't
* need this value.
*
* @return 0 on success;
* BLE_HS_ENOENT if the specified service could
* not be found.
*/
int ble_gatts_find_svc(const ble_uuid_t *uuid, uint16_t *out_handle);
/**
* Retrieves the pair of attribute handles associated with a local GATT
* characteristic.
*
* @param svc_uuid The UUID of the parent service.
* @param chr_uuid The UUID of the characteristic to look up.
* @param out_def_handle On success, populated with the handle
* of the characteristic definition attribute.
* Pass null if you don't need this value.
* @param out_val_handle On success, populated with the handle
* of the characteristic value attribute.
* Pass null if you don't need this value.
*
* @return 0 on success;
* BLE_HS_ENOENT if the specified service or
* characteristic could not be found.
*/
int ble_gatts_find_chr(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid,
uint16_t *out_def_handle, uint16_t *out_val_handle);
/**
* Retrieves the attribute handle associated with a local GATT descriptor.
*
* @param svc_uuid The UUID of the grandparent service.
* @param chr_uuid The UUID of the parent characteristic.
* @param dsc_uuid The UUID of the descriptor ro look up.
* @param out_handle On success, populated with the handle
* of the descriptor attribute. Pass null if
* you don't need this value.
*
* @return 0 on success;
* BLE_HS_ENOENT if the specified service,
* characteristic, or descriptor could not be
* found.
*/
int ble_gatts_find_dsc(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid,
const ble_uuid_t *dsc_uuid, uint16_t *out_dsc_handle);
typedef void (*ble_gatt_svc_foreach_fn)(const struct ble_gatt_svc_def *svc,
uint16_t handle,
uint16_t end_group_handle,
void *arg);
/**
* Prints dump of local GATT database. This is useful to log local state of
* database in human readable form.
*/
void ble_gatts_show_local(void);
/**
* Resets the GATT server to its initial state. On success, this function
* removes all supported services, characteristics, and descriptors. This
* function requires that:
* o No peers are connected, and
* o No GAP operations are active (advertise, discover, or connect).
*
* @return 0 on success;
* BLE_HS_EBUSY if the GATT server could not be
* reset due to existing connections or active
* GAP procedures.
*/
int ble_gatts_reset(void);
/**
* Makes all registered services available to peers. This function gets called
* automatically by the NimBLE host on startup; manual calls are only necessary
* for replacing the set of supported services with a new one. This function
* requires that:
* o No peers are connected, and
* o No GAP operations are active (advertise, discover, or connect).
*
* @return 0 on success;
* A BLE host core return code on unexpected
* error.
*/
int ble_gatts_start(void);
/**
* Resets the GATT configuration parameters and deallocates the memory of attributes.
*
*/
void ble_gatts_stop(void);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif

View File

@@ -0,0 +1,392 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_HS_
#define H_BLE_HS_
/**
* @brief Bluetooth Host
* @defgroup bt_host Bluetooth Host
* @{
*/
#include <inttypes.h>
#include "nimble/nimble/include/nimble/hci_common.h"
#include "ble_att.h"
#include "ble_eddystone.h"
#include "ble_gap.h"
#include "ble_gatt.h"
#include "ble_hs_adv.h"
#include "ble_hs_id.h"
#include "ble_hs_hci.h"
#include "ble_hs_log.h"
#include "ble_hs_mbuf.h"
#include "ble_hs_stop.h"
#include "ble_ibeacon.h"
#include "ble_l2cap.h"
#include "ble_sm.h"
#include "ble_store.h"
#include "ble_uuid.h"
#include "nimble/nimble/include/nimble/nimble_npl.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BLE_HS_FOREVER INT32_MAX
/** Connection handle not present */
#define BLE_HS_CONN_HANDLE_NONE 0xffff
/**
* @brief Bluetooth Host Error Code
* @defgroup bt_host_err Bluetooth Host Error Code
*
* Defines error codes returned by Bluetooth host. If error comes from specific
* component (eg L2CAP or Security Manager) it is shifted by base allowing to
* identify component.
* @{
*/
#define BLE_HS_EAGAIN 1
#define BLE_HS_EALREADY 2
#define BLE_HS_EINVAL 3
#define BLE_HS_EMSGSIZE 4
#define BLE_HS_ENOENT 5
#define BLE_HS_ENOMEM 6
#define BLE_HS_ENOTCONN 7
#define BLE_HS_ENOTSUP 8
#define BLE_HS_EAPP 9
#define BLE_HS_EBADDATA 10
#define BLE_HS_EOS 11
#define BLE_HS_ECONTROLLER 12
#define BLE_HS_ETIMEOUT 13
#define BLE_HS_EDONE 14
#define BLE_HS_EBUSY 15
#define BLE_HS_EREJECT 16
#define BLE_HS_EUNKNOWN 17
#define BLE_HS_EROLE 18
#define BLE_HS_ETIMEOUT_HCI 19
#define BLE_HS_ENOMEM_EVT 20
#define BLE_HS_ENOADDR 21
#define BLE_HS_ENOTSYNCED 22
#define BLE_HS_EAUTHEN 23
#define BLE_HS_EAUTHOR 24
#define BLE_HS_EENCRYPT 25
#define BLE_HS_EENCRYPT_KEY_SZ 26
#define BLE_HS_ESTORE_CAP 27
#define BLE_HS_ESTORE_FAIL 28
#define BLE_HS_EPREEMPTED 29
#define BLE_HS_EDISABLED 30
#define BLE_HS_ESTALLED 31
/** Error base for ATT errors */
#define BLE_HS_ERR_ATT_BASE 0x100
/** Converts error to ATT base */
#define BLE_HS_ATT_ERR(x) ((x) ? BLE_HS_ERR_ATT_BASE + (x) : 0)
/** Error base for HCI errors */
#define BLE_HS_ERR_HCI_BASE 0x200
/** Converts error to HCI base */
#define BLE_HS_HCI_ERR(x) ((x) ? BLE_HS_ERR_HCI_BASE + (x) : 0)
/** Error base for L2CAP errors */
#define BLE_HS_ERR_L2C_BASE 0x300
/** Converts error to L2CAP base */
#define BLE_HS_L2C_ERR(x) ((x) ? BLE_HS_ERR_L2C_BASE + (x) : 0)
/** Error base for local Security Manager errors */
#define BLE_HS_ERR_SM_US_BASE 0x400
/** Converts error to local Security Manager base */
#define BLE_HS_SM_US_ERR(x) ((x) ? BLE_HS_ERR_SM_US_BASE + (x) : 0)
/** Error base for remote (peer) Security Manager errors */
#define BLE_HS_ERR_SM_PEER_BASE 0x500
/** Converts error to remote (peer) Security Manager base */
#define BLE_HS_SM_PEER_ERR(x) ((x) ? BLE_HS_ERR_SM_PEER_BASE + (x) : 0)
/** Error base for hardware errors */
#define BLE_HS_ERR_HW_BASE 0x600
/** Converts error to hardware error base */
#define BLE_HS_HW_ERR(x) (BLE_HS_ERR_HW_BASE + (x))
/**
* @}
*/
/**
* @brief Bluetooth Host Configuration
* @defgroup bt_host_conf Bluetooth Host Configuration
*
* @{
*/
/**
* @brief Local Input-Output capabilities of device
* @defgroup bt_host_io_local Local Input-Output capabilities of device
*
* @{
*/
/** DisplayOnly IO capability */
#define BLE_HS_IO_DISPLAY_ONLY 0x00
/** DisplayYesNo IO capability */
#define BLE_HS_IO_DISPLAY_YESNO 0x01
/** KeyboardOnly IO capability */
#define BLE_HS_IO_KEYBOARD_ONLY 0x02
/** NoInputNoOutput IO capability */
#define BLE_HS_IO_NO_INPUT_OUTPUT 0x03
/** KeyboardDisplay Only IO capability */
#define BLE_HS_IO_KEYBOARD_DISPLAY 0x04
/**
* @}
*/
/** @brief Stack reset callback
*
* @param reason Reason code for reset
*/
typedef void ble_hs_reset_fn(int reason);
/** @brief Stack sync callback */
typedef void ble_hs_sync_fn(void);
/** @brief Bluetooth Host main configuration structure
*
* Those can be used by application to configure stack.
*
* The only reason Security Manager (sm_ members) is configurable at runtime is
* to simplify security testing. Defaults for those are configured by selecting
* proper options in application's syscfg.
*/
struct ble_hs_cfg {
/**
* An optional callback that gets executed upon registration of each GATT
* resource (service, characteristic, or descriptor).
*/
ble_gatt_register_fn *gatts_register_cb;
/**
* An optional argument that gets passed to the GATT registration
* callback.
*/
void *gatts_register_arg;
/** Security Manager Local Input Output Capabilities */
uint8_t sm_io_cap;
/** @brief Security Manager OOB flag
*
* If set proper flag in Pairing Request/Response will be set.
*/
unsigned sm_oob_data_flag:1;
/** @brief Security Manager Bond flag
*
* If set proper flag in Pairing Request/Response will be set. This results
* in storing keys distributed during bonding.
*/
unsigned sm_bonding:1;
/** @brief Security Manager MITM flag
*
* If set proper flag in Pairing Request/Response will be set. This results
* in requiring Man-In-The-Middle protection when pairing.
*/
unsigned sm_mitm:1;
/** @brief Security Manager Secure Connections flag
*
* If set proper flag in Pairing Request/Response will be set. This results
* in using LE Secure Connections for pairing if also supported by remote
* device. Fallback to legacy pairing if not supported by remote.
*/
unsigned sm_sc:1;
/** @brief Security Manager Key Press Notification flag
*
* Currently unsupported and should not be set.
*/
unsigned sm_keypress:1;
/** @brief Security Manager Local Key Distribution Mask */
uint8_t sm_our_key_dist;
/** @brief Security Manager Remote Key Distribution Mask */
uint8_t sm_their_key_dist;
/** @brief Stack reset callback
*
* This callback is executed when the host resets itself and the controller
* due to fatal error.
*/
ble_hs_reset_fn *reset_cb;
/** @brief Stack sync callback
*
* This callback is executed when the host and controller become synced.
* This happens at startup and after a reset.
*/
ble_hs_sync_fn *sync_cb;
/* XXX: These need to go away. Instead, the nimble host package should
* require the host-store API (not yet implemented)..
*/
/** Storage Read callback handles read of security material */
ble_store_read_fn *store_read_cb;
/** Storage Write callback handles write of security material */
ble_store_write_fn *store_write_cb;
/** Storage Delete callback handles deletion of security material */
ble_store_delete_fn *store_delete_cb;
/** @brief Storage Status callback.
*
* This callback gets executed when a persistence operation cannot be
* performed or a persistence failure is imminent. For example, if is
* insufficient storage capacity for a record to be persisted, this
* function gets called to give the application the opportunity to make
* room.
*/
ble_store_status_fn *store_status_cb;
/** An optional argument that gets passed to the storage status callback. */
void *store_status_arg;
};
extern struct ble_hs_cfg ble_hs_cfg;
/**
* @}
*/
/**
* @brief Indicates whether the host is enabled. The host is enabled if it is
* starting or fully started. It is disabled if it is stopping or stopped.
*
* @return 1 if the host is enabled;
* 0 if the host is disabled.
*/
int ble_hs_is_enabled(void);
/**
* Indicates whether the host has synchronized with the controller.
* Synchronization must occur before any host procedures can be performed.
*
* @return 1 if the host and controller are in sync;
* 0 if the host and controller are out of sync.
*/
int ble_hs_synced(void);
/**
* Synchronizes the host with the controller by sending a sequence of HCI
* commands. This function must be called before any other host functionality
* is used, but it must be called after both the host and controller are
* initialized. Typically, the host-parent-task calls this function at the top
* of its task routine. This function must only be called in the host parent
* task. A safe alternative for starting the stack from any task is to call
* `ble_hs_sched_start()`.
*
* If the host fails to synchronize with the controller (if the controller is
* not fully booted, for example), the host will attempt to resynchronize every
* 100 ms. For this reason, an error return code is not necessarily fatal.
*
* @return 0 on success; nonzero on error.
*/
int ble_hs_start(void);
/**
* Enqueues a host start event to the default event queue. The actual host
* startup is performed in the host parent task, but using the default queue
* here ensures the event won't run until the end of main() when this is
* called during system initialization. This allows the application to
* configure the host package in the meantime.
*
* If auto-start is disabled, the application should use this function to start
* the BLE stack. This function can be called at any time as long as the host
* is stopped. When the host successfully starts, the application is notified
* via the ble_hs_cfg.sync_cb callback.
*/
void ble_hs_sched_start(void);
/**
* Causes the host to reset the NimBLE stack as soon as possible. The
* application is notified when the reset occurs via the host reset callback.
*
* @param reason The host error code that gets passed to the reset callback.
*/
void ble_hs_sched_reset(int reason);
/**
* Designates the specified event queue for NimBLE host work. By default, the
* host uses the default event queue and runs in the main task. This function
* is useful if you want the host to run in a different task.
*
* @param evq The event queue to use for host work.
*/
void ble_hs_evq_set(struct ble_npl_eventq *evq);
/**
* Initializes the NimBLE host. This function must be called before the OS is
* started. The NimBLE stack requires an application task to function. One
* application task in particular is designated as the "host parent task". In
* addition to application-specific work, the host parent task does work for
* NimBLE by processing events generated by the host.
*/
void ble_hs_init(void);
/**
* Deinitializes the NimBLE host. This function must be called after the
* NimBLE host stop procedure is complete.
*/
void ble_hs_deinit(void);
/**
* @brief Called when the system is shutting down. Stops the BLE host.
*
* @param reason The reason for the shutdown. One of the
* HAL_RESET_[...] codes or an
* implementation-defined value.
*
* @return SYSDOWN_IN_PROGRESS.
*/
int ble_hs_shutdown(int reason);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif

View File

@@ -0,0 +1,177 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_HS_ADV_
#define H_BLE_HS_ADV_
#include <inttypes.h>
#include "ble_uuid.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BLE_HS_ADV_MAX_SZ BLE_HCI_MAX_ADV_DATA_LEN
/** Max field payload size (account for 2-byte header). */
#define BLE_HS_ADV_MAX_FIELD_SZ (BLE_HS_ADV_MAX_SZ - 2)
struct ble_hs_adv_field {
uint8_t length;
uint8_t type;
uint8_t value[0];
};
typedef int (* ble_hs_adv_parse_func_t) (const struct ble_hs_adv_field *,
void *);
struct ble_hs_adv_fields {
/*** 0x01 - Flags. */
uint8_t flags;
/*** 0x02,0x03 - 16-bit service class UUIDs. */
const ble_uuid16_t *uuids16;
uint8_t num_uuids16;
unsigned uuids16_is_complete:1;
/*** 0x04,0x05 - 32-bit service class UUIDs. */
const ble_uuid32_t *uuids32;
uint8_t num_uuids32;
unsigned uuids32_is_complete:1;
/*** 0x06,0x07 - 128-bit service class UUIDs. */
const ble_uuid128_t *uuids128;
uint8_t num_uuids128;
unsigned uuids128_is_complete:1;
/*** 0x08,0x09 - Local name. */
const uint8_t *name;
uint8_t name_len;
unsigned name_is_complete:1;
/*** 0x0a - Tx power level. */
int8_t tx_pwr_lvl;
unsigned tx_pwr_lvl_is_present:1;
/*** 0x0d - Slave connection interval range. */
const uint8_t *slave_itvl_range;
/*** 0x16 - Service data - 16-bit UUID. */
const uint8_t *svc_data_uuid16;
uint8_t svc_data_uuid16_len;
/*** 0x17 - Public target address. */
const uint8_t *public_tgt_addr;
uint8_t num_public_tgt_addrs;
/*** 0x19 - Appearance. */
uint16_t appearance;
unsigned appearance_is_present:1;
/*** 0x1a - Advertising interval. */
uint16_t adv_itvl;
unsigned adv_itvl_is_present:1;
/*** 0x20 - Service data - 32-bit UUID. */
const uint8_t *svc_data_uuid32;
uint8_t svc_data_uuid32_len;
/*** 0x21 - Service data - 128-bit UUID. */
const uint8_t *svc_data_uuid128;
uint8_t svc_data_uuid128_len;
/*** 0x24 - URI. */
const uint8_t *uri;
uint8_t uri_len;
/*** 0xff - Manufacturer specific data. */
const uint8_t *mfg_data;
uint8_t mfg_data_len;
};
#define BLE_HS_ADV_TYPE_FLAGS 0x01
#define BLE_HS_ADV_TYPE_INCOMP_UUIDS16 0x02
#define BLE_HS_ADV_TYPE_COMP_UUIDS16 0x03
#define BLE_HS_ADV_TYPE_INCOMP_UUIDS32 0x04
#define BLE_HS_ADV_TYPE_COMP_UUIDS32 0x05
#define BLE_HS_ADV_TYPE_INCOMP_UUIDS128 0x06
#define BLE_HS_ADV_TYPE_COMP_UUIDS128 0x07
#define BLE_HS_ADV_TYPE_INCOMP_NAME 0x08
#define BLE_HS_ADV_TYPE_COMP_NAME 0x09
#define BLE_HS_ADV_TYPE_TX_PWR_LVL 0x0a
#define BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE 0x12
#define BLE_HS_ADV_TYPE_SOL_UUIDS16 0x14
#define BLE_HS_ADV_TYPE_SOL_UUIDS128 0x15
#define BLE_HS_ADV_TYPE_SVC_DATA_UUID16 0x16
#define BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR 0x17
#define BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR 0x18
#define BLE_HS_ADV_TYPE_APPEARANCE 0x19
#define BLE_HS_ADV_TYPE_ADV_ITVL 0x1a
#define BLE_HS_ADV_TYPE_SVC_DATA_UUID32 0x20
#define BLE_HS_ADV_TYPE_SVC_DATA_UUID128 0x21
#define BLE_HS_ADV_TYPE_URI 0x24
#define BLE_HS_ADV_TYPE_MESH_PROV 0x29
#define BLE_HS_ADV_TYPE_MESH_MESSAGE 0x2a
#define BLE_HS_ADV_TYPE_MESH_BEACON 0x2b
#define BLE_HS_ADV_TYPE_MFG_DATA 0xff
#define BLE_HS_ADV_FLAGS_LEN 1
#define BLE_HS_ADV_F_DISC_LTD 0x01
#define BLE_HS_ADV_F_DISC_GEN 0x02
#define BLE_HS_ADV_F_BREDR_UNSUP 0x04
#define BLE_HS_ADV_TX_PWR_LVL_LEN 1
/**
* Set the tx_pwr_lvl field to this if you want the stack to fill in the tx
* power level field.
*/
#define BLE_HS_ADV_TX_PWR_LVL_AUTO (-128)
#define BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN 4
#define BLE_HS_ADV_SVC_DATA_UUID16_MIN_LEN 2
#define BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN 6
#define BLE_HS_ADV_APPEARANCE_LEN 2
#define BLE_HS_ADV_ADV_ITVL_LEN 2
#define BLE_HS_ADV_SVC_DATA_UUID32_MIN_LEN 4
#define BLE_HS_ADV_SVC_DATA_UUID128_MIN_LEN 16
int ble_hs_adv_set_fields_mbuf(const struct ble_hs_adv_fields *adv_fields,
struct os_mbuf *om);
int ble_hs_adv_set_fields(const struct ble_hs_adv_fields *adv_fields,
uint8_t *dst, uint8_t *dst_len, uint8_t max_len);
int ble_hs_adv_parse_fields(struct ble_hs_adv_fields *adv_fields,
const uint8_t *src, uint8_t src_len);
int ble_hs_adv_parse(const uint8_t *data, uint8_t length,
ble_hs_adv_parse_func_t func, void *user_data);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,98 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_HS_HCI_
#define H_BLE_HS_HCI_
/**
* @brief Bluetooth Host HCI utils
* @defgroup bt_host_hci Bluetooth Host HCI utils
* @ingroup bt_host
* @{
*/
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Queries the controller for the channel map used with the specified
* connection. The channel map is represented as an array of five bytes, with
* each bit corresponding to an individual channel. The array is interpreted
* as little-endian, such that:
* map[0] & 0x01 --> Channel 0.
* map[0] & 0x02 --> Channel 1.
* ...
* map[1] & 0x01 --> Channel 8.
*
* As there are 37 channels, only the first 37 bits get written.
*
* If a bit is 1, the corresponding channel is used. Otherwise, the channel is
* unused.
*
* @param conn_handle The handle of the connection whose channel map
* is being read.
* @param out_chan_map On success, the retrieved channel map gets
* written here. This buffer must have a size
* >= 5 bytes.
*
* @return 0 on success;
* A BLE host HCI return code if the controller
* rejected the request;
* A BLE host core return code on unexpected
* error.
*/
int ble_hs_hci_read_chan_map(uint16_t conn_handle, uint8_t *out_chan_map);
/**
* Instructs the controller to use the specified channel map. The channel map
* is represented as an array of five bytes, with each bit corresponding to an
* individual channel. The array is interpreted as little-endian, such that:
* map[0] & 0x01 --> Channel 0.
* map[0] & 0x02 --> Channel 1.
* ...
* map[1] & 0x01 --> Channel 8.
*
* As there are 37 channels, only the first 37 bits should be written are used.
*
* If a bit is 1, the corresponding channel can be used. Otherwise, the
* channel should not be used.
*
* @param chan_map The channel map to configure. This buffer
* should have a size of 5 bytes.
*
* @return 0 on success;
* A BLE host HCI return code if the controller
* rejected the request;
* A BLE host core return code on unexpected
* error.
*/
int ble_hs_hci_set_chan_class(const uint8_t *chan_map);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif

View File

@@ -0,0 +1,132 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_HS_ID_
#define H_BLE_HS_ID_
/**
* @brief Bluetooth Host Identity
* @defgroup bt_host_id Bluetooth Host Identity
* @ingroup bt_host
* @{
*/
#include <inttypes.h>
#include "nimble/nimble/include/nimble/ble.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Generates a new random address. This function does not configure the device
* with the new address; the caller can use the address in subsequent
* operations.
*
* @param nrpa The type of random address to generate:
* 0: static
* 1: non-resolvable private
* @param out_addr On success, the generated address gets written
* here.
*
* @return 0 on success; nonzero on failure.
*/
int ble_hs_id_gen_rnd(int nrpa, ble_addr_t *out_addr);
/**
* Sets the device's random address. The address type (static vs.
* non-resolvable private) is inferred from the most-significant byte of the
* address. The address is specified in host byte order (little-endian!).
*
* @param rnd_addr The random address to set.
*
* @return 0 on success;
* BLE_HS_EINVAL if the specified address is not a
* valid static random or non-resolvable
* private address.
* Other nonzero on error.
*/
int ble_hs_id_set_rnd(const uint8_t *rnd_addr);
/**
* Retrieves one of the device's identity addresses. The device can have two
* identity addresses: one public and one random. The id_addr_type argument
* specifies which of these two addresses to retrieve.
*
* @param id_addr_type The type of identity address to retrieve.
* Valid values are:
* o BLE_ADDR_PUBLIC
* o BLE_ADDR_RANDOM
* @param out_id_addr On success, the requested identity address is
* copied into this buffer. The buffer must
* be at least six bytes in size. Pass NULL
* if you do not require this information.
* @param out_is_nrpa On success, the pointed-to value indicates
* whether the retrieved address is a
* non-resolvable private address. Pass NULL
* if you do not require this information.
*
* @return 0 on success;
* BLE_HS_EINVAL if an invalid address type was
* specified;
* BLE_HS_ENOADDR if the device does not have an
* identity address of the requested type;
* Other BLE host core code on error.
*/
int ble_hs_id_copy_addr(uint8_t id_addr_type, uint8_t *out_id_addr,
int *out_is_nrpa);
/**
* Determines the best address type to use for automatic address type
* resolution. Calculation of the best address type is done as follows:
*
* if privacy requested:
* if we have a random static address:
* --> RPA with static random ID
* else
* --> RPA with public ID
* end
* else
* if we have a random static address:
* --> random static address
* else
* --> public address
* end
* end
*
* @param privacy (0/1) Whether to use a private address.
* @param out_addr_type On success, the "own addr type" code gets
* written here.
*
* @return 0 if an address type was successfully inferred.
* BLE_HS_ENOADDR if the device does not have a
* suitable address.
* Other BLE host core code on error.
*/
int ble_hs_id_infer_auto(int privacy, uint8_t *out_addr_type);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif

Some files were not shown because too many files have changed in this diff Show More