Merge pull request #1434 from Ralim/BLE
Basic BLE support for Pinecil V2
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
#define portCHAR char
|
||||
#define configSUPPORT_STATIC_ALLOCATION 1
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 0
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
#define CLINT_CTRL_ADDR (0x02000000UL)
|
||||
#define configCLINT_BASE_ADDRESS CLINT_CTRL_ADDR
|
||||
#define configUSE_PREEMPTION 1
|
||||
@@ -14,7 +14,7 @@
|
||||
#define configTICK_RATE_HZ ((TickType_t)1000)
|
||||
#define configMAX_PRIORITIES (7)
|
||||
#define configMINIMAL_STACK_SIZE ((unsigned short)160) /* Only needs to be this high as some demo tasks also use this constant. In production only the idle task would use this. */
|
||||
#define configTOTAL_HEAP_SIZE ((size_t)0)
|
||||
#define configTOTAL_HEAP_SIZE ((size_t)1024 * 8)
|
||||
#define configMAX_TASK_NAME_LEN (24)
|
||||
#define configUSE_TRACE_FACILITY 0
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
@@ -35,7 +35,10 @@
|
||||
#define configUSE_CO_ROUTINES 0
|
||||
|
||||
/* Software timer definitions. */
|
||||
#define configUSE_TIMERS 0
|
||||
#define configUSE_TIMERS 1
|
||||
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
|
||||
#define configTIMER_QUEUE_LENGTH 8
|
||||
#define configTIMER_TASK_STACK_DEPTH (160)
|
||||
|
||||
/* Task priorities. Allow these to be overridden. */
|
||||
#ifndef uartPRIMARY_PRIORITY
|
||||
@@ -63,7 +66,7 @@ void vApplicationSleep(uint32_t xExpectedIdleTime);
|
||||
|
||||
#define INCLUDE_vTaskPrioritySet 0
|
||||
#define INCLUDE_uxTaskPriorityGet 0
|
||||
#define INCLUDE_vTaskDelete 0
|
||||
#define INCLUDE_vTaskDelete 1
|
||||
#define INCLUDE_vTaskSuspend 1
|
||||
#define INCLUDE_xResumeFromISR 1
|
||||
#define INCLUDE_vTaskDelayUntil 1
|
||||
|
||||
550
source/Core/BSP/Pinecilv2/MemMang/heap_5.c
Normal file
550
source/Core/BSP/Pinecilv2/MemMang/heap_5.c
Normal file
@@ -0,0 +1,550 @@
|
||||
/*
|
||||
* FreeRTOS Kernel V10.4.1
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* https://www.FreeRTOS.org
|
||||
* https://github.com/FreeRTOS
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* A sample implementation of pvPortMalloc() that allows the heap to be defined
|
||||
* across multiple non-contigous blocks and combines (coalescences) adjacent
|
||||
* memory blocks as they are freed.
|
||||
*
|
||||
* See heap_1.c, heap_2.c, heap_3.c and heap_4.c for alternative
|
||||
* implementations, and the memory management pages of https://www.FreeRTOS.org
|
||||
* for more information.
|
||||
*
|
||||
* Usage notes:
|
||||
*
|
||||
* vPortDefineHeapRegions() ***must*** be called before pvPortMalloc().
|
||||
* pvPortMalloc() will be called if any task objects (tasks, queues, event
|
||||
* groups, etc.) are created, therefore vPortDefineHeapRegions() ***must*** be
|
||||
* called before any other objects are defined.
|
||||
*
|
||||
* vPortDefineHeapRegions() takes a single parameter. The parameter is an array
|
||||
* of HeapRegion_t structures. HeapRegion_t is defined in portable.h as
|
||||
*
|
||||
* typedef struct HeapRegion
|
||||
* {
|
||||
* uint8_t *pucStartAddress; << Start address of a block of memory that will be part of the heap.
|
||||
* size_t xSizeInBytes; << Size of the block of memory.
|
||||
* } HeapRegion_t;
|
||||
*
|
||||
* The array is terminated using a NULL zero sized region definition, and the
|
||||
* memory regions defined in the array ***must*** appear in address order from
|
||||
* low address to high address. So the following is a valid example of how
|
||||
* to use the function.
|
||||
*
|
||||
* HeapRegion_t xHeapRegions[] =
|
||||
* {
|
||||
* { ( uint8_t * ) 0x80000000UL, 0x10000 }, << Defines a block of 0x10000 bytes starting at address 0x80000000
|
||||
* { ( uint8_t * ) 0x90000000UL, 0xa0000 }, << Defines a block of 0xa0000 bytes starting at address of 0x90000000
|
||||
* { NULL, 0 } << Terminates the array.
|
||||
* };
|
||||
*
|
||||
* vPortDefineHeapRegions( xHeapRegions ); << Pass the array into vPortDefineHeapRegions().
|
||||
*
|
||||
* Note 0x80000000 is the lower address so appears in the array first.
|
||||
*
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
|
||||
* all the API functions to use the MPU wrappers. That should only be done when
|
||||
* task.h is included from an application file. */
|
||||
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
|
||||
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
|
||||
#endif
|
||||
|
||||
/* Block sizes must not get too small. */
|
||||
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) )
|
||||
|
||||
/* Assumes 8bit bytes! */
|
||||
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
|
||||
|
||||
/* Define the linked list structure. This is used to link free blocks in order
|
||||
* of their memory address. */
|
||||
typedef struct A_BLOCK_LINK
|
||||
{
|
||||
struct A_BLOCK_LINK * pxNextFreeBlock; /*<< The next free block in the list. */
|
||||
size_t xBlockSize; /*<< The size of the free block. */
|
||||
} BlockLink_t;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Inserts a block of memory that is being freed into the correct position in
|
||||
* the list of free memory blocks. The block being freed will be merged with
|
||||
* the block in front it and/or the block behind it if the memory blocks are
|
||||
* adjacent to each other.
|
||||
*/
|
||||
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The size of the structure placed at the beginning of each allocated memory
|
||||
* block must by correctly byte aligned. */
|
||||
static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
|
||||
|
||||
/* Create a couple of list links to mark the start and end of the list. */
|
||||
static BlockLink_t xStart, * pxEnd = NULL;
|
||||
|
||||
/* Keeps track of the number of calls to allocate and free memory as well as the
|
||||
* number of free bytes remaining, but says nothing about fragmentation. */
|
||||
static size_t xFreeBytesRemaining = 0U;
|
||||
static size_t xMinimumEverFreeBytesRemaining = 0U;
|
||||
static size_t xNumberOfSuccessfulAllocations = 0;
|
||||
static size_t xNumberOfSuccessfulFrees = 0;
|
||||
|
||||
/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize
|
||||
* member of an BlockLink_t structure is set then the block belongs to the
|
||||
* application. When the bit is free the block is still part of the free heap
|
||||
* space. */
|
||||
static size_t xBlockAllocatedBit = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void * pvPortMalloc( size_t xWantedSize )
|
||||
{
|
||||
BlockLink_t * pxBlock, * pxPreviousBlock, * pxNewBlockLink;
|
||||
void * pvReturn = NULL;
|
||||
|
||||
/* The heap must be initialised before the first call to
|
||||
* prvPortMalloc(). */
|
||||
configASSERT( pxEnd );
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* Check the requested block size is not so large that the top bit is
|
||||
* set. The top bit of the block size member of the BlockLink_t structure
|
||||
* is used to determine who owns the block - the application or the
|
||||
* kernel, so it must be free. */
|
||||
if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
|
||||
{
|
||||
/* The wanted size is increased so it can contain a BlockLink_t
|
||||
* structure in addition to the requested amount of bytes. */
|
||||
if( xWantedSize > 0 )
|
||||
{
|
||||
xWantedSize += xHeapStructSize;
|
||||
|
||||
/* Ensure that blocks are always aligned to the required number
|
||||
* of bytes. */
|
||||
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
|
||||
{
|
||||
/* Byte alignment required. */
|
||||
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
|
||||
{
|
||||
/* Traverse the list from the start (lowest address) block until
|
||||
* one of adequate size is found. */
|
||||
pxPreviousBlock = &xStart;
|
||||
pxBlock = xStart.pxNextFreeBlock;
|
||||
|
||||
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
|
||||
{
|
||||
pxPreviousBlock = pxBlock;
|
||||
pxBlock = pxBlock->pxNextFreeBlock;
|
||||
}
|
||||
|
||||
/* If the end marker was reached then a block of adequate size
|
||||
* was not found. */
|
||||
if( pxBlock != pxEnd )
|
||||
{
|
||||
/* Return the memory space pointed to - jumping over the
|
||||
* BlockLink_t structure at its start. */
|
||||
pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
|
||||
|
||||
/* This block is being returned for use so must be taken out
|
||||
* of the list of free blocks. */
|
||||
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
|
||||
|
||||
/* If the block is larger than required it can be split into
|
||||
* two. */
|
||||
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
|
||||
{
|
||||
/* This block is to be split into two. Create a new
|
||||
* block following the number of bytes requested. The void
|
||||
* cast is used to prevent byte alignment warnings from the
|
||||
* compiler. */
|
||||
pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
|
||||
|
||||
/* Calculate the sizes of two blocks split from the
|
||||
* single block. */
|
||||
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
|
||||
pxBlock->xBlockSize = xWantedSize;
|
||||
|
||||
/* Insert the new block into the list of free blocks. */
|
||||
prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
xFreeBytesRemaining -= pxBlock->xBlockSize;
|
||||
|
||||
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
|
||||
{
|
||||
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
/* The block is being returned - it is allocated and owned
|
||||
* by the application and has no "next" block. */
|
||||
pxBlock->xBlockSize |= xBlockAllocatedBit;
|
||||
pxBlock->pxNextFreeBlock = NULL;
|
||||
xNumberOfSuccessfulAllocations++;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
traceMALLOC( pvReturn, xWantedSize );
|
||||
}
|
||||
( void ) xTaskResumeAll();
|
||||
|
||||
#if ( configUSE_MALLOC_FAILED_HOOK == 1 )
|
||||
{
|
||||
if( pvReturn == NULL )
|
||||
{
|
||||
extern void vApplicationMallocFailedHook( void );
|
||||
vApplicationMallocFailedHook();
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
#endif /* if ( configUSE_MALLOC_FAILED_HOOK == 1 ) */
|
||||
|
||||
return pvReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortFree( void * pv )
|
||||
{
|
||||
uint8_t * puc = ( uint8_t * ) pv;
|
||||
BlockLink_t * pxLink;
|
||||
|
||||
if( pv != NULL )
|
||||
{
|
||||
/* The memory being freed will have an BlockLink_t structure immediately
|
||||
* before it. */
|
||||
puc -= xHeapStructSize;
|
||||
|
||||
/* This casting is to keep the compiler from issuing warnings. */
|
||||
pxLink = ( void * ) puc;
|
||||
|
||||
/* Check the block is actually allocated. */
|
||||
configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
|
||||
configASSERT( pxLink->pxNextFreeBlock == NULL );
|
||||
|
||||
if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
|
||||
{
|
||||
if( pxLink->pxNextFreeBlock == NULL )
|
||||
{
|
||||
/* The block is being returned to the heap - it is no longer
|
||||
* allocated. */
|
||||
pxLink->xBlockSize &= ~xBlockAllocatedBit;
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* Add this block to the list of free blocks. */
|
||||
xFreeBytesRemaining += pxLink->xBlockSize;
|
||||
traceFREE( pv, pxLink->xBlockSize );
|
||||
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
|
||||
xNumberOfSuccessfulFrees++;
|
||||
}
|
||||
( void ) xTaskResumeAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
size_t xPortGetFreeHeapSize( void )
|
||||
{
|
||||
return xFreeBytesRemaining;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
size_t xPortGetMinimumEverFreeHeapSize( void )
|
||||
{
|
||||
return xMinimumEverFreeBytesRemaining;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert )
|
||||
{
|
||||
BlockLink_t * pxIterator;
|
||||
uint8_t * puc;
|
||||
|
||||
/* Iterate through the list until a block is found that has a higher address
|
||||
* than the block being inserted. */
|
||||
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
|
||||
{
|
||||
/* Nothing to do here, just iterate to the right position. */
|
||||
}
|
||||
|
||||
/* Do the block being inserted, and the block it is being inserted after
|
||||
* make a contiguous block of memory? */
|
||||
puc = ( uint8_t * ) pxIterator;
|
||||
|
||||
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
|
||||
{
|
||||
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
|
||||
pxBlockToInsert = pxIterator;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
/* Do the block being inserted, and the block it is being inserted before
|
||||
* make a contiguous block of memory? */
|
||||
puc = ( uint8_t * ) pxBlockToInsert;
|
||||
|
||||
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
|
||||
{
|
||||
if( pxIterator->pxNextFreeBlock != pxEnd )
|
||||
{
|
||||
/* Form one big block from the two blocks. */
|
||||
pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
|
||||
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
pxBlockToInsert->pxNextFreeBlock = pxEnd;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
|
||||
}
|
||||
|
||||
/* If the block being inserted plugged a gab, so was merged with the block
|
||||
* before and the block after, then it's pxNextFreeBlock pointer will have
|
||||
* already been set, and should not be set here as that would make it point
|
||||
* to itself. */
|
||||
if( pxIterator != pxBlockToInsert )
|
||||
{
|
||||
pxIterator->pxNextFreeBlock = pxBlockToInsert;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions )
|
||||
{
|
||||
BlockLink_t * pxFirstFreeBlockInRegion = NULL, * pxPreviousFreeBlock;
|
||||
size_t xAlignedHeap;
|
||||
size_t xTotalRegionSize, xTotalHeapSize = 0;
|
||||
BaseType_t xDefinedRegions = 0;
|
||||
size_t xAddress;
|
||||
const HeapRegion_t * pxHeapRegion;
|
||||
|
||||
/* Can only call once! */
|
||||
configASSERT( pxEnd == NULL );
|
||||
|
||||
pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );
|
||||
|
||||
while( pxHeapRegion->xSizeInBytes > 0 )
|
||||
{
|
||||
xTotalRegionSize = pxHeapRegion->xSizeInBytes;
|
||||
|
||||
/* Ensure the heap region starts on a correctly aligned boundary. */
|
||||
xAddress = ( size_t ) pxHeapRegion->pucStartAddress;
|
||||
|
||||
if( ( xAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
|
||||
{
|
||||
xAddress += ( portBYTE_ALIGNMENT - 1 );
|
||||
xAddress &= ~portBYTE_ALIGNMENT_MASK;
|
||||
|
||||
/* Adjust the size for the bytes lost to alignment. */
|
||||
xTotalRegionSize -= xAddress - ( size_t ) pxHeapRegion->pucStartAddress;
|
||||
}
|
||||
|
||||
xAlignedHeap = xAddress;
|
||||
|
||||
/* Set xStart if it has not already been set. */
|
||||
if( xDefinedRegions == 0 )
|
||||
{
|
||||
/* xStart is used to hold a pointer to the first item in the list of
|
||||
* free blocks. The void cast is used to prevent compiler warnings. */
|
||||
xStart.pxNextFreeBlock = ( BlockLink_t * ) xAlignedHeap;
|
||||
xStart.xBlockSize = ( size_t ) 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Should only get here if one region has already been added to the
|
||||
* heap. */
|
||||
configASSERT( pxEnd != NULL );
|
||||
|
||||
/* Check blocks are passed in with increasing start addresses. */
|
||||
configASSERT( xAddress > ( size_t ) pxEnd );
|
||||
}
|
||||
|
||||
/* Remember the location of the end marker in the previous region, if
|
||||
* any. */
|
||||
pxPreviousFreeBlock = pxEnd;
|
||||
|
||||
/* pxEnd is used to mark the end of the list of free blocks and is
|
||||
* inserted at the end of the region space. */
|
||||
xAddress = xAlignedHeap + xTotalRegionSize;
|
||||
xAddress -= xHeapStructSize;
|
||||
xAddress &= ~portBYTE_ALIGNMENT_MASK;
|
||||
pxEnd = ( BlockLink_t * ) xAddress;
|
||||
pxEnd->xBlockSize = 0;
|
||||
pxEnd->pxNextFreeBlock = NULL;
|
||||
|
||||
/* To start with there is a single free block in this region that is
|
||||
* sized to take up the entire heap region minus the space taken by the
|
||||
* free block structure. */
|
||||
pxFirstFreeBlockInRegion = ( BlockLink_t * ) xAlignedHeap;
|
||||
pxFirstFreeBlockInRegion->xBlockSize = xAddress - ( size_t ) pxFirstFreeBlockInRegion;
|
||||
pxFirstFreeBlockInRegion->pxNextFreeBlock = pxEnd;
|
||||
|
||||
/* If this is not the first region that makes up the entire heap space
|
||||
* then link the previous region to this region. */
|
||||
if( pxPreviousFreeBlock != NULL )
|
||||
{
|
||||
pxPreviousFreeBlock->pxNextFreeBlock = pxFirstFreeBlockInRegion;
|
||||
}
|
||||
|
||||
xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize;
|
||||
|
||||
/* Move onto the next HeapRegion_t structure. */
|
||||
xDefinedRegions++;
|
||||
pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );
|
||||
}
|
||||
|
||||
xMinimumEverFreeBytesRemaining = xTotalHeapSize;
|
||||
xFreeBytesRemaining = xTotalHeapSize;
|
||||
|
||||
/* Check something was actually defined before it is accessed. */
|
||||
configASSERT( xTotalHeapSize );
|
||||
|
||||
/* Work out the position of the top bit in a size_t variable. */
|
||||
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortGetHeapStats( HeapStats_t * pxHeapStats )
|
||||
{
|
||||
BlockLink_t * pxBlock;
|
||||
size_t xBlocks = 0, xMaxSize = 0, xMinSize = portMAX_DELAY; /* portMAX_DELAY used as a portable way of getting the maximum value. */
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
pxBlock = xStart.pxNextFreeBlock;
|
||||
|
||||
/* pxBlock will be NULL if the heap has not been initialised. The heap
|
||||
* is initialised automatically when the first allocation is made. */
|
||||
if( pxBlock != NULL )
|
||||
{
|
||||
do
|
||||
{
|
||||
/* Increment the number of blocks and record the largest block seen
|
||||
* so far. */
|
||||
xBlocks++;
|
||||
|
||||
if( pxBlock->xBlockSize > xMaxSize )
|
||||
{
|
||||
xMaxSize = pxBlock->xBlockSize;
|
||||
}
|
||||
|
||||
/* Heap five will have a zero sized block at the end of each
|
||||
* each region - the block is only used to link to the next
|
||||
* heap region so it not a real block. */
|
||||
if( pxBlock->xBlockSize != 0 )
|
||||
{
|
||||
if( pxBlock->xBlockSize < xMinSize )
|
||||
{
|
||||
xMinSize = pxBlock->xBlockSize;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move to the next block in the chain until the last block is
|
||||
* reached. */
|
||||
pxBlock = pxBlock->pxNextFreeBlock;
|
||||
} while( pxBlock != pxEnd );
|
||||
}
|
||||
}
|
||||
( void ) xTaskResumeAll();
|
||||
|
||||
pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize;
|
||||
pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize;
|
||||
pxHeapStats->xNumberOfFreeBlocks = xBlocks;
|
||||
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining;
|
||||
pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations;
|
||||
pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees;
|
||||
pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining;
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef BSP_PINE64_PINS_H_
|
||||
#define BSP_PINE64_PINS_H_
|
||||
#include "bl702_adc.h"
|
||||
#include "bl702_pwm.h"
|
||||
#include "hal_gpio.h"
|
||||
|
||||
#define KEY_B_Pin GPIO_PIN_28
|
||||
|
||||
@@ -8,21 +8,46 @@
|
||||
#include "BSP.h"
|
||||
#include "Debug.h"
|
||||
#include "FreeRTOSConfig.h"
|
||||
#include "Pins.h"
|
||||
|
||||
#include "IRQ.h"
|
||||
#include "Pins.h"
|
||||
#include "bl702_sec_eng.h"
|
||||
#include "history.hpp"
|
||||
#include <string.h>
|
||||
#define ADC_NORM_SAMPLES 16
|
||||
#define ADC_FILTER_LEN 4
|
||||
uint16_t ADCReadings[ADC_NORM_SAMPLES]; // room for 32 lots of the pair of readings
|
||||
|
||||
// Heap
|
||||
|
||||
extern uint8_t _heap_start;
|
||||
extern uint8_t _heap_size; // @suppress("Type cannot be resolved")
|
||||
static HeapRegion_t xHeapRegions[] = {
|
||||
{&_heap_start, (unsigned int)&_heap_size},
|
||||
{NULL, 0}, /* Terminates the array. */
|
||||
{NULL, 0} /* Terminates the array. */
|
||||
};
|
||||
|
||||
// Functions
|
||||
|
||||
void setup_timer_scheduler(void);
|
||||
void setup_pwm(void);
|
||||
void setup_adc(void);
|
||||
void hardware_init() {
|
||||
|
||||
vPortDefineHeapRegions(xHeapRegions);
|
||||
HBN_Set_XCLK_CLK_Sel(HBN_XCLK_CLK_XTAL);
|
||||
|
||||
// Set capcode
|
||||
{
|
||||
uint32_t tmpVal = 0;
|
||||
tmpVal = BL_RD_REG(AON_BASE, AON_XTAL_CFG);
|
||||
tmpVal = BL_SET_REG_BITS_VAL(tmpVal, AON_XTAL_CAPCODE_IN_AON, 33);
|
||||
tmpVal = BL_SET_REG_BITS_VAL(tmpVal, AON_XTAL_CAPCODE_OUT_AON, 33);
|
||||
BL_WR_REG(AON_BASE, AON_XTAL_CFG, tmpVal);
|
||||
}
|
||||
|
||||
Sec_Eng_Trng_Enable();
|
||||
|
||||
gpio_set_mode(OLED_RESET_Pin, GPIO_OUTPUT_MODE);
|
||||
gpio_set_mode(KEY_A_Pin, GPIO_INPUT_PD_MODE);
|
||||
gpio_set_mode(KEY_B_Pin, GPIO_INPUT_PD_MODE);
|
||||
@@ -150,12 +175,3 @@ void setupFUSBIRQ() {
|
||||
CPU_Interrupt_Enable(GPIO_INT0_IRQn);
|
||||
gpio_irq_enable(FUSB302_IRQ_Pin, ENABLE);
|
||||
}
|
||||
|
||||
void vAssertCalled(void) {
|
||||
MSG((char *)"vAssertCalled\r\n");
|
||||
PWM_Channel_Disable(PWM_Channel);
|
||||
gpio_set_mode(PWM_Out_Pin, GPIO_INPUT_PD_MODE);
|
||||
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,323 @@
|
||||
/*****************************************************************************************
|
||||
*
|
||||
* @file bl_hci_wrapper.c
|
||||
*
|
||||
* @brief Bouffalo Lab hci wrapper functions
|
||||
*
|
||||
* Copyright (C) Bouffalo Lab 2018
|
||||
*
|
||||
* History: 2018-08 crealted by llgong @ Shanghai
|
||||
*
|
||||
*****************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <log.h>
|
||||
#include "hci_host.h"
|
||||
#include "bl_hci_wrapper.h"
|
||||
#include "hci_driver.h"
|
||||
#include "../common/include/errno.h"
|
||||
#include "byteorder.h"
|
||||
#include "hci_onchip.h"
|
||||
|
||||
#define DATA_MSG_CNT 10
|
||||
|
||||
struct rx_msg_struct data_msg[DATA_MSG_CNT];
|
||||
struct k_queue msg_queue;
|
||||
#if defined(BFLB_BLE_NOTIFY_ADV_DISCARDED)
|
||||
extern void ble_controller_notify_adv_discarded(uint8_t *adv_bd_addr, uint8_t adv_type);
|
||||
#endif
|
||||
|
||||
struct rx_msg_struct *bl_find_valid_data_msg()
|
||||
{
|
||||
struct rx_msg_struct empty_msg;
|
||||
memset(&empty_msg, 0, sizeof(struct rx_msg_struct));
|
||||
|
||||
for (int i = 0; i < DATA_MSG_CNT; i++) {
|
||||
if (!memcmp(&data_msg[i], &empty_msg, sizeof(struct rx_msg_struct))) {
|
||||
return (data_msg + i);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int bl_onchiphci_send_2_controller(struct net_buf *buf)
|
||||
{
|
||||
uint16_t opcode;
|
||||
uint16_t dest_id = 0x00;
|
||||
uint8_t buf_type;
|
||||
uint8_t pkt_type;
|
||||
hci_pkt_struct pkt;
|
||||
|
||||
buf_type = bt_buf_get_type(buf);
|
||||
switch (buf_type) {
|
||||
case BT_BUF_CMD: {
|
||||
struct bt_hci_cmd_hdr *chdr;
|
||||
|
||||
if (buf->len < sizeof(struct bt_hci_cmd_hdr)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chdr = (void *)buf->data;
|
||||
|
||||
if (buf->len < chdr->param_len) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pkt_type = BT_HCI_CMD;
|
||||
opcode = sys_le16_to_cpu(chdr->opcode);
|
||||
//move buf to the payload
|
||||
net_buf_pull(buf, sizeof(struct bt_hci_cmd_hdr));
|
||||
switch (opcode) {
|
||||
//ble refer to hci_cmd_desc_tab_le, for the ones of which dest_ll is BLE_CTRL
|
||||
case BT_HCI_OP_LE_CONN_UPDATE:
|
||||
case BT_HCI_OP_LE_READ_CHAN_MAP:
|
||||
case BT_HCI_OP_LE_READ_REMOTE_FEATURES:
|
||||
case BT_HCI_OP_LE_START_ENCRYPTION:
|
||||
case BT_HCI_OP_LE_LTK_REQ_REPLY:
|
||||
case BT_HCI_OP_LE_LTK_REQ_NEG_REPLY:
|
||||
case BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY:
|
||||
case BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY:
|
||||
case BT_HCI_OP_LE_SET_DATA_LEN:
|
||||
case BT_HCI_OP_LE_READ_PHY:
|
||||
case BT_HCI_OP_LE_SET_PHY:
|
||||
//bredr identify link id, according to dest_id
|
||||
case BT_HCI_OP_READ_REMOTE_FEATURES:
|
||||
case BT_HCI_OP_READ_REMOTE_EXT_FEATURES:
|
||||
case BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE: {
|
||||
//dest_id is connectin handle
|
||||
dest_id = buf->data[0];
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pkt.p.hci_cmd.opcode = opcode;
|
||||
pkt.p.hci_cmd.param_len = chdr->param_len;
|
||||
pkt.p.hci_cmd.params = buf->data;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case BT_BUF_ACL_OUT: {
|
||||
struct bt_hci_acl_hdr *acl;
|
||||
//connhandle +l2cap field
|
||||
uint16_t connhdl_l2cf, tlt_len;
|
||||
|
||||
if (buf->len < sizeof(struct bt_hci_acl_hdr)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pkt_type = BT_HCI_ACL_DATA;
|
||||
acl = (void *)buf->data;
|
||||
tlt_len = sys_le16_to_cpu(acl->len);
|
||||
connhdl_l2cf = sys_le16_to_cpu(acl->handle);
|
||||
//move buf to the payload
|
||||
net_buf_pull(buf, sizeof(struct bt_hci_acl_hdr));
|
||||
|
||||
if (buf->len < tlt_len) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
//get connection_handle
|
||||
dest_id = bt_acl_handle(connhdl_l2cf);
|
||||
pkt.p.acl_data.conhdl = dest_id;
|
||||
pkt.p.acl_data.pb_bc_flag = bt_acl_flags(connhdl_l2cf);
|
||||
pkt.p.acl_data.len = tlt_len;
|
||||
pkt.p.acl_data.buffer = (uint8_t *)buf->data;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return bt_onchiphci_send(pkt_type, dest_id, &pkt);
|
||||
}
|
||||
|
||||
void bl_packet_to_host(uint8_t pkt_type, uint16_t src_id, uint8_t *param, uint8_t param_len, struct net_buf *buf)
|
||||
{
|
||||
uint16_t tlt_len;
|
||||
bool prio = true;
|
||||
uint8_t nb_h2c_cmd_pkts = 0x01;
|
||||
|
||||
uint8_t *buf_data = net_buf_tail(buf);
|
||||
bt_buf_set_rx_adv(buf, false);
|
||||
|
||||
switch (pkt_type) {
|
||||
case BT_HCI_CMD_CMP_EVT: {
|
||||
tlt_len = BT_HCI_EVT_CC_PARAM_OFFSET + param_len;
|
||||
*buf_data++ = BT_HCI_EVT_CMD_COMPLETE;
|
||||
*buf_data++ = BT_HCI_CCEVT_HDR_PARLEN + param_len;
|
||||
*buf_data++ = nb_h2c_cmd_pkts;
|
||||
sys_put_le16(src_id, buf_data);
|
||||
buf_data += 2;
|
||||
memcpy(buf_data, param, param_len);
|
||||
break;
|
||||
}
|
||||
case BT_HCI_CMD_STAT_EVT: {
|
||||
tlt_len = BT_HCI_CSEVT_LEN;
|
||||
*buf_data++ = BT_HCI_EVT_CMD_STATUS;
|
||||
*buf_data++ = BT_HCI_CSVT_PARLEN;
|
||||
*buf_data++ = *(uint8_t *)param;
|
||||
*buf_data++ = nb_h2c_cmd_pkts;
|
||||
sys_put_le16(src_id, buf_data);
|
||||
break;
|
||||
}
|
||||
case BT_HCI_LE_EVT: {
|
||||
prio = false;
|
||||
bt_buf_set_type(buf, BT_BUF_EVT);
|
||||
if (param[0] == BT_HCI_EVT_LE_ADVERTISING_REPORT) {
|
||||
bt_buf_set_rx_adv(buf, true);
|
||||
}
|
||||
tlt_len = BT_HCI_EVT_LE_PARAM_OFFSET + param_len;
|
||||
*buf_data++ = BT_HCI_EVT_LE_META_EVENT;
|
||||
*buf_data++ = param_len;
|
||||
memcpy(buf_data, param, param_len);
|
||||
break;
|
||||
}
|
||||
case BT_HCI_EVT: {
|
||||
if (src_id != BT_HCI_EVT_NUM_COMPLETED_PACKETS) {
|
||||
prio = false;
|
||||
}
|
||||
bt_buf_set_type(buf, BT_BUF_EVT);
|
||||
tlt_len = BT_HCI_EVT_LE_PARAM_OFFSET + param_len;
|
||||
*buf_data++ = src_id;
|
||||
*buf_data++ = param_len;
|
||||
memcpy(buf_data, param, param_len);
|
||||
break;
|
||||
}
|
||||
case BT_HCI_ACL_DATA: {
|
||||
prio = false;
|
||||
bt_buf_set_type(buf, BT_BUF_ACL_IN);
|
||||
tlt_len = bt_onchiphci_hanlde_rx_acl(param, buf_data);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
net_buf_unref(buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
net_buf_add(buf, tlt_len);
|
||||
|
||||
if (prio) {
|
||||
bt_recv_prio(buf);
|
||||
} else {
|
||||
hci_driver_enque_recvq(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void bl_trigger_queued_msg()
|
||||
{
|
||||
struct net_buf *buf = NULL;
|
||||
struct rx_msg_struct *msg = NULL;
|
||||
|
||||
do {
|
||||
unsigned int lock = irq_lock();
|
||||
|
||||
if (k_queue_is_empty(&msg_queue)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (bt_buf_get_rx_avail_cnt() <= CONFIG_BT_RX_BUF_RSV_COUNT)
|
||||
break;
|
||||
|
||||
buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT);
|
||||
if (!buf) {
|
||||
break;
|
||||
}
|
||||
|
||||
msg = k_fifo_get(&msg_queue, K_NO_WAIT);
|
||||
|
||||
BT_ASSERT(msg);
|
||||
|
||||
bl_packet_to_host(msg->pkt_type, msg->src_id, msg->param, msg->param_len, buf);
|
||||
|
||||
irq_unlock(lock);
|
||||
|
||||
if (msg->param) {
|
||||
k_free(msg->param);
|
||||
}
|
||||
memset(msg, 0, sizeof(struct rx_msg_struct));
|
||||
|
||||
} while (buf);
|
||||
}
|
||||
|
||||
static void bl_onchiphci_rx_packet_handler(uint8_t pkt_type, uint16_t src_id, uint8_t *param, uint8_t param_len)
|
||||
{
|
||||
struct net_buf *buf = NULL;
|
||||
struct rx_msg_struct *rx_msg = NULL;
|
||||
|
||||
if (pkt_type == BT_HCI_CMD_CMP_EVT || pkt_type == BT_HCI_CMD_STAT_EVT) {
|
||||
buf = bt_buf_get_cmd_complete(K_FOREVER);
|
||||
bl_packet_to_host(pkt_type, src_id, param, param_len, buf);
|
||||
return;
|
||||
} else if (pkt_type == BT_HCI_LE_EVT && param[0] == BT_HCI_EVT_LE_ADVERTISING_REPORT) {
|
||||
if (bt_buf_get_rx_avail_cnt() <= CONFIG_BT_RX_BUF_RSV_COUNT) {
|
||||
BT_INFO("Discard adv report.");
|
||||
#if defined(BFLB_BLE_NOTIFY_ADV_DISCARDED)
|
||||
ble_controller_notify_adv_discarded(¶m[4], param[2]);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT);
|
||||
if (buf)
|
||||
bl_packet_to_host(pkt_type, src_id, param, param_len, buf);
|
||||
return;
|
||||
} else {
|
||||
if (pkt_type != BT_HCI_ACL_DATA) {
|
||||
/* Using the reserved buf (CONFIG_BT_RX_BUF_RSV_COUNT) firstly. */
|
||||
buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT);
|
||||
if (buf) {
|
||||
bl_packet_to_host(pkt_type, src_id, param, param_len, buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rx_msg = bl_find_valid_data_msg();
|
||||
}
|
||||
|
||||
BT_ASSERT(rx_msg);
|
||||
|
||||
rx_msg->pkt_type = pkt_type;
|
||||
rx_msg->src_id = src_id;
|
||||
rx_msg->param_len = param_len;
|
||||
if (param_len) {
|
||||
rx_msg->param = k_malloc(param_len);
|
||||
memcpy(rx_msg->param, param, param_len);
|
||||
}
|
||||
|
||||
k_fifo_put(&msg_queue, rx_msg);
|
||||
|
||||
bl_trigger_queued_msg();
|
||||
}
|
||||
|
||||
uint8_t bl_onchiphci_interface_init(void)
|
||||
{
|
||||
for (int i = 0; i < DATA_MSG_CNT; i++) {
|
||||
memset(data_msg + i, 0, sizeof(struct rx_msg_struct));
|
||||
}
|
||||
|
||||
k_queue_init(&msg_queue, DATA_MSG_CNT);
|
||||
|
||||
return bt_onchiphci_interface_init(bl_onchiphci_rx_packet_handler);
|
||||
}
|
||||
|
||||
void bl_onchiphci_interface_deinit(void)
|
||||
{
|
||||
struct rx_msg_struct *msg;
|
||||
|
||||
do {
|
||||
msg = k_fifo_get(&msg_queue, K_NO_WAIT);
|
||||
if (msg) {
|
||||
if (msg->param) {
|
||||
k_free(msg->param);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
k_queue_free(&msg_queue);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef __BL_HCI_WRAPPER_H__
|
||||
#define __BL_HCI_WRAPPER_H__
|
||||
|
||||
#include "net/buf.h"
|
||||
#include "bluetooth.h"
|
||||
|
||||
struct rx_msg_struct {
|
||||
uint8_t pkt_type;
|
||||
uint16_t src_id;
|
||||
uint8_t *param;
|
||||
uint8_t param_len;
|
||||
} __packed;
|
||||
|
||||
typedef enum {
|
||||
DATA_TYPE_COMMAND = 1,
|
||||
DATA_TYPE_ACL = 2,
|
||||
DATA_TYPE_SCO = 3,
|
||||
DATA_TYPE_EVENT = 4
|
||||
} serial_data_type_t;
|
||||
|
||||
uint8_t bl_onchiphci_interface_init(void);
|
||||
void bl_onchiphci_interface_deinit(void);
|
||||
void bl_trigger_queued_msg(void);
|
||||
int bl_onchiphci_send_2_controller(struct net_buf *buf);
|
||||
|
||||
#endif //__BL_CONTROLLER_H__
|
||||
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
* Copyright (c) 2011-2014 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Atomic ops in pure C
|
||||
*
|
||||
* This module provides the atomic operators for processors
|
||||
* which do not support native atomic operations.
|
||||
*
|
||||
* The atomic operations are guaranteed to be atomic with respect
|
||||
* to interrupt service routines, and to operations performed by peer
|
||||
* processors.
|
||||
*
|
||||
* (originally from x86's atomic.c)
|
||||
*/
|
||||
#include <FreeRTOS.h>
|
||||
#include <include/atomic.h>
|
||||
#include "bl_port.h"
|
||||
//#include <toolchain.h>
|
||||
//#include <arch/cpu.h>
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic compare-and-set primitive
|
||||
*
|
||||
* This routine provides the compare-and-set operator. If the original value at
|
||||
* <target> equals <oldValue>, then <newValue> is stored at <target> and the
|
||||
* function returns 1.
|
||||
*
|
||||
* If the original value at <target> does not equal <oldValue>, then the store
|
||||
* is not done and the function returns 0.
|
||||
*
|
||||
* The reading of the original value at <target>, the comparison,
|
||||
* and the write of the new value (if it occurs) all happen atomically with
|
||||
* respect to both interrupts and accesses of other processors to <target>.
|
||||
*
|
||||
* @param target address to be tested
|
||||
* @param old_value value to compare against
|
||||
* @param new_value value to compare against
|
||||
* @return Returns 1 if <new_value> is written, 0 otherwise.
|
||||
*/
|
||||
int atomic_cas(atomic_t *target, atomic_val_t old_value,
|
||||
atomic_val_t new_value)
|
||||
{
|
||||
unsigned int key;
|
||||
int ret = 0;
|
||||
|
||||
key = irq_lock();
|
||||
|
||||
if (*target == old_value) {
|
||||
*target = new_value;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
irq_unlock(key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic addition primitive
|
||||
*
|
||||
* This routine provides the atomic addition operator. The <value> is
|
||||
* atomically added to the value at <target>, placing the result at <target>,
|
||||
* and the old value from <target> is returned.
|
||||
*
|
||||
* @param target memory location to add to
|
||||
* @param value the value to add
|
||||
*
|
||||
* @return The previous value from <target>
|
||||
*/
|
||||
atomic_val_t atomic_add(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
unsigned int key;
|
||||
atomic_val_t ret;
|
||||
|
||||
key = irq_lock();
|
||||
|
||||
ret = *target;
|
||||
*target += value;
|
||||
|
||||
irq_unlock(key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic subtraction primitive
|
||||
*
|
||||
* This routine provides the atomic subtraction operator. The <value> is
|
||||
* atomically subtracted from the value at <target>, placing the result at
|
||||
* <target>, and the old value from <target> is returned.
|
||||
*
|
||||
* @param target the memory location to subtract from
|
||||
* @param value the value to subtract
|
||||
*
|
||||
* @return The previous value from <target>
|
||||
*/
|
||||
atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
unsigned int key;
|
||||
atomic_val_t ret;
|
||||
|
||||
key = irq_lock();
|
||||
|
||||
ret = *target;
|
||||
*target -= value;
|
||||
|
||||
irq_unlock(key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic increment primitive
|
||||
*
|
||||
* @param target memory location to increment
|
||||
*
|
||||
* This routine provides the atomic increment operator. The value at <target>
|
||||
* is atomically incremented by 1, and the old value from <target> is returned.
|
||||
*
|
||||
* @return The value from <target> before the increment
|
||||
*/
|
||||
atomic_val_t atomic_inc(atomic_t *target)
|
||||
{
|
||||
unsigned int key;
|
||||
atomic_val_t ret;
|
||||
|
||||
key = irq_lock();
|
||||
|
||||
ret = *target;
|
||||
(*target)++;
|
||||
|
||||
irq_unlock(key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic decrement primitive
|
||||
*
|
||||
* @param target memory location to decrement
|
||||
*
|
||||
* This routine provides the atomic decrement operator. The value at <target>
|
||||
* is atomically decremented by 1, and the old value from <target> is returned.
|
||||
*
|
||||
* @return The value from <target> prior to the decrement
|
||||
*/
|
||||
atomic_val_t atomic_dec(atomic_t *target)
|
||||
{
|
||||
unsigned int key;
|
||||
atomic_val_t ret;
|
||||
|
||||
key = irq_lock();
|
||||
|
||||
ret = *target;
|
||||
(*target)--;
|
||||
|
||||
irq_unlock(key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic get primitive
|
||||
*
|
||||
* @param target memory location to read from
|
||||
*
|
||||
* This routine provides the atomic get primitive to atomically read
|
||||
* a value from <target>. It simply does an ordinary load. Note that <target>
|
||||
* is expected to be aligned to a 4-byte boundary.
|
||||
*
|
||||
* @return The value read from <target>
|
||||
*/
|
||||
atomic_val_t atomic_get(const atomic_t *target)
|
||||
{
|
||||
return *target;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic get-and-set primitive
|
||||
*
|
||||
* This routine provides the atomic set operator. The <value> is atomically
|
||||
* written at <target> and the previous value at <target> is returned.
|
||||
*
|
||||
* @param target the memory location to write to
|
||||
* @param value the value to write
|
||||
*
|
||||
* @return The previous value from <target>
|
||||
*/
|
||||
atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
unsigned int key;
|
||||
atomic_val_t ret;
|
||||
|
||||
key = irq_lock();
|
||||
|
||||
ret = *target;
|
||||
*target = value;
|
||||
|
||||
irq_unlock(key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic clear primitive
|
||||
*
|
||||
* This routine provides the atomic clear operator. The value of 0 is atomically
|
||||
* written at <target> and the previous value at <target> is returned. (Hence,
|
||||
* atomic_clear(pAtomicVar) is equivalent to atomic_set(pAtomicVar, 0).)
|
||||
*
|
||||
* @param target the memory location to write
|
||||
*
|
||||
* @return The previous value from <target>
|
||||
*/
|
||||
atomic_val_t atomic_clear(atomic_t *target)
|
||||
{
|
||||
unsigned int key;
|
||||
atomic_val_t ret;
|
||||
|
||||
key = irq_lock();
|
||||
|
||||
ret = *target;
|
||||
*target = 0;
|
||||
|
||||
irq_unlock(key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic bitwise inclusive OR primitive
|
||||
*
|
||||
* This routine provides the atomic bitwise inclusive OR operator. The <value>
|
||||
* is atomically bitwise OR'ed with the value at <target>, placing the result
|
||||
* at <target>, and the previous value at <target> is returned.
|
||||
*
|
||||
* @param target the memory location to be modified
|
||||
* @param value the value to OR
|
||||
*
|
||||
* @return The previous value from <target>
|
||||
*/
|
||||
atomic_val_t atomic_or(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
unsigned int key;
|
||||
atomic_val_t ret;
|
||||
|
||||
key = irq_lock();
|
||||
|
||||
ret = *target;
|
||||
*target |= value;
|
||||
|
||||
irq_unlock(key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic bitwise exclusive OR (XOR) primitive
|
||||
*
|
||||
* This routine provides the atomic bitwise exclusive OR operator. The <value>
|
||||
* is atomically bitwise XOR'ed with the value at <target>, placing the result
|
||||
* at <target>, and the previous value at <target> is returned.
|
||||
*
|
||||
* @param target the memory location to be modified
|
||||
* @param value the value to XOR
|
||||
*
|
||||
* @return The previous value from <target>
|
||||
*/
|
||||
atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
unsigned int key;
|
||||
atomic_val_t ret;
|
||||
|
||||
key = irq_lock();
|
||||
|
||||
ret = *target;
|
||||
*target ^= value;
|
||||
|
||||
irq_unlock(key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic bitwise AND primitive
|
||||
*
|
||||
* This routine provides the atomic bitwise AND operator. The <value> is
|
||||
* atomically bitwise AND'ed with the value at <target>, placing the result
|
||||
* at <target>, and the previous value at <target> is returned.
|
||||
*
|
||||
* @param target the memory location to be modified
|
||||
* @param value the value to AND
|
||||
*
|
||||
* @return The previous value from <target>
|
||||
*/
|
||||
atomic_val_t atomic_and(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
unsigned int key;
|
||||
atomic_val_t ret;
|
||||
|
||||
key = irq_lock();
|
||||
|
||||
ret = *target;
|
||||
*target &= value;
|
||||
|
||||
irq_unlock(key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic bitwise NAND primitive
|
||||
*
|
||||
* This routine provides the atomic bitwise NAND operator. The <value> is
|
||||
* atomically bitwise NAND'ed with the value at <target>, placing the result
|
||||
* at <target>, and the previous value at <target> is returned.
|
||||
*
|
||||
* @param target the memory location to be modified
|
||||
* @param value the value to NAND
|
||||
*
|
||||
* @return The previous value from <target>
|
||||
*/
|
||||
atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
unsigned int key;
|
||||
atomic_val_t ret;
|
||||
|
||||
key = irq_lock();
|
||||
|
||||
ret = *target;
|
||||
*target = ~(*target & value);
|
||||
|
||||
irq_unlock(key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <util.h>
|
||||
|
||||
u8_t u8_to_dec(char *buf, u8_t buflen, u8_t value)
|
||||
{
|
||||
u8_t divisor = 100;
|
||||
u8_t num_digits = 0;
|
||||
u8_t digit;
|
||||
|
||||
while (buflen > 0 && divisor > 0) {
|
||||
digit = value / divisor;
|
||||
if (digit != 0 || divisor == 1 || num_digits != 0) {
|
||||
*buf = (char)digit + '0';
|
||||
buf++;
|
||||
buflen--;
|
||||
num_digits++;
|
||||
}
|
||||
|
||||
value -= digit * divisor;
|
||||
divisor /= 10;
|
||||
}
|
||||
|
||||
if (buflen) {
|
||||
*buf = '\0';
|
||||
}
|
||||
|
||||
return num_digits;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @file dummy.c
|
||||
* Static compilation checks.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
|
||||
#if defined(CONFIG_BT_HCI_HOST)
|
||||
/* The Bluetooth subsystem requires the Tx thread to execute at higher priority
|
||||
* than the Rx thread as the Tx thread needs to process the acknowledgements
|
||||
* before new Rx data is processed. This is a necessity to correctly detect
|
||||
* transaction violations in ATT and SMP protocols.
|
||||
*/
|
||||
BUILD_ASSERT(CONFIG_BT_HCI_TX_PRIO < CONFIG_BT_RX_PRIO);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_CTLR)
|
||||
/* The Bluetooth Controller's priority receive thread priority shall be higher
|
||||
* than the Bluetooth Host's Tx and the Controller's receive thread priority.
|
||||
* This is required in order to dispatch Number of Completed Packets event
|
||||
* before any new data arrives on a connection to the Host threads.
|
||||
*/
|
||||
BUILD_ASSERT(CONFIG_BT_CTLR_RX_PRIO < CONFIG_BT_HCI_TX_PRIO);
|
||||
#endif /* CONFIG_BT_CTLR */
|
||||
|
||||
/* Immediate logging is not supported with the software-based Link Layer
|
||||
* since it introduces ISR latency due to outputting log messages with
|
||||
* interrupts disabled.
|
||||
*/
|
||||
#if !defined(CONFIG_TEST) && !defined(CONFIG_ARCH_POSIX) && \
|
||||
(defined(CONFIG_BT_LL_SW_SPLIT) || defined(CONFIG_BT_LL_SW_LEGACY))
|
||||
BUILD_ASSERT_MSG(!IS_ENABLED(CONFIG_LOG_IMMEDIATE), "Immediate logging not "
|
||||
"supported with the software Link Layer");
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <zephyr/types.h>
|
||||
#include <errno.h>
|
||||
// #include <sys/util.h>
|
||||
|
||||
@@ -0,0 +1,444 @@
|
||||
/* atomic operations */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997-2015, Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __ATOMIC_H__
|
||||
#define __ATOMIC_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int atomic_t;
|
||||
typedef atomic_t atomic_val_t;
|
||||
|
||||
/**
|
||||
* @defgroup atomic_apis Atomic Services APIs
|
||||
* @ingroup kernel_apis
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Atomic compare-and-set.
|
||||
*
|
||||
* This routine performs an atomic compare-and-set on @a target. If the current
|
||||
* value of @a target equals @a old_value, @a target is set to @a new_value.
|
||||
* If the current value of @a target does not equal @a old_value, @a target
|
||||
* is left unchanged.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param old_value Original value to compare against.
|
||||
* @param new_value New value to store.
|
||||
* @return 1 if @a new_value is written, 0 otherwise.
|
||||
*/
|
||||
#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
|
||||
static inline int atomic_cas(atomic_t *target, atomic_val_t old_value,
|
||||
atomic_val_t new_value)
|
||||
{
|
||||
return __atomic_compare_exchange_n(target, &old_value, new_value,
|
||||
0, __ATOMIC_SEQ_CST,
|
||||
__ATOMIC_SEQ_CST);
|
||||
}
|
||||
#else
|
||||
extern int atomic_cas(atomic_t *target, atomic_val_t old_value,
|
||||
atomic_val_t new_value);
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic addition.
|
||||
*
|
||||
* This routine performs an atomic addition on @a target.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param value Value to add.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
|
||||
static inline atomic_val_t atomic_add(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
return __atomic_fetch_add(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
#else
|
||||
extern atomic_val_t atomic_add(atomic_t *target, atomic_val_t value);
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic subtraction.
|
||||
*
|
||||
* This routine performs an atomic subtraction on @a target.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param value Value to subtract.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
|
||||
static inline atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
return __atomic_fetch_sub(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
#else
|
||||
extern atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value);
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic increment.
|
||||
*
|
||||
* This routine performs an atomic increment by 1 on @a target.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
|
||||
static inline atomic_val_t atomic_inc(atomic_t *target)
|
||||
{
|
||||
return atomic_add(target, 1);
|
||||
}
|
||||
#else
|
||||
extern atomic_val_t atomic_inc(atomic_t *target);
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic decrement.
|
||||
*
|
||||
* This routine performs an atomic decrement by 1 on @a target.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
|
||||
static inline atomic_val_t atomic_dec(atomic_t *target)
|
||||
{
|
||||
return atomic_sub(target, 1);
|
||||
}
|
||||
#else
|
||||
extern atomic_val_t atomic_dec(atomic_t *target);
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic get.
|
||||
*
|
||||
* This routine performs an atomic read on @a target.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
*
|
||||
* @return Value of @a target.
|
||||
*/
|
||||
#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
|
||||
static inline atomic_val_t atomic_get(const atomic_t *target)
|
||||
{
|
||||
return __atomic_load_n(target, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
#else
|
||||
extern atomic_val_t atomic_get(const atomic_t *target);
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic get-and-set.
|
||||
*
|
||||
* This routine atomically sets @a target to @a value and returns
|
||||
* the previous value of @a target.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param value Value to write to @a target.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
|
||||
static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
/* This builtin, as described by Intel, is not a traditional
|
||||
* test-and-set operation, but rather an atomic exchange operation. It
|
||||
* writes value into *ptr, and returns the previous contents of *ptr.
|
||||
*/
|
||||
return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
#else
|
||||
extern atomic_val_t atomic_set(atomic_t *target, atomic_val_t value);
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic clear.
|
||||
*
|
||||
* This routine atomically sets @a target to zero and returns its previous
|
||||
* value. (Hence, it is equivalent to atomic_set(target, 0).)
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
|
||||
static inline atomic_val_t atomic_clear(atomic_t *target)
|
||||
{
|
||||
return atomic_set(target, 0);
|
||||
}
|
||||
#else
|
||||
extern atomic_val_t atomic_clear(atomic_t *target);
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic bitwise inclusive OR.
|
||||
*
|
||||
* This routine atomically sets @a target to the bitwise inclusive OR of
|
||||
* @a target and @a value.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param value Value to OR.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
|
||||
static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
#else
|
||||
extern atomic_val_t atomic_or(atomic_t *target, atomic_val_t value);
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic bitwise exclusive OR (XOR).
|
||||
*
|
||||
* This routine atomically sets @a target to the bitwise exclusive OR (XOR) of
|
||||
* @a target and @a value.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param value Value to XOR
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
|
||||
static inline atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
return __atomic_fetch_xor(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
#else
|
||||
extern atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value);
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic bitwise AND.
|
||||
*
|
||||
* This routine atomically sets @a target to the bitwise AND of @a target
|
||||
* and @a value.
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param value Value to AND.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
|
||||
static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
#else
|
||||
extern atomic_val_t atomic_and(atomic_t *target, atomic_val_t value);
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Atomic bitwise NAND.
|
||||
*
|
||||
* This routine atomically sets @a target to the bitwise NAND of @a target
|
||||
* and @a value. (This operation is equivalent to target = ~(target & value).)
|
||||
*
|
||||
* @param target Address of atomic variable.
|
||||
* @param value Value to NAND.
|
||||
*
|
||||
* @return Previous value of @a target.
|
||||
*/
|
||||
#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
|
||||
static inline atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value)
|
||||
{
|
||||
return __atomic_fetch_nand(target, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
#else
|
||||
extern atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize an atomic variable.
|
||||
*
|
||||
* This macro can be used to initialize an atomic variable. For example,
|
||||
* @code atomic_t my_var = ATOMIC_INIT(75); @endcode
|
||||
*
|
||||
* @param i Value to assign to atomic variable.
|
||||
*/
|
||||
#define ATOMIC_INIT(i) (i)
|
||||
|
||||
/**
|
||||
* @cond INTERNAL_HIDDEN
|
||||
*/
|
||||
|
||||
#define ATOMIC_BITS (sizeof(atomic_val_t) * 8)
|
||||
#define ATOMIC_MASK(bit) (1 << ((bit) & (ATOMIC_BITS - 1)))
|
||||
#define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS))
|
||||
|
||||
/**
|
||||
* INTERNAL_HIDDEN @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Define an array of atomic variables.
|
||||
*
|
||||
* This macro defines an array of atomic variables containing at least
|
||||
* @a num_bits bits.
|
||||
*
|
||||
* @note
|
||||
* If used from file scope, the bits of the array are initialized to zero;
|
||||
* if used from within a function, the bits are left uninitialized.
|
||||
*
|
||||
* @param name Name of array of atomic variables.
|
||||
* @param num_bits Number of bits needed.
|
||||
*/
|
||||
#define ATOMIC_DEFINE(name, num_bits) \
|
||||
atomic_t name[1 + ((num_bits)-1) / ATOMIC_BITS]
|
||||
|
||||
/**
|
||||
* @brief Atomically test a bit.
|
||||
*
|
||||
* This routine tests whether bit number @a bit of @a target is set or not.
|
||||
* The target may be a single atomic variable or an array of them.
|
||||
*
|
||||
* @param target Address of atomic variable or array.
|
||||
* @param bit Bit number (starting from 0).
|
||||
*
|
||||
* @return 1 if the bit was set, 0 if it wasn't.
|
||||
*/
|
||||
static inline int atomic_test_bit(const atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit));
|
||||
|
||||
return (1 & (val >> (bit & (ATOMIC_BITS - 1))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Atomically test and clear a bit.
|
||||
*
|
||||
* Atomically clear bit number @a bit of @a target and return its old value.
|
||||
* The target may be a single atomic variable or an array of them.
|
||||
*
|
||||
* @param target Address of atomic variable or array.
|
||||
* @param bit Bit number (starting from 0).
|
||||
*
|
||||
* @return 1 if the bit was set, 0 if it wasn't.
|
||||
*/
|
||||
static inline int atomic_test_and_clear_bit(atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
atomic_val_t old;
|
||||
|
||||
old = atomic_and(ATOMIC_ELEM(target, bit), ~mask);
|
||||
|
||||
return (old & mask) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Atomically set a bit.
|
||||
*
|
||||
* Atomically set bit number @a bit of @a target and return its old value.
|
||||
* The target may be a single atomic variable or an array of them.
|
||||
*
|
||||
* @param target Address of atomic variable or array.
|
||||
* @param bit Bit number (starting from 0).
|
||||
*
|
||||
* @return 1 if the bit was set, 0 if it wasn't.
|
||||
*/
|
||||
static inline int atomic_test_and_set_bit(atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
atomic_val_t old;
|
||||
|
||||
old = atomic_or(ATOMIC_ELEM(target, bit), mask);
|
||||
|
||||
return (old & mask) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Atomically clear a bit.
|
||||
*
|
||||
* Atomically clear bit number @a bit of @a target.
|
||||
* The target may be a single atomic variable or an array of them.
|
||||
*
|
||||
* @param target Address of atomic variable or array.
|
||||
* @param bit Bit number (starting from 0).
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
static inline void atomic_clear_bit(atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
|
||||
atomic_and(ATOMIC_ELEM(target, bit), ~mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Atomically set a bit.
|
||||
*
|
||||
* Atomically set bit number @a bit of @a target.
|
||||
* The target may be a single atomic variable or an array of them.
|
||||
*
|
||||
* @param target Address of atomic variable or array.
|
||||
* @param bit Bit number (starting from 0).
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
static inline void atomic_set_bit(atomic_t *target, int bit)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
|
||||
atomic_or(ATOMIC_ELEM(target, bit), mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Atomically set a bit to a given value.
|
||||
*
|
||||
* Atomically set bit number @a bit of @a target to value @a val.
|
||||
* The target may be a single atomic variable or an array of them.
|
||||
*
|
||||
* @param target Address of atomic variable or array.
|
||||
* @param bit Bit number (starting from 0).
|
||||
* @param val true for 1, false for 0.
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val)
|
||||
{
|
||||
atomic_val_t mask = ATOMIC_MASK(bit);
|
||||
|
||||
if (val) {
|
||||
(void)atomic_or(ATOMIC_ELEM(target, bit), mask);
|
||||
} else {
|
||||
(void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ATOMIC_H__ */
|
||||
@@ -0,0 +1,132 @@
|
||||
/* errno.h - errno numbers */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1984-1999, 2012 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1986 Regents of the University of California.
|
||||
* All rights reserved. The Berkeley software License Agreement
|
||||
* specifies the terms and conditions for redistribution.
|
||||
*
|
||||
* @(#)errno.h 7.1 (Berkeley) 6/4/86
|
||||
*/
|
||||
|
||||
#ifndef __INCerrnoh
|
||||
#define __INCerrnoh
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int *__errno(void);
|
||||
#define errno (*__errno())
|
||||
|
||||
/*
|
||||
* POSIX Error codes
|
||||
*/
|
||||
|
||||
#define EPERM 1 /* Not owner */
|
||||
#define ENOENT 2 /* No such file or directory */
|
||||
#define ESRCH 3 /* No such context */
|
||||
#define EINTR 4 /* Interrupted system call */
|
||||
#define EIO 5 /* I/O error */
|
||||
#define ENXIO 6 /* No such device or address */
|
||||
#define E2BIG 7 /* Arg list too long */
|
||||
#define ENOEXEC 8 /* Exec format error */
|
||||
#define EBADF 9 /* Bad file number */
|
||||
#define ECHILD 10 /* No children */
|
||||
#define EAGAIN 11 /* No more contexts */
|
||||
#define ENOMEM 12 /* Not enough core */
|
||||
#define EACCES 13 /* Permission denied */
|
||||
#define EFAULT 14 /* Bad address */
|
||||
#define ENOTEMPTY 15 /* Directory not empty */
|
||||
#define EBUSY 16 /* Mount device busy */
|
||||
#define EEXIST 17 /* File exists */
|
||||
#define EXDEV 18 /* Cross-device link */
|
||||
#define ENODEV 19 /* No such device */
|
||||
#define ENOTDIR 20 /* Not a directory */
|
||||
#define EISDIR 21 /* Is a directory */
|
||||
#define EINVAL 22 /* Invalid argument */
|
||||
#define ENFILE 23 /* File table overflow */
|
||||
#define EMFILE 24 /* Too many open files */
|
||||
#define ENOTTY 25 /* Not a typewriter */
|
||||
#define ENAMETOOLONG 26 /* File name too long */
|
||||
#define EFBIG 27 /* File too large */
|
||||
#define ENOSPC 28 /* No space left on device */
|
||||
#define ESPIPE 29 /* Illegal seek */
|
||||
#define EROFS 30 /* Read-only file system */
|
||||
#define EMLINK 31 /* Too many links */
|
||||
#define EPIPE 32 /* Broken pipe */
|
||||
#define EDEADLK 33 /* Resource deadlock avoided */
|
||||
#define ENOLCK 34 /* No locks available */
|
||||
#define ENOTSUP 35 /* Unsupported value */
|
||||
#define EMSGSIZE 36 /* Message size */
|
||||
|
||||
/* ANSI math software */
|
||||
#define EDOM 37 /* Argument too large */
|
||||
#define ERANGE 38 /* Result too large */
|
||||
|
||||
/* ipc/network software */
|
||||
|
||||
/* argument errors */
|
||||
#define EDESTADDRREQ 40 /* Destination address required */
|
||||
#define EPROTOTYPE 41 /* Protocol wrong type for socket */
|
||||
#define ENOPROTOOPT 42 /* Protocol not available */
|
||||
#define EPROTONOSUPPORT 43 /* Protocol not supported */
|
||||
#define ESOCKTNOSUPPORT 44 /* Socket type not supported */
|
||||
#define EOPNOTSUPP 45 /* Operation not supported on socket */
|
||||
#define EPFNOSUPPORT 46 /* Protocol family not supported */
|
||||
#define EAFNOSUPPORT 47 /* Addr family not supported */
|
||||
#define EADDRINUSE 48 /* Address already in use */
|
||||
#define EADDRNOTAVAIL 49 /* Can't assign requested address */
|
||||
#define ENOTSOCK 50 /* Socket operation on non-socket */
|
||||
|
||||
/* operational errors */
|
||||
#define ENETUNREACH 51 /* Network is unreachable */
|
||||
#define ENETRESET 52 /* Network dropped connection on reset */
|
||||
#define ECONNABORTED 53 /* Software caused connection abort */
|
||||
#define ECONNRESET 54 /* Connection reset by peer */
|
||||
#define ENOBUFS 55 /* No buffer space available */
|
||||
#define EISCONN 56 /* Socket is already connected */
|
||||
#define ENOTCONN 57 /* Socket is not connected */
|
||||
#define ESHUTDOWN 58 /* Can't send after socket shutdown */
|
||||
#define ETOOMANYREFS 59 /* Too many references: can't splice */
|
||||
#define ETIMEDOUT 60 /* Connection timed out */
|
||||
#define ECONNREFUSED 61 /* Connection refused */
|
||||
#define ENETDOWN 62 /* Network is down */
|
||||
#define ETXTBSY 63 /* Text file busy */
|
||||
#define ELOOP 64 /* Too many levels of symbolic links */
|
||||
#define EHOSTUNREACH 65 /* No route to host */
|
||||
#define ENOTBLK 66 /* Block device required */
|
||||
#define EHOSTDOWN 67 /* Host is down */
|
||||
|
||||
/* non-blocking and interrupt i/o */
|
||||
#define EINPROGRESS 68 /* Operation now in progress */
|
||||
#define EALREADY 69 /* Operation already in progress */
|
||||
#define EWOULDBLOCK EAGAIN /* Operation would block */
|
||||
|
||||
#define ENOSYS 71 /* Function not implemented */
|
||||
|
||||
/* aio errors (should be under posix) */
|
||||
#define ECANCELED 72 /* Operation canceled */
|
||||
|
||||
#define ERRMAX 81
|
||||
|
||||
/* specific STREAMS errno values */
|
||||
|
||||
#define ENOSR 74 /* Insufficient memory */
|
||||
#define ENOSTR 75 /* STREAMS device required */
|
||||
#define EPROTO 76 /* Generic STREAMS error */
|
||||
#define EBADMSG 77 /* Invalid STREAMS message */
|
||||
#define ENODATA 78 /* Missing expected message data */
|
||||
#define ETIME 79 /* STREAMS timeout occurred */
|
||||
#define ENOMSG 80 /* Unexpected message type */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INCerrnoh */
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2014 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Debug aid
|
||||
*
|
||||
*
|
||||
* The __ASSERT() macro can be used inside kernel code.
|
||||
*
|
||||
* Assertions are enabled by setting the __ASSERT_ON symbol to a non-zero value.
|
||||
* There are two ways to do this:
|
||||
* a) Use the ASSERT and ASSERT_LEVEL kconfig options
|
||||
* b) Add "CFLAGS += -D__ASSERT_ON=<level>" at the end of a project's Makefile
|
||||
* The Makefile method takes precedence over the kconfig option if both are
|
||||
* used.
|
||||
*
|
||||
* Specifying an assertion level of 1 causes the compiler to issue warnings that
|
||||
* the kernel contains debug-type __ASSERT() statements; this reminder is issued
|
||||
* since assertion code is not normally present in a final product. Specifying
|
||||
* assertion level 2 suppresses these warnings.
|
||||
*
|
||||
* The __ASSERT_EVAL() macro can also be used inside kernel code.
|
||||
*
|
||||
* It makes use of the __ASSERT() macro, but has some extra flexibility. It
|
||||
* allows the developer to specify different actions depending whether the
|
||||
* __ASSERT() macro is enabled or not. This can be particularly useful to
|
||||
* prevent the compiler from generating comments (errors, warnings or remarks)
|
||||
* about variables that are only used with __ASSERT() being assigned a value,
|
||||
* but otherwise unused when the __ASSERT() macro is disabled.
|
||||
*
|
||||
* Consider the following example:
|
||||
*
|
||||
* int x;
|
||||
*
|
||||
* x = foo ();
|
||||
* __ASSERT (x != 0, "foo() returned zero!");
|
||||
*
|
||||
* If __ASSERT() is disabled, then 'x' is assigned a value, but never used.
|
||||
* This type of situation can be resolved using the __ASSERT_EVAL() macro.
|
||||
*
|
||||
* __ASSERT_EVAL ((void) foo(),
|
||||
* int x = foo(),
|
||||
* x != 0,
|
||||
* "foo() returned zero!");
|
||||
*
|
||||
* The first parameter tells __ASSERT_EVAL() what to do if __ASSERT() is
|
||||
* disabled. The second parameter tells __ASSERT_EVAL() what to do if
|
||||
* __ASSERT() is enabled. The third and fourth parameters are the parameters
|
||||
* it passes to __ASSERT().
|
||||
*
|
||||
* The __ASSERT_NO_MSG() macro can be used to perform an assertion that reports
|
||||
* the failed test and its location, but lacks additional debugging information
|
||||
* provided to assist the user in diagnosing the problem; its use is
|
||||
* discouraged.
|
||||
*/
|
||||
|
||||
#ifndef ___ASSERT__H_
|
||||
#define ___ASSERT__H_
|
||||
|
||||
#ifdef CONFIG_ASSERT
|
||||
#ifndef __ASSERT_ON
|
||||
#define __ASSERT_ON CONFIG_ASSERT_LEVEL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __ASSERT_ON
|
||||
#if (__ASSERT_ON < 0) || (__ASSERT_ON > 2)
|
||||
#error "Invalid __ASSERT() level: must be between 0 and 2"
|
||||
#endif
|
||||
|
||||
#if __ASSERT_ON
|
||||
#include <misc/printk.h>
|
||||
#define __ASSERT(test, fmt, ...) \
|
||||
do { \
|
||||
if (!(test)) { \
|
||||
printk("ASSERTION FAIL [%s] @ %s:%d:\n\t", \
|
||||
_STRINGIFY(test), \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
printk(fmt, ##__VA_ARGS__); \
|
||||
for (;;) \
|
||||
; /* spin thread */ \
|
||||
} \
|
||||
} while ((0))
|
||||
|
||||
#define __ASSERT_EVAL(expr1, expr2, test, fmt, ...) \
|
||||
do { \
|
||||
expr2; \
|
||||
__ASSERT(test, fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#if (__ASSERT_ON == 1)
|
||||
#warning "__ASSERT() statements are ENABLED"
|
||||
#endif
|
||||
#else
|
||||
#define __ASSERT(test, fmt, ...) \
|
||||
do { /* nothing */ \
|
||||
} while ((0))
|
||||
#define __ASSERT_EVAL(expr1, expr2, test, fmt, ...) expr1
|
||||
#endif
|
||||
#else
|
||||
#define __ASSERT(test, fmt, ...) \
|
||||
do { /* nothing */ \
|
||||
} while ((0))
|
||||
#define __ASSERT_EVAL(expr1, expr2, test, fmt, ...) expr1
|
||||
#endif
|
||||
|
||||
#define __ASSERT_NO_MSG(test) __ASSERT(test, "")
|
||||
|
||||
#endif /* ___ASSERT__H_ */
|
||||
@@ -0,0 +1,441 @@
|
||||
/** @file
|
||||
* @brief Byte order helpers.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016, Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __BYTEORDER_H__
|
||||
#define __BYTEORDER_H__
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <stddef.h>
|
||||
#include <misc/__assert.h>
|
||||
|
||||
#ifndef __BYTE_ORDER__
|
||||
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
|
||||
#endif
|
||||
|
||||
/* Internal helpers only used by the sys_* APIs further below */
|
||||
#define __bswap_16(x) ((u16_t)((((x) >> 8) & 0xff) | (((x)&0xff) << 8)))
|
||||
#define __bswap_32(x) ((u32_t)((((x) >> 24) & 0xff) | \
|
||||
(((x) >> 8) & 0xff00) | \
|
||||
(((x)&0xff00) << 8) | \
|
||||
(((x)&0xff) << 24)))
|
||||
#define __bswap_64(x) ((u64_t)((((x) >> 56) & 0xff) | \
|
||||
(((x) >> 40) & 0xff00) | \
|
||||
(((x) >> 24) & 0xff0000) | \
|
||||
(((x) >> 8) & 0xff000000) | \
|
||||
(((x)&0xff000000) << 8) | \
|
||||
(((x)&0xff0000) << 24) | \
|
||||
(((x)&0xff00) << 40) | \
|
||||
(((x)&0xff) << 56)))
|
||||
|
||||
/** @def sys_le16_to_cpu
|
||||
* @brief Convert 16-bit integer from little-endian to host endianness.
|
||||
*
|
||||
* @param val 16-bit integer in little-endian format.
|
||||
*
|
||||
* @return 16-bit integer in host endianness.
|
||||
*/
|
||||
|
||||
/** @def sys_cpu_to_le16
|
||||
* @brief Convert 16-bit integer from host endianness to little-endian.
|
||||
*
|
||||
* @param val 16-bit integer in host endianness.
|
||||
*
|
||||
* @return 16-bit integer in little-endian format.
|
||||
*/
|
||||
|
||||
/** @def sys_be16_to_cpu
|
||||
* @brief Convert 16-bit integer from big-endian to host endianness.
|
||||
*
|
||||
* @param val 16-bit integer in big-endian format.
|
||||
*
|
||||
* @return 16-bit integer in host endianness.
|
||||
*/
|
||||
|
||||
/** @def sys_cpu_to_be16
|
||||
* @brief Convert 16-bit integer from host endianness to big-endian.
|
||||
*
|
||||
* @param val 16-bit integer in host endianness.
|
||||
*
|
||||
* @return 16-bit integer in big-endian format.
|
||||
*/
|
||||
|
||||
/** @def sys_le32_to_cpu
|
||||
* @brief Convert 32-bit integer from little-endian to host endianness.
|
||||
*
|
||||
* @param val 32-bit integer in little-endian format.
|
||||
*
|
||||
* @return 32-bit integer in host endianness.
|
||||
*/
|
||||
|
||||
/** @def sys_cpu_to_le32
|
||||
* @brief Convert 32-bit integer from host endianness to little-endian.
|
||||
*
|
||||
* @param val 32-bit integer in host endianness.
|
||||
*
|
||||
* @return 32-bit integer in little-endian format.
|
||||
*/
|
||||
|
||||
/** @def sys_be32_to_cpu
|
||||
* @brief Convert 32-bit integer from big-endian to host endianness.
|
||||
*
|
||||
* @param val 32-bit integer in big-endian format.
|
||||
*
|
||||
* @return 32-bit integer in host endianness.
|
||||
*/
|
||||
|
||||
/** @def sys_cpu_to_be32
|
||||
* @brief Convert 32-bit integer from host endianness to big-endian.
|
||||
*
|
||||
* @param val 32-bit integer in host endianness.
|
||||
*
|
||||
* @return 32-bit integer in big-endian format.
|
||||
*/
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define sys_le16_to_cpu(val) (val)
|
||||
#define sys_cpu_to_le16(val) (val)
|
||||
#define sys_be16_to_cpu(val) __bswap_16(val)
|
||||
#define sys_cpu_to_be16(val) __bswap_16(val)
|
||||
#define sys_le32_to_cpu(val) (val)
|
||||
#define sys_cpu_to_le32(val) (val)
|
||||
#define sys_le64_to_cpu(val) (val)
|
||||
#define sys_cpu_to_le64(val) (val)
|
||||
#define sys_be32_to_cpu(val) __bswap_32(val)
|
||||
#define sys_cpu_to_be32(val) __bswap_32(val)
|
||||
#define sys_be64_to_cpu(val) __bswap_64(val)
|
||||
#define sys_cpu_to_be64(val) __bswap_64(val)
|
||||
/********************************************************************************
|
||||
** Macros to get and put bytes to a stream (Little Endian format).
|
||||
*/
|
||||
#define UINT32_TO_STREAM(p, u32) \
|
||||
{ \
|
||||
*(p)++ = (u8_t)(u32); \
|
||||
*(p)++ = (u8_t)((u32) >> 8); \
|
||||
*(p)++ = (u8_t)((u32) >> 16); \
|
||||
*(p)++ = (u8_t)((u32) >> 24); \
|
||||
}
|
||||
#define UINT24_TO_STREAM(p, u24) \
|
||||
{ \
|
||||
*(p)++ = (u8_t)(u24); \
|
||||
*(p)++ = (u8_t)((u24) >> 8); \
|
||||
*(p)++ = (u8_t)((u24) >> 16); \
|
||||
}
|
||||
#define UINT16_TO_STREAM(p, u16) \
|
||||
{ \
|
||||
*(p)++ = (u8_t)(u16); \
|
||||
*(p)++ = (u8_t)((u16) >> 8); \
|
||||
}
|
||||
#define UINT8_TO_STREAM(p, u8) \
|
||||
{ \
|
||||
*(p)++ = (u8_t)(u8); \
|
||||
}
|
||||
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define sys_le16_to_cpu(val) __bswap_16(val)
|
||||
#define sys_cpu_to_le16(val) __bswap_16(val)
|
||||
#define sys_be16_to_cpu(val) (val)
|
||||
#define sys_cpu_to_be16(val) (val)
|
||||
#define sys_le32_to_cpu(val) __bswap_32(val)
|
||||
#define sys_cpu_to_le32(val) __bswap_32(val)
|
||||
#define sys_le64_to_cpu(val) __bswap_64(val)
|
||||
#define sys_cpu_to_le64(val) __bswap_64(val)
|
||||
#define sys_be32_to_cpu(val) (val)
|
||||
#define sys_cpu_to_be32(val) (val)
|
||||
#define sys_be64_to_cpu(val) (val)
|
||||
#define sys_cpu_to_be64(val) (val)
|
||||
/********************************************************************************
|
||||
** Macros to get and put bytes to a stream (Big Endian format)
|
||||
*/
|
||||
#define UINT32_TO_STREAM(p, u32) \
|
||||
{ \
|
||||
*(p)++ = (u8_t)((u32) >> 24); \
|
||||
*(p)++ = (u8_t)((u32) >> 16); \
|
||||
*(p)++ = (u8_t)((u32) >> 8); \
|
||||
*(p)++ = (u8_t)(u32); \
|
||||
}
|
||||
#define UINT24_TO_STREAM(p, u24) \
|
||||
{ \
|
||||
*(p)++ = (u8_t)((u24) >> 16); \
|
||||
*(p)++ = (u8_t)((u24) >> 8); \
|
||||
*(p)++ = (u8_t)(u24); \
|
||||
}
|
||||
#define UINT16_TO_STREAM(p, u16) \
|
||||
{ \
|
||||
*(p)++ = (u8_t)((u16) >> 8); \
|
||||
*(p)++ = (u8_t)(u16); \
|
||||
}
|
||||
#define UINT8_TO_STREAM(p, u8) \
|
||||
{ \
|
||||
*(p)++ = (u8_t)(u8); \
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Put a 16-bit integer as big-endian to arbitrary location.
|
||||
*
|
||||
* Put a 16-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in big-endian format.
|
||||
*
|
||||
* @param val 16-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_be16(u16_t val, u8_t dst[2])
|
||||
{
|
||||
dst[0] = val >> 8;
|
||||
dst[1] = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 24-bit integer as big-endian to arbitrary location.
|
||||
*
|
||||
* Put a 24-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in big-endian format.
|
||||
*
|
||||
* @param val 24-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_be24(uint32_t val, uint8_t dst[3])
|
||||
{
|
||||
dst[0] = val >> 16;
|
||||
sys_put_be16(val, &dst[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 32-bit integer as big-endian to arbitrary location.
|
||||
*
|
||||
* Put a 32-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in big-endian format.
|
||||
*
|
||||
* @param val 32-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_be32(u32_t val, u8_t dst[4])
|
||||
{
|
||||
sys_put_be16(val >> 16, dst);
|
||||
sys_put_be16(val, &dst[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 16-bit integer as little-endian to arbitrary location.
|
||||
*
|
||||
* Put a 16-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in little-endian format.
|
||||
*
|
||||
* @param val 16-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_le16(u16_t val, u8_t dst[2])
|
||||
{
|
||||
dst[0] = val;
|
||||
dst[1] = val >> 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 24-bit integer as little-endian to arbitrary location.
|
||||
*
|
||||
* Put a 24-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in littel-endian format.
|
||||
*
|
||||
* @param val 24-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_le24(uint32_t val, uint8_t dst[3])
|
||||
{
|
||||
sys_put_le16(val, dst);
|
||||
dst[2] = val >> 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 32-bit integer as little-endian to arbitrary location.
|
||||
*
|
||||
* Put a 32-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in little-endian format.
|
||||
*
|
||||
* @param val 32-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_le32(u32_t val, u8_t dst[4])
|
||||
{
|
||||
sys_put_le16(val, dst);
|
||||
sys_put_le16(val >> 16, &dst[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a 64-bit integer as little-endian to arbitrary location.
|
||||
*
|
||||
* Put a 64-bit integer, originally in host endianness, to a
|
||||
* potentially unaligned memory location in little-endian format.
|
||||
*
|
||||
* @param val 64-bit integer in host endianness.
|
||||
* @param dst Destination memory address to store the result.
|
||||
*/
|
||||
static inline void sys_put_le64(u64_t val, u8_t dst[8])
|
||||
{
|
||||
sys_put_le32(val, dst);
|
||||
sys_put_le32(val >> 32, &dst[4]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 16-bit integer stored in big-endian format.
|
||||
*
|
||||
* Get a 16-bit integer, stored in big-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the big-endian 16-bit integer to get.
|
||||
*
|
||||
* @return 16-bit integer in host endianness.
|
||||
*/
|
||||
static inline u16_t sys_get_be16(const u8_t src[2])
|
||||
{
|
||||
return ((u16_t)src[0] << 8) | src[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 24-bit integer stored in big-endian format.
|
||||
*
|
||||
* Get a 24-bit integer, stored in big-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the big-endian 24-bit integer to get.
|
||||
*
|
||||
* @return 24-bit integer in host endianness.
|
||||
*/
|
||||
static inline uint32_t sys_get_be24(const uint8_t src[3])
|
||||
{
|
||||
return ((uint32_t)src[0] << 16) | sys_get_be16(&src[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 32-bit integer stored in big-endian format.
|
||||
*
|
||||
* Get a 32-bit integer, stored in big-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the big-endian 32-bit integer to get.
|
||||
*
|
||||
* @return 32-bit integer in host endianness.
|
||||
*/
|
||||
static inline u32_t sys_get_be32(const u8_t src[4])
|
||||
{
|
||||
return ((u32_t)sys_get_be16(&src[0]) << 16) | sys_get_be16(&src[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 16-bit integer stored in little-endian format.
|
||||
*
|
||||
* Get a 16-bit integer, stored in little-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the little-endian 16-bit integer to get.
|
||||
*
|
||||
* @return 16-bit integer in host endianness.
|
||||
*/
|
||||
static inline u16_t sys_get_le16(const u8_t src[2])
|
||||
{
|
||||
return ((u16_t)src[1] << 8) | src[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 24-bit integer stored in big-endian format.
|
||||
*
|
||||
* Get a 24-bit integer, stored in big-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the big-endian 24-bit integer to get.
|
||||
*
|
||||
* @return 24-bit integer in host endianness.
|
||||
*/
|
||||
static inline uint32_t sys_get_le24(const uint8_t src[3])
|
||||
{
|
||||
return ((uint32_t)src[2] << 16) | sys_get_le16(&src[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 32-bit integer stored in little-endian format.
|
||||
*
|
||||
* Get a 32-bit integer, stored in little-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the little-endian 32-bit integer to get.
|
||||
*
|
||||
* @return 32-bit integer in host endianness.
|
||||
*/
|
||||
static inline u32_t sys_get_le32(const u8_t src[4])
|
||||
{
|
||||
return ((u32_t)sys_get_le16(&src[2]) << 16) | sys_get_le16(&src[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a 64-bit integer stored in little-endian format.
|
||||
*
|
||||
* Get a 64-bit integer, stored in little-endian format in a potentially
|
||||
* unaligned memory location, and convert it to the host endianness.
|
||||
*
|
||||
* @param src Location of the little-endian 64-bit integer to get.
|
||||
*
|
||||
* @return 64-bit integer in host endianness.
|
||||
*/
|
||||
static inline u64_t sys_get_le64(const u8_t src[8])
|
||||
{
|
||||
return ((u64_t)sys_get_le32(&src[4]) << 32) | sys_get_le32(&src[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Swap one buffer content into another
|
||||
*
|
||||
* Copy the content of src buffer into dst buffer in reversed order,
|
||||
* i.e.: src[n] will be put in dst[end-n]
|
||||
* Where n is an index and 'end' the last index in both arrays.
|
||||
* The 2 memory pointers must be pointing to different areas, and have
|
||||
* a minimum size of given length.
|
||||
*
|
||||
* @param dst A valid pointer on a memory area where to copy the data in
|
||||
* @param src A valid pointer on a memory area where to copy the data from
|
||||
* @param length Size of both dst and src memory areas
|
||||
*/
|
||||
static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
|
||||
{
|
||||
__ASSERT(((src < dst && (src + length) <= dst) ||
|
||||
(src > dst && (dst + length) <= src)),
|
||||
"Source and destination buffers must not overlap");
|
||||
|
||||
src += length - 1;
|
||||
|
||||
for (; length > 0; length--) {
|
||||
*((u8_t *)dst++) = *((u8_t *)src--);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Swap buffer content
|
||||
*
|
||||
* In-place memory swap, where final content will be reversed.
|
||||
* I.e.: buf[n] will be put in buf[end-n]
|
||||
* Where n is an index and 'end' the last index of buf.
|
||||
*
|
||||
* @param buf A valid pointer on a memory area to swap
|
||||
* @param length Size of buf memory area
|
||||
*/
|
||||
static inline void sys_mem_swap(void *buf, size_t length)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < (length / 2); i++) {
|
||||
u8_t tmp = ((u8_t *)buf)[i];
|
||||
|
||||
((u8_t *)buf)[i] = ((u8_t *)buf)[length - 1 - i];
|
||||
((u8_t *)buf)[length - 1 - i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __BYTEORDER_H__ */
|
||||
@@ -0,0 +1,501 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2015 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Doubly-linked list implementation
|
||||
*
|
||||
* Doubly-linked list implementation using inline macros/functions.
|
||||
* This API is not thread safe, and thus if a list is used across threads,
|
||||
* calls to functions must be protected with synchronization primitives.
|
||||
*
|
||||
* The lists are expected to be initialized such that both the head and tail
|
||||
* pointers point to the list itself. Initializing the lists in such a fashion
|
||||
* simplifies the adding and removing of nodes to/from the list.
|
||||
*/
|
||||
|
||||
#ifndef _misc_dlist__h_
|
||||
#define _misc_dlist__h_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct _dnode {
|
||||
union {
|
||||
struct _dnode *head; /* ptr to head of list (sys_dlist_t) */
|
||||
struct _dnode *next; /* ptr to next node (sys_dnode_t) */
|
||||
};
|
||||
union {
|
||||
struct _dnode *tail; /* ptr to tail of list (sys_dlist_t) */
|
||||
struct _dnode *prev; /* ptr to previous node (sys_dnode_t) */
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct _dnode sys_dlist_t;
|
||||
typedef struct _dnode sys_dnode_t;
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to iterate on a list
|
||||
* Note: the loop is unsafe and thus __dn should not be removed
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_DLIST_FOR_EACH_NODE(l, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* This and other SYS_DLIST_*() macros are not thread safe.
|
||||
*
|
||||
* @param __dl A pointer on a sys_dlist_t to iterate on
|
||||
* @param __dn A sys_dnode_t pointer to peek each node of the list
|
||||
*/
|
||||
#define SYS_DLIST_FOR_EACH_NODE(__dl, __dn) \
|
||||
for (__dn = sys_dlist_peek_head(__dl); __dn; \
|
||||
__dn = sys_dlist_peek_next(__dl, __dn))
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to iterate on a list, from a node in the list
|
||||
* Note: the loop is unsafe and thus __dn should not be removed
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_DLIST_ITERATE_FROM_NODE(l, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* Like SYS_DLIST_FOR_EACH_NODE(), but __dn already contains a node in the list
|
||||
* where to start searching for the next entry from. If NULL, it starts from
|
||||
* the head.
|
||||
*
|
||||
* This and other SYS_DLIST_*() macros are not thread safe.
|
||||
*
|
||||
* @param __dl A pointer on a sys_dlist_t to iterate on
|
||||
* @param __dn A sys_dnode_t pointer to peek each node of the list;
|
||||
* it contains the starting node, or NULL to start from the head
|
||||
*/
|
||||
#define SYS_DLIST_ITERATE_FROM_NODE(__dl, __dn) \
|
||||
for (__dn = __dn ? sys_dlist_peek_next_no_check(__dl, __dn) : sys_dlist_peek_head(__dl); \
|
||||
__dn; \
|
||||
__dn = sys_dlist_peek_next(__dl, __dn))
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to safely iterate on a list
|
||||
* Note: __dn can be removed, it will not break the loop.
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_DLIST_FOR_EACH_NODE_SAFE(l, n, s) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* This and other SYS_DLIST_*() macros are not thread safe.
|
||||
*
|
||||
* @param __dl A pointer on a sys_dlist_t to iterate on
|
||||
* @param __dn A sys_dnode_t pointer to peek each node of the list
|
||||
* @param __dns A sys_dnode_t pointer for the loop to run safely
|
||||
*/
|
||||
#define SYS_DLIST_FOR_EACH_NODE_SAFE(__dl, __dn, __dns) \
|
||||
for (__dn = sys_dlist_peek_head(__dl), \
|
||||
__dns = sys_dlist_peek_next(__dl, __dn); \
|
||||
__dn; __dn = __dns, \
|
||||
__dns = sys_dlist_peek_next(__dl, __dn))
|
||||
|
||||
/*
|
||||
* @brief Provide the primitive to resolve the container of a list node
|
||||
* Note: it is safe to use with NULL pointer nodes
|
||||
*
|
||||
* @param __dn A pointer on a sys_dnode_t to get its container
|
||||
* @param __cn Container struct type pointer
|
||||
* @param __n The field name of sys_dnode_t within the container struct
|
||||
*/
|
||||
#define SYS_DLIST_CONTAINER(__dn, __cn, __n) \
|
||||
(__dn ? CONTAINER_OF(__dn, __typeof__(*__cn), __n) : NULL)
|
||||
/*
|
||||
* @brief Provide the primitive to peek container of the list head
|
||||
*
|
||||
* @param __dl A pointer on a sys_dlist_t to peek
|
||||
* @param __cn Container struct type pointer
|
||||
* @param __n The field name of sys_dnode_t within the container struct
|
||||
*/
|
||||
#define SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n) \
|
||||
SYS_DLIST_CONTAINER(sys_dlist_peek_head(__dl), __cn, __n)
|
||||
|
||||
/*
|
||||
* @brief Provide the primitive to peek the next container
|
||||
*
|
||||
* @param __dl A pointer on a sys_dlist_t to peek
|
||||
* @param __cn Container struct type pointer
|
||||
* @param __n The field name of sys_dnode_t within the container struct
|
||||
*/
|
||||
#define SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n) \
|
||||
((__cn) ? SYS_DLIST_CONTAINER(sys_dlist_peek_next(__dl, &(__cn->__n)), \
|
||||
__cn, __n) : \
|
||||
NULL)
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to iterate on a list under a container
|
||||
* Note: the loop is unsafe and thus __cn should not be detached
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_DLIST_FOR_EACH_CONTAINER(l, c, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* @param __dl A pointer on a sys_dlist_t to iterate on
|
||||
* @param __cn A pointer to peek each entry of the list
|
||||
* @param __n The field name of sys_dnode_t within the container struct
|
||||
*/
|
||||
#define SYS_DLIST_FOR_EACH_CONTAINER(__dl, __cn, __n) \
|
||||
for (__cn = SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n); __cn; \
|
||||
__cn = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n))
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to safely iterate on a list under a container
|
||||
* Note: __cn can be detached, it will not break the loop.
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_DLIST_FOR_EACH_CONTAINER_SAFE(l, c, cn, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* @param __dl A pointer on a sys_dlist_t to iterate on
|
||||
* @param __cn A pointer to peek each entry of the list
|
||||
* @param __cns A pointer for the loop to run safely
|
||||
* @param __n The field name of sys_dnode_t within the container struct
|
||||
*/
|
||||
#define SYS_DLIST_FOR_EACH_CONTAINER_SAFE(__dl, __cn, __cns, __n) \
|
||||
for (__cn = SYS_DLIST_PEEK_HEAD_CONTAINER(__dl, __cn, __n), \
|
||||
__cns = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n); \
|
||||
__cn; \
|
||||
__cn = __cns, \
|
||||
__cns = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n))
|
||||
|
||||
/**
|
||||
* @brief initialize list
|
||||
*
|
||||
* @param list the doubly-linked list
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
|
||||
static inline void sys_dlist_init(sys_dlist_t *list)
|
||||
{
|
||||
list->head = (sys_dnode_t *)list;
|
||||
list->tail = (sys_dnode_t *)list;
|
||||
}
|
||||
|
||||
#define SYS_DLIST_STATIC_INIT(ptr_to_list) \
|
||||
{ \
|
||||
{ (ptr_to_list) }, \
|
||||
{ \
|
||||
(ptr_to_list) \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check if a node is the list's head
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the node to check
|
||||
*
|
||||
* @return 1 if node is the head, 0 otherwise
|
||||
*/
|
||||
|
||||
static inline int sys_dlist_is_head(sys_dlist_t *list, sys_dnode_t *node)
|
||||
{
|
||||
return list->head == node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check if a node is the list's tail
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the node to check
|
||||
*
|
||||
* @return 1 if node is the tail, 0 otherwise
|
||||
*/
|
||||
|
||||
static inline int sys_dlist_is_tail(sys_dlist_t *list, sys_dnode_t *node)
|
||||
{
|
||||
return list->tail == node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check if the list is empty
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
*
|
||||
* @return 1 if empty, 0 otherwise
|
||||
*/
|
||||
|
||||
static inline int sys_dlist_is_empty(sys_dlist_t *list)
|
||||
{
|
||||
return list->head == list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check if more than one node present
|
||||
*
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
*
|
||||
* @return 1 if multiple nodes, 0 otherwise
|
||||
*/
|
||||
|
||||
static inline int sys_dlist_has_multiple_nodes(sys_dlist_t *list)
|
||||
{
|
||||
return list->head != list->tail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get a reference to the head item in the list
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
*
|
||||
* @return a pointer to the head element, NULL if list is empty
|
||||
*/
|
||||
|
||||
static inline sys_dnode_t *sys_dlist_peek_head(sys_dlist_t *list)
|
||||
{
|
||||
return sys_dlist_is_empty(list) ? NULL : list->head;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get a reference to the head item in the list
|
||||
*
|
||||
* The list must be known to be non-empty.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
*
|
||||
* @return a pointer to the head element
|
||||
*/
|
||||
|
||||
static inline sys_dnode_t *sys_dlist_peek_head_not_empty(sys_dlist_t *list)
|
||||
{
|
||||
return list->head;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get a reference to the next item in the list, node is not NULL
|
||||
*
|
||||
* Faster than sys_dlist_peek_next() if node is known not to be NULL.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the node from which to get the next element in the list
|
||||
*
|
||||
* @return a pointer to the next element from a node, NULL if node is the tail
|
||||
*/
|
||||
|
||||
static inline sys_dnode_t *sys_dlist_peek_next_no_check(sys_dlist_t *list,
|
||||
sys_dnode_t *node)
|
||||
{
|
||||
return (node == list->tail) ? NULL : node->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get a reference to the next item in the list
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the node from which to get the next element in the list
|
||||
*
|
||||
* @return a pointer to the next element from a node, NULL if node is the tail
|
||||
* or NULL (when node comes from reading the head of an empty list).
|
||||
*/
|
||||
|
||||
static inline sys_dnode_t *sys_dlist_peek_next(sys_dlist_t *list,
|
||||
sys_dnode_t *node)
|
||||
{
|
||||
return node ? sys_dlist_peek_next_no_check(list, node) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get a reference to the tail item in the list
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
*
|
||||
* @return a pointer to the tail element, NULL if list is empty
|
||||
*/
|
||||
|
||||
static inline sys_dnode_t *sys_dlist_peek_tail(sys_dlist_t *list)
|
||||
{
|
||||
return sys_dlist_is_empty(list) ? NULL : list->tail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief add node to tail of list
|
||||
*
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the element to append
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
|
||||
static inline void sys_dlist_append(sys_dlist_t *list, sys_dnode_t *node)
|
||||
{
|
||||
node->next = list;
|
||||
node->prev = list->tail;
|
||||
|
||||
list->tail->next = node;
|
||||
list->tail = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief add node to head of list
|
||||
*
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the element to append
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
|
||||
static inline void sys_dlist_prepend(sys_dlist_t *list, sys_dnode_t *node)
|
||||
{
|
||||
node->next = list->head;
|
||||
node->prev = list;
|
||||
|
||||
list->head->prev = node;
|
||||
list->head = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief insert node after a node
|
||||
*
|
||||
* Insert a node after a specified node in a list.
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param insert_point the insert point in the list: if NULL, insert at head
|
||||
* @param node the element to append
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
|
||||
static inline void sys_dlist_insert_after(sys_dlist_t *list,
|
||||
sys_dnode_t *insert_point, sys_dnode_t *node)
|
||||
{
|
||||
if (!insert_point) {
|
||||
sys_dlist_prepend(list, node);
|
||||
} else {
|
||||
node->next = insert_point->next;
|
||||
node->prev = insert_point;
|
||||
insert_point->next->prev = node;
|
||||
insert_point->next = node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief insert node before a node
|
||||
*
|
||||
* Insert a node before a specified node in a list.
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param insert_point the insert point in the list: if NULL, insert at tail
|
||||
* @param node the element to insert
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
|
||||
static inline void sys_dlist_insert_before(sys_dlist_t *list,
|
||||
sys_dnode_t *insert_point, sys_dnode_t *node)
|
||||
{
|
||||
if (!insert_point) {
|
||||
sys_dlist_append(list, node);
|
||||
} else {
|
||||
node->prev = insert_point->prev;
|
||||
node->next = insert_point;
|
||||
insert_point->prev->next = node;
|
||||
insert_point->prev = node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief insert node at position
|
||||
*
|
||||
* Insert a node in a location depending on a external condition. The cond()
|
||||
* function checks if the node is to be inserted _before_ the current node
|
||||
* against which it is checked.
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
* @param node the element to insert
|
||||
* @param cond a function that determines if the current node is the correct
|
||||
* insert point
|
||||
* @param data parameter to cond()
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
|
||||
static inline void sys_dlist_insert_at(sys_dlist_t *list, sys_dnode_t *node,
|
||||
int (*cond)(sys_dnode_t *, void *), void *data)
|
||||
{
|
||||
if (sys_dlist_is_empty(list)) {
|
||||
sys_dlist_append(list, node);
|
||||
} else {
|
||||
sys_dnode_t *pos = sys_dlist_peek_head(list);
|
||||
|
||||
while (pos && !cond(pos, data)) {
|
||||
pos = sys_dlist_peek_next(list, pos);
|
||||
}
|
||||
sys_dlist_insert_before(list, pos, node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief remove a specific node from a list
|
||||
*
|
||||
* The list is implicit from the node. The node must be part of a list.
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param node the node to remove
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
|
||||
static inline void sys_dlist_remove(sys_dnode_t *node)
|
||||
{
|
||||
node->prev->next = node->next;
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the first node in a list
|
||||
*
|
||||
* This and other sys_dlist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list the doubly-linked list to operate on
|
||||
*
|
||||
* @return the first node in the list, NULL if list is empty
|
||||
*/
|
||||
|
||||
static inline sys_dnode_t *sys_dlist_get(sys_dlist_t *list)
|
||||
{
|
||||
sys_dnode_t *node;
|
||||
|
||||
if (sys_dlist_is_empty(list)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = list->head;
|
||||
sys_dlist_remove(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _misc_dlist__h_ */
|
||||
@@ -0,0 +1,28 @@
|
||||
/* printk.h - low-level debug output */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2012, 2014 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _PRINTK_H_
|
||||
#define _PRINTK_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <zephyr.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define snprintk snprintf
|
||||
#define printk printf
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Single-linked list implementation
|
||||
*
|
||||
* Single-linked list implementation using inline macros/functions.
|
||||
* This API is not thread safe, and thus if a list is used across threads,
|
||||
* calls to functions must be protected with synchronization primitives.
|
||||
*/
|
||||
|
||||
#ifndef __SLIST_H__
|
||||
#define __SLIST_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct _snode {
|
||||
struct _snode *next;
|
||||
};
|
||||
|
||||
typedef struct _snode sys_snode_t;
|
||||
|
||||
struct _slist {
|
||||
sys_snode_t *head;
|
||||
sys_snode_t *tail;
|
||||
};
|
||||
|
||||
typedef struct _slist sys_slist_t;
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to iterate on a list
|
||||
* Note: the loop is unsafe and thus __sn should not be removed
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_SLIST_FOR_EACH_NODE(l, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* This and other SYS_SLIST_*() macros are not thread safe.
|
||||
*
|
||||
* @param __sl A pointer on a sys_slist_t to iterate on
|
||||
* @param __sn A sys_snode_t pointer to peek each node of the list
|
||||
*/
|
||||
#define SYS_SLIST_FOR_EACH_NODE(__sl, __sn) \
|
||||
for (__sn = sys_slist_peek_head(__sl); __sn; \
|
||||
__sn = sys_slist_peek_next(__sn))
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to iterate on a list, from a node in the list
|
||||
* Note: the loop is unsafe and thus __sn should not be removed
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_SLIST_ITERATE_FROM_NODE(l, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* Like SYS_SLIST_FOR_EACH_NODE(), but __dn already contains a node in the list
|
||||
* where to start searching for the next entry from. If NULL, it starts from
|
||||
* the head.
|
||||
*
|
||||
* This and other SYS_SLIST_*() macros are not thread safe.
|
||||
*
|
||||
* @param __sl A pointer on a sys_slist_t to iterate on
|
||||
* @param __sn A sys_snode_t pointer to peek each node of the list
|
||||
* it contains the starting node, or NULL to start from the head
|
||||
*/
|
||||
#define SYS_SLIST_ITERATE_FROM_NODE(__sl, __sn) \
|
||||
for (__sn = __sn ? sys_slist_peek_next_no_check(__sn) : sys_slist_peek_head(__sl); \
|
||||
__sn; \
|
||||
__sn = sys_slist_peek_next(__sn))
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to safely iterate on a list
|
||||
* Note: __sn can be removed, it will not break the loop.
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_SLIST_FOR_EACH_NODE_SAFE(l, n, s) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* This and other SYS_SLIST_*() macros are not thread safe.
|
||||
*
|
||||
* @param __sl A pointer on a sys_slist_t to iterate on
|
||||
* @param __sn A sys_snode_t pointer to peek each node of the list
|
||||
* @param __sns A sys_snode_t pointer for the loop to run safely
|
||||
*/
|
||||
#define SYS_SLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \
|
||||
for (__sn = sys_slist_peek_head(__sl), \
|
||||
__sns = sys_slist_peek_next(__sn); \
|
||||
__sn; __sn = __sns, \
|
||||
__sns = sys_slist_peek_next(__sn))
|
||||
|
||||
/*
|
||||
* @brief Provide the primitive to resolve the container of a list node
|
||||
* Note: it is safe to use with NULL pointer nodes
|
||||
*
|
||||
* @param __ln A pointer on a sys_node_t to get its container
|
||||
* @param __cn Container struct type pointer
|
||||
* @param __n The field name of sys_node_t within the container struct
|
||||
*/
|
||||
#define SYS_SLIST_CONTAINER(__ln, __cn, __n) \
|
||||
((__ln) ? CONTAINER_OF((__ln), __typeof__(*(__cn)), __n) : NULL)
|
||||
/*
|
||||
* @brief Provide the primitive to peek container of the list head
|
||||
*
|
||||
* @param __sl A pointer on a sys_slist_t to peek
|
||||
* @param __cn Container struct type pointer
|
||||
* @param __n The field name of sys_node_t within the container struct
|
||||
*/
|
||||
#define SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n) \
|
||||
SYS_SLIST_CONTAINER(sys_slist_peek_head(__sl), __cn, __n)
|
||||
|
||||
/*
|
||||
* @brief Provide the primitive to peek container of the list tail
|
||||
*
|
||||
* @param __sl A pointer on a sys_slist_t to peek
|
||||
* @param __cn Container struct type pointer
|
||||
* @param __n The field name of sys_node_t within the container struct
|
||||
*/
|
||||
#define SYS_SLIST_PEEK_TAIL_CONTAINER(__sl, __cn, __n) \
|
||||
SYS_SLIST_CONTAINER(sys_slist_peek_tail(__sl), __cn, __n)
|
||||
|
||||
/*
|
||||
* @brief Provide the primitive to peek the next container
|
||||
*
|
||||
* @param __cn Container struct type pointer
|
||||
* @param __n The field name of sys_node_t within the container struct
|
||||
*/
|
||||
|
||||
#define SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n) \
|
||||
((__cn) ? SYS_SLIST_CONTAINER(sys_slist_peek_next(&((__cn)->__n)), \
|
||||
__cn, __n) : \
|
||||
NULL)
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to iterate on a list under a container
|
||||
* Note: the loop is unsafe and thus __cn should not be detached
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_SLIST_FOR_EACH_CONTAINER(l, c, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* @param __sl A pointer on a sys_slist_t to iterate on
|
||||
* @param __cn A pointer to peek each entry of the list
|
||||
* @param __n The field name of sys_node_t within the container struct
|
||||
*/
|
||||
#define SYS_SLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \
|
||||
for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n); __cn; \
|
||||
__cn = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n))
|
||||
|
||||
/**
|
||||
* @brief Provide the primitive to safely iterate on a list under a container
|
||||
* Note: __cn can be detached, it will not break the loop.
|
||||
*
|
||||
* User _MUST_ add the loop statement curly braces enclosing its own code:
|
||||
*
|
||||
* SYS_SLIST_FOR_EACH_NODE_SAFE(l, c, cn, n) {
|
||||
* <user code>
|
||||
* }
|
||||
*
|
||||
* @param __sl A pointer on a sys_slist_t to iterate on
|
||||
* @param __cn A pointer to peek each entry of the list
|
||||
* @param __cns A pointer for the loop to run safely
|
||||
* @param __n The field name of sys_node_t within the container struct
|
||||
*/
|
||||
#define SYS_SLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n) \
|
||||
for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n), \
|
||||
__cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n); \
|
||||
__cn; \
|
||||
__cn = __cns, __cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n))
|
||||
|
||||
/**
|
||||
* @brief Initialize a list
|
||||
*
|
||||
* @param list A pointer on the list to initialize
|
||||
*/
|
||||
static inline void sys_slist_init(sys_slist_t *list)
|
||||
{
|
||||
list->head = NULL;
|
||||
list->tail = NULL;
|
||||
}
|
||||
|
||||
#define SYS_SLIST_STATIC_INIT(ptr_to_list) \
|
||||
{ \
|
||||
NULL, NULL \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test if the given list is empty
|
||||
*
|
||||
* @param list A pointer on the list to test
|
||||
*
|
||||
* @return a boolean, true if it's empty, false otherwise
|
||||
*/
|
||||
static inline bool sys_slist_is_empty(sys_slist_t *list)
|
||||
{
|
||||
return (!list->head);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Peek the first node from the list
|
||||
*
|
||||
* @param list A point on the list to peek the first node from
|
||||
*
|
||||
* @return A pointer on the first node of the list (or NULL if none)
|
||||
*/
|
||||
static inline sys_snode_t *sys_slist_peek_head(sys_slist_t *list)
|
||||
{
|
||||
return list->head;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Peek the last node from the list
|
||||
*
|
||||
* @param list A point on the list to peek the last node from
|
||||
*
|
||||
* @return A pointer on the last node of the list (or NULL if none)
|
||||
*/
|
||||
static inline sys_snode_t *sys_slist_peek_tail(sys_slist_t *list)
|
||||
{
|
||||
return list->tail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Peek the next node from current node, node is not NULL
|
||||
*
|
||||
* Faster then sys_slist_peek_next() if node is known not to be NULL.
|
||||
*
|
||||
* @param node A pointer on the node where to peek the next node
|
||||
*
|
||||
* @return a pointer on the next node (or NULL if none)
|
||||
*/
|
||||
static inline sys_snode_t *sys_slist_peek_next_no_check(sys_snode_t *node)
|
||||
{
|
||||
return node->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Peek the next node from current node
|
||||
*
|
||||
* @param node A pointer on the node where to peek the next node
|
||||
*
|
||||
* @return a pointer on the next node (or NULL if none)
|
||||
*/
|
||||
static inline sys_snode_t *sys_slist_peek_next(sys_snode_t *node)
|
||||
{
|
||||
return node ? sys_slist_peek_next_no_check(node) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prepend a node to the given list
|
||||
*
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
* @param node A pointer on the node to prepend
|
||||
*/
|
||||
static inline void sys_slist_prepend(sys_slist_t *list,
|
||||
sys_snode_t *node)
|
||||
{
|
||||
node->next = list->head;
|
||||
list->head = node;
|
||||
|
||||
if (!list->tail) {
|
||||
list->tail = list->head;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Append a node to the given list
|
||||
*
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
* @param node A pointer on the node to append
|
||||
*/
|
||||
static inline void sys_slist_append(sys_slist_t *list,
|
||||
sys_snode_t *node)
|
||||
{
|
||||
node->next = NULL;
|
||||
|
||||
if (!list->tail) {
|
||||
list->tail = node;
|
||||
list->head = node;
|
||||
} else {
|
||||
list->tail->next = node;
|
||||
list->tail = node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Append a list to the given list
|
||||
*
|
||||
* Append a singly-linked, NULL-terminated list consisting of nodes containing
|
||||
* the pointer to the next node as the first element of a node, to @a list.
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
* @param head A pointer to the first element of the list to append
|
||||
* @param tail A pointer to the last element of the list to append
|
||||
*/
|
||||
static inline void sys_slist_append_list(sys_slist_t *list,
|
||||
void *head, void *tail)
|
||||
{
|
||||
if (!list->tail) {
|
||||
list->head = (sys_snode_t *)head;
|
||||
list->tail = (sys_snode_t *)tail;
|
||||
} else {
|
||||
list->tail->next = (sys_snode_t *)head;
|
||||
list->tail = (sys_snode_t *)tail;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief merge two slists, appending the second one to the first
|
||||
*
|
||||
* When the operation is completed, the appending list is empty.
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
* @param list_to_append A pointer to the list to append.
|
||||
*/
|
||||
static inline void sys_slist_merge_slist(sys_slist_t *list,
|
||||
sys_slist_t *list_to_append)
|
||||
{
|
||||
sys_slist_append_list(list, list_to_append->head,
|
||||
list_to_append->tail);
|
||||
sys_slist_init(list_to_append);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insert a node to the given list
|
||||
*
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
* @param prev A pointer on the previous node
|
||||
* @param node A pointer on the node to insert
|
||||
*/
|
||||
static inline void sys_slist_insert(sys_slist_t *list,
|
||||
sys_snode_t *prev,
|
||||
sys_snode_t *node)
|
||||
{
|
||||
if (!prev) {
|
||||
sys_slist_prepend(list, node);
|
||||
} else if (!prev->next) {
|
||||
sys_slist_append(list, node);
|
||||
} else {
|
||||
node->next = prev->next;
|
||||
prev->next = node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetch and remove the first node of the given list
|
||||
*
|
||||
* List must be known to be non-empty.
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
*
|
||||
* @return A pointer to the first node of the list
|
||||
*/
|
||||
static inline sys_snode_t *sys_slist_get_not_empty(sys_slist_t *list)
|
||||
{
|
||||
sys_snode_t *node = list->head;
|
||||
|
||||
list->head = node->next;
|
||||
if (list->tail == node) {
|
||||
list->tail = list->head;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetch and remove the first node of the given list
|
||||
*
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
*
|
||||
* @return A pointer to the first node of the list (or NULL if empty)
|
||||
*/
|
||||
static inline sys_snode_t *sys_slist_get(sys_slist_t *list)
|
||||
{
|
||||
return sys_slist_is_empty(list) ? NULL : sys_slist_get_not_empty(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove a node
|
||||
*
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
* @param prev_node A pointer on the previous node
|
||||
* (can be NULL, which means the node is the list's head)
|
||||
* @param node A pointer on the node to remove
|
||||
*/
|
||||
static inline void sys_slist_remove(sys_slist_t *list,
|
||||
sys_snode_t *prev_node,
|
||||
sys_snode_t *node)
|
||||
{
|
||||
if (!prev_node) {
|
||||
list->head = node->next;
|
||||
|
||||
/* Was node also the tail? */
|
||||
if (list->tail == node) {
|
||||
list->tail = list->head;
|
||||
}
|
||||
} else {
|
||||
prev_node->next = node->next;
|
||||
|
||||
/* Was node the tail? */
|
||||
if (list->tail == node) {
|
||||
list->tail = prev_node;
|
||||
}
|
||||
}
|
||||
|
||||
node->next = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find and remove a node from a list
|
||||
*
|
||||
* This and other sys_slist_*() functions are not thread safe.
|
||||
*
|
||||
* @param list A pointer on the list to affect
|
||||
* @param node A pointer on the node to remove from the list
|
||||
*
|
||||
* @return true if node was removed
|
||||
*/
|
||||
static inline bool sys_slist_find_and_remove(sys_slist_t *list,
|
||||
sys_snode_t *node)
|
||||
{
|
||||
sys_snode_t *prev = NULL;
|
||||
sys_snode_t *test;
|
||||
|
||||
SYS_SLIST_FOR_EACH_NODE(list, test)
|
||||
{
|
||||
if (test == node) {
|
||||
sys_slist_remove(list, prev, node);
|
||||
return true;
|
||||
}
|
||||
|
||||
prev = test;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SLIST_H__ */
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @file stack.h
|
||||
* Stack usage analysis helpers
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _MISC_STACK_H_
|
||||
#define _MISC_STACK_H_
|
||||
|
||||
#include <misc/printk.h>
|
||||
|
||||
#if defined(CONFIG_INIT_STACKS)
|
||||
static inline size_t stack_unused_space_get(const char *stack, size_t size)
|
||||
{
|
||||
size_t unused = 0;
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_STACK_SENTINEL
|
||||
/* First 4 bytes of the stack buffer reserved for the sentinel
|
||||
* value, it won't be 0xAAAAAAAA for thread stacks.
|
||||
*/
|
||||
stack += 4;
|
||||
#endif
|
||||
|
||||
/* TODO Currently all supported platforms have stack growth down and
|
||||
* there is no Kconfig option to configure it so this always build
|
||||
* "else" branch. When support for platform with stack direction up
|
||||
* (or configurable direction) is added this check should be confirmed
|
||||
* that correct Kconfig option is used.
|
||||
*/
|
||||
#if defined(STACK_GROWS_UP)
|
||||
for (i = size - 1; i >= 0; i--) {
|
||||
if ((unsigned char)stack[i] == 0xaa) {
|
||||
unused++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((unsigned char)stack[i] == 0xaa) {
|
||||
unused++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return unused;
|
||||
}
|
||||
#else
|
||||
static inline size_t stack_unused_space_get(const char *stack, size_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_INIT_STACKS) && defined(CONFIG_PRINTK)
|
||||
static inline void stack_analyze(const char *name, const char *stack,
|
||||
unsigned int size)
|
||||
{
|
||||
unsigned int pcnt, unused = 0;
|
||||
|
||||
unused = stack_unused_space_get(stack, size);
|
||||
|
||||
/* Calculate the real size reserved for the stack */
|
||||
pcnt = ((size - unused) * 100) / size;
|
||||
|
||||
printk("%s (real size %u):\tunused %u\tusage %u / %u (%u %%)\n", name,
|
||||
size, unused, size - unused, size, pcnt);
|
||||
}
|
||||
#else
|
||||
static inline void stack_analyze(const char *name, const char *stack,
|
||||
unsigned int size)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#define STACK_ANALYZE(name, sym) \
|
||||
stack_analyze(name, K_THREAD_STACK_BUFFER(sym), \
|
||||
K_THREAD_STACK_SIZEOF(sym))
|
||||
|
||||
#endif /* _MISC_STACK_H_ */
|
||||
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2014, Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Misc utilities
|
||||
*
|
||||
* Misc utilities usable by the kernel and application code.
|
||||
*/
|
||||
|
||||
#ifndef _UTIL__H_
|
||||
#define _UTIL__H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _ASMLANGUAGE
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#if defined(BFLB_BLE)
|
||||
#include <stddef.h>
|
||||
#include "utils_string.h"
|
||||
#endif
|
||||
|
||||
/* Helper to pass a int as a pointer or vice-versa.
|
||||
* Those are available for 32 bits architectures:
|
||||
*/
|
||||
#define POINTER_TO_UINT(x) ((u32_t)(x))
|
||||
#define UINT_TO_POINTER(x) ((void *)(x))
|
||||
#define POINTER_TO_INT(x) ((s32_t)(x))
|
||||
#define INT_TO_POINTER(x) ((void *)(x))
|
||||
|
||||
/* Evaluates to 0 if cond is true-ish; compile error otherwise */
|
||||
#define ZERO_OR_COMPILE_ERROR(cond) ((int)sizeof(char[1 - 2 * !(cond)]) - 1)
|
||||
|
||||
/* Evaluates to 0 if array is an array; compile error if not array (e.g.
|
||||
* pointer)
|
||||
*/
|
||||
#define IS_ARRAY(array) \
|
||||
ZERO_OR_COMPILE_ERROR( \
|
||||
!__builtin_types_compatible_p(__typeof__(array), \
|
||||
__typeof__(&(array)[0])))
|
||||
|
||||
/* Evaluates to number of elements in an array; compile error if not
|
||||
* an array (e.g. pointer)
|
||||
*/
|
||||
#define ARRAY_SIZE(array) \
|
||||
((unsigned long)(IS_ARRAY(array) + \
|
||||
(sizeof(array) / sizeof((array)[0]))))
|
||||
|
||||
/* Evaluates to 1 if ptr is part of array, 0 otherwise; compile error if
|
||||
* "array" argument is not an array (e.g. "ptr" and "array" mixed up)
|
||||
*/
|
||||
#define PART_OF_ARRAY(array, ptr) \
|
||||
((ptr) && ((ptr) >= &array[0] && (ptr) < &array[ARRAY_SIZE(array)]))
|
||||
|
||||
#define CONTAINER_OF(ptr, type, field) \
|
||||
((type *)(((char *)(ptr)) - offsetof(type, field)))
|
||||
|
||||
/* round "x" up/down to next multiple of "align" (which must be a power of 2) */
|
||||
#define ROUND_UP(x, align) \
|
||||
(((unsigned long)(x) + ((unsigned long)align - 1)) & \
|
||||
~((unsigned long)align - 1))
|
||||
#define ROUND_DOWN(x, align) ((unsigned long)(x) & ~((unsigned long)align - 1))
|
||||
|
||||
#define ceiling_fraction(numerator, divider) \
|
||||
(((numerator) + ((divider)-1)) / (divider))
|
||||
|
||||
#ifdef INLINED
|
||||
#define INLINE inline
|
||||
#else
|
||||
#define INLINE
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
void get_bytearray_from_string(char **params, uint8_t *result, int array_size);
|
||||
void get_uint8_from_string(char **params, uint8_t *result);
|
||||
void get_uint16_from_string(char **params, uint16_t *result);
|
||||
void get_uint32_from_string(char **params, uint32_t *result);
|
||||
void reverse_bytearray(uint8_t *src, uint8_t *result, int array_size);
|
||||
void reverse_bytearray(uint8_t *src, uint8_t *result, int array_size);
|
||||
unsigned int find_lsb_set(uint32_t data);
|
||||
|
||||
static inline int is_power_of_two(unsigned int x)
|
||||
{
|
||||
return (x != 0) && !(x & (x - 1));
|
||||
}
|
||||
|
||||
static inline s64_t arithmetic_shift_right(s64_t value, u8_t shift)
|
||||
{
|
||||
s64_t sign_ext;
|
||||
|
||||
if (shift == 0) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/* extract sign bit */
|
||||
sign_ext = (value >> 63) & 1;
|
||||
|
||||
/* make all bits of sign_ext be the same as the value's sign bit */
|
||||
sign_ext = -sign_ext;
|
||||
|
||||
/* shift value and fill opened bit positions with sign bit */
|
||||
return (value >> shift) | (sign_ext << (64 - shift));
|
||||
}
|
||||
|
||||
#endif /* !_ASMLANGUAGE */
|
||||
|
||||
/* KB, MB, GB */
|
||||
#define KB(x) ((x) << 10)
|
||||
#define MB(x) (KB(x) << 10)
|
||||
#define GB(x) (MB(x) << 10)
|
||||
|
||||
/* KHZ, MHZ */
|
||||
#define KHZ(x) ((x)*1000)
|
||||
#define MHZ(x) (KHZ(x) * 1000)
|
||||
|
||||
#define BIT_MASK(n) (BIT(n) - 1)
|
||||
|
||||
/**
|
||||
* @brief Check for macro definition in compiler-visible expressions
|
||||
*
|
||||
* This trick was pioneered in Linux as the config_enabled() macro.
|
||||
* The madness has the effect of taking a macro value that may be
|
||||
* defined to "1" (e.g. CONFIG_MYFEATURE), or may not be defined at
|
||||
* all and turning it into a literal expression that can be used at
|
||||
* "runtime". That is, it works similarly to
|
||||
* "defined(CONFIG_MYFEATURE)" does except that it is an expansion
|
||||
* that can exist in a standard expression and be seen by the compiler
|
||||
* and optimizer. Thus much ifdef usage can be replaced with cleaner
|
||||
* expressions like:
|
||||
*
|
||||
* if (IS_ENABLED(CONFIG_MYFEATURE))
|
||||
* myfeature_enable();
|
||||
*
|
||||
* INTERNAL
|
||||
* First pass just to expand any existing macros, we need the macro
|
||||
* value to be e.g. a literal "1" at expansion time in the next macro,
|
||||
* not "(1)", etc... Standard recursive expansion does not work.
|
||||
*/
|
||||
#define IS_ENABLED(config_macro) _IS_ENABLED1(config_macro)
|
||||
|
||||
/* Now stick on a "_XXXX" prefix, it will now be "_XXXX1" if config_macro
|
||||
* is "1", or just "_XXXX" if it's undefined.
|
||||
* ENABLED: _IS_ENABLED2(_XXXX1)
|
||||
* DISABLED _IS_ENABLED2(_XXXX)
|
||||
*/
|
||||
#define _IS_ENABLED1(config_macro) _IS_ENABLED2(_XXXX##config_macro)
|
||||
|
||||
/* Here's the core trick, we map "_XXXX1" to "_YYYY," (i.e. a string
|
||||
* with a trailing comma), so it has the effect of making this a
|
||||
* two-argument tuple to the preprocessor only in the case where the
|
||||
* value is defined to "1"
|
||||
* ENABLED: _YYYY, <--- note comma!
|
||||
* DISABLED: _XXXX
|
||||
*/
|
||||
#define _XXXX1 _YYYY,
|
||||
|
||||
/* Then we append an extra argument to fool the gcc preprocessor into
|
||||
* accepting it as a varargs macro.
|
||||
* arg1 arg2 arg3
|
||||
* ENABLED: _IS_ENABLED3(_YYYY, 1, 0)
|
||||
* DISABLED _IS_ENABLED3(_XXXX 1, 0)
|
||||
*/
|
||||
#define _IS_ENABLED2(one_or_two_args) _IS_ENABLED3(one_or_two_args 1, 0)
|
||||
|
||||
/* And our second argument is thus now cooked to be 1 in the case
|
||||
* where the value is defined to 1, and 0 if not:
|
||||
*/
|
||||
#define _IS_ENABLED3(ignore_this, val, ...) val
|
||||
|
||||
/**
|
||||
* Macros for doing code-generation with the preprocessor.
|
||||
*
|
||||
* Generally it is better to generate code with the preprocessor than
|
||||
* to copy-paste code or to generate code with the build system /
|
||||
* python script's etc.
|
||||
*
|
||||
* http://stackoverflow.com/a/12540675
|
||||
*/
|
||||
#define UTIL_EMPTY(...)
|
||||
#define UTIL_DEFER(...) __VA_ARGS__ UTIL_EMPTY()
|
||||
#define UTIL_OBSTRUCT(...) __VA_ARGS__ UTIL_DEFER(UTIL_EMPTY)()
|
||||
#define UTIL_EXPAND(...) __VA_ARGS__
|
||||
|
||||
#define UTIL_EVAL(...) UTIL_EVAL1(UTIL_EVAL1(UTIL_EVAL1(__VA_ARGS__)))
|
||||
#define UTIL_EVAL1(...) UTIL_EVAL2(UTIL_EVAL2(UTIL_EVAL2(__VA_ARGS__)))
|
||||
#define UTIL_EVAL2(...) UTIL_EVAL3(UTIL_EVAL3(UTIL_EVAL3(__VA_ARGS__)))
|
||||
#define UTIL_EVAL3(...) UTIL_EVAL4(UTIL_EVAL4(UTIL_EVAL4(__VA_ARGS__)))
|
||||
#define UTIL_EVAL4(...) UTIL_EVAL5(UTIL_EVAL5(UTIL_EVAL5(__VA_ARGS__)))
|
||||
#define UTIL_EVAL5(...) __VA_ARGS__
|
||||
|
||||
#define UTIL_CAT(a, ...) UTIL_PRIMITIVE_CAT(a, __VA_ARGS__)
|
||||
#define UTIL_PRIMITIVE_CAT(a, ...) a##__VA_ARGS__
|
||||
|
||||
#define UTIL_INC(x) UTIL_PRIMITIVE_CAT(UTIL_INC_, x)
|
||||
#define UTIL_INC_0 1
|
||||
#define UTIL_INC_1 2
|
||||
#define UTIL_INC_2 3
|
||||
#define UTIL_INC_3 4
|
||||
#define UTIL_INC_4 5
|
||||
#define UTIL_INC_5 6
|
||||
#define UTIL_INC_6 7
|
||||
#define UTIL_INC_7 8
|
||||
#define UTIL_INC_8 9
|
||||
#define UTIL_INC_9 10
|
||||
#define UTIL_INC_10 11
|
||||
#define UTIL_INC_11 12
|
||||
#define UTIL_INC_12 13
|
||||
#define UTIL_INC_13 14
|
||||
#define UTIL_INC_14 15
|
||||
#define UTIL_INC_15 16
|
||||
#define UTIL_INC_16 17
|
||||
#define UTIL_INC_17 18
|
||||
#define UTIL_INC_18 19
|
||||
#define UTIL_INC_19 19
|
||||
|
||||
#define UTIL_DEC(x) UTIL_PRIMITIVE_CAT(UTIL_DEC_, x)
|
||||
#define UTIL_DEC_0 0
|
||||
#define UTIL_DEC_1 0
|
||||
#define UTIL_DEC_2 1
|
||||
#define UTIL_DEC_3 2
|
||||
#define UTIL_DEC_4 3
|
||||
#define UTIL_DEC_5 4
|
||||
#define UTIL_DEC_6 5
|
||||
#define UTIL_DEC_7 6
|
||||
#define UTIL_DEC_8 7
|
||||
#define UTIL_DEC_9 8
|
||||
#define UTIL_DEC_10 9
|
||||
#define UTIL_DEC_11 10
|
||||
#define UTIL_DEC_12 11
|
||||
#define UTIL_DEC_13 12
|
||||
#define UTIL_DEC_14 13
|
||||
#define UTIL_DEC_15 14
|
||||
#define UTIL_DEC_16 15
|
||||
#define UTIL_DEC_17 16
|
||||
#define UTIL_DEC_18 17
|
||||
#define UTIL_DEC_19 18
|
||||
|
||||
#define UTIL_CHECK_N(x, n, ...) n
|
||||
#define UTIL_CHECK(...) UTIL_CHECK_N(__VA_ARGS__, 0, )
|
||||
|
||||
#define UTIL_NOT(x) UTIL_CHECK(UTIL_PRIMITIVE_CAT(UTIL_NOT_, x))
|
||||
#define UTIL_NOT_0 ~, 1,
|
||||
|
||||
#define UTIL_COMPL(b) UTIL_PRIMITIVE_CAT(UTIL_COMPL_, b)
|
||||
#define UTIL_COMPL_0 1
|
||||
#define UTIL_COMPL_1 0
|
||||
|
||||
#define UTIL_BOOL(x) UTIL_COMPL(UTIL_NOT(x))
|
||||
|
||||
#define UTIL_IIF(c) UTIL_PRIMITIVE_CAT(UTIL_IIF_, c)
|
||||
#define UTIL_IIF_0(t, ...) __VA_ARGS__
|
||||
#define UTIL_IIF_1(t, ...) t
|
||||
|
||||
#define UTIL_IF(c) UTIL_IIF(UTIL_BOOL(c))
|
||||
|
||||
#define UTIL_EAT(...)
|
||||
#define UTIL_EXPAND(...) __VA_ARGS__
|
||||
#define UTIL_WHEN(c) UTIL_IF(c) \
|
||||
(UTIL_EXPAND, UTIL_EAT)
|
||||
|
||||
#define UTIL_REPEAT(count, macro, ...) \
|
||||
UTIL_WHEN(count) \
|
||||
( \
|
||||
UTIL_OBSTRUCT(UTIL_REPEAT_INDIRECT)()( \
|
||||
UTIL_DEC(count), macro, __VA_ARGS__) \
|
||||
UTIL_OBSTRUCT(macro)( \
|
||||
UTIL_DEC(count), __VA_ARGS__))
|
||||
#define UTIL_REPEAT_INDIRECT() UTIL_REPEAT
|
||||
|
||||
/**
|
||||
* Generates a sequence of code.
|
||||
* Useful for generating code like;
|
||||
*
|
||||
* NRF_PWM0, NRF_PWM1, NRF_PWM2,
|
||||
*
|
||||
* @arg LEN: The length of the sequence. Must be defined and less than
|
||||
* 20.
|
||||
*
|
||||
* @arg F(i, F_ARG): A macro function that accepts two arguments.
|
||||
* F is called repeatedly, the first argument
|
||||
* is the index in the sequence, and the second argument is the third
|
||||
* argument given to UTIL_LISTIFY.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* \#define FOO(i, _) NRF_PWM ## i ,
|
||||
* { UTIL_LISTIFY(PWM_COUNT, FOO) }
|
||||
* // The above two lines will generate the below:
|
||||
* { NRF_PWM0 , NRF_PWM1 , }
|
||||
*
|
||||
* @note Calling UTIL_LISTIFY with undefined arguments has undefined
|
||||
* behaviour.
|
||||
*/
|
||||
#define UTIL_LISTIFY(LEN, F, F_ARG) UTIL_EVAL(UTIL_REPEAT(LEN, F, F_ARG))
|
||||
|
||||
#if defined(BFLB_BLE)
|
||||
/**
|
||||
* @brief Convert a single character into a hexadecimal nibble.
|
||||
*
|
||||
* @param[in] c The character to convert
|
||||
* @param x The address of storage for the converted number.
|
||||
*
|
||||
* @return Zero on success or (negative) error code otherwise.
|
||||
*/
|
||||
int char2hex(char c, u8_t *x);
|
||||
|
||||
/**
|
||||
* @brief Convert a single hexadecimal nibble into a character.
|
||||
*
|
||||
* @param[in] c The number to convert
|
||||
* @param x The address of storage for the converted character.
|
||||
*
|
||||
* @return Zero on success or (negative) error code otherwise.
|
||||
*/
|
||||
int hex2char(u8_t x, char *c);
|
||||
|
||||
/**
|
||||
* @brief Convert a binary array into string representation.
|
||||
*
|
||||
* @param[in] buf The binary array to convert
|
||||
* @param[in] buflen The length of the binary array to convert
|
||||
* @param[out] hex Address of where to store the string representation.
|
||||
* @param[in] hexlen Size of the storage area for string representation.
|
||||
*
|
||||
* @return The length of the converted string, or 0 if an error occurred.
|
||||
*/
|
||||
size_t bin2hex(const u8_t *buf, size_t buflen, char *hex, size_t hexlen);
|
||||
|
||||
/*
|
||||
* Convert hex string to byte string
|
||||
* Return number of bytes written to buf, or 0 on error
|
||||
* @return The length of the converted array, or 0 if an error occurred.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Convert a hexadecimal string into a binary array.
|
||||
*
|
||||
* @param[in] hex The hexadecimal string to convert
|
||||
* @param[in] hexlen The length of the hexadecimal string to convert.
|
||||
* @param[out] buf Address of where to store the binary data
|
||||
* @param[in] buflen Size of the storage area for binary data
|
||||
*
|
||||
* @return The length of the binary array , or 0 if an error occurred.
|
||||
*/
|
||||
size_t hex2bin(const char *hex, size_t hexlen, u8_t *buf, size_t buflen);
|
||||
|
||||
/**
|
||||
* @brief Convert a u8_t into decimal string representation.
|
||||
*
|
||||
* Convert a u8_t value into ASCII decimal string representation.
|
||||
* The string is terminated if there is enough space in buf.
|
||||
*
|
||||
* @param[out] buf Address of where to store the string representation.
|
||||
* @param[in] buflen Size of the storage area for string representation.
|
||||
* @param[in] value The value to convert to decimal string
|
||||
*
|
||||
* @return The length of the converted string (excluding terminator if
|
||||
* any), or 0 if an error occurred.
|
||||
*/
|
||||
u8_t u8_to_dec(char *buf, u8_t buflen, u8_t value);
|
||||
#endif //#if defined(BFLB_BLE)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _UTIL__H_ */
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef __UTILS_STRING_H__
|
||||
#define __UTILS_STRING_H__
|
||||
void get_bytearray_from_string(char **params, uint8_t *result, int array_size);
|
||||
void get_uint8_from_string(char **params, uint8_t *result);
|
||||
void get_uint16_from_string(char **params, uint16_t *result);
|
||||
void get_uint32_from_string(char **params, uint32_t *result);
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2014, Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Macros to abstract toolchain specific capabilities
|
||||
*
|
||||
* This file contains various macros to abstract compiler capabilities that
|
||||
* utilize toolchain specific attributes and/or pragmas.
|
||||
*/
|
||||
|
||||
#ifndef _TOOLCHAIN_H
|
||||
#define _TOOLCHAIN_H
|
||||
|
||||
#if defined(__XCC__)
|
||||
#include <toolchain/xcc.h>
|
||||
#elif defined(__GNUC__) || (defined(_LINKER) && defined(__GCC_LINKER_CMD__))
|
||||
#include <toolchain/gcc.h>
|
||||
#else
|
||||
#include <toolchain/other.h>
|
||||
#endif
|
||||
|
||||
#endif /* _TOOLCHAIN_H */
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2014 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_TOOLCHAIN_COMMON_H_
|
||||
#define ZEPHYR_INCLUDE_TOOLCHAIN_COMMON_H_
|
||||
/**
|
||||
* @file
|
||||
* @brief Common toolchain abstraction
|
||||
*
|
||||
* Macros to abstract compiler capabilities (common to all toolchains).
|
||||
*/
|
||||
|
||||
/* Abstract use of extern keyword for compatibility between C and C++ */
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN_C extern "C"
|
||||
#else
|
||||
#define EXTERN_C extern
|
||||
#endif
|
||||
|
||||
/* Use TASK_ENTRY_CPP to tag task entry points defined in C++ files. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define TASK_ENTRY_CPP extern "C"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Generate a reference to an external symbol.
|
||||
* The reference indicates to the linker that the symbol is required
|
||||
* by the module containing the reference and should be included
|
||||
* in the image if the module is in the image.
|
||||
*
|
||||
* The assembler directive ".set" is used to define a local symbol.
|
||||
* No memory is allocated, and the local symbol does not appear in
|
||||
* the symbol table.
|
||||
*/
|
||||
|
||||
#ifdef _ASMLANGUAGE
|
||||
#define REQUIRES(sym) .set sym##_Requires, sym
|
||||
#else
|
||||
#define REQUIRES(sym) __asm__(".set " #sym "_Requires, " #sym "\n\t");
|
||||
#endif
|
||||
|
||||
#ifdef _ASMLANGUAGE
|
||||
#define SECTION .section
|
||||
#endif
|
||||
|
||||
#define CONFIG_RISCV 1
|
||||
/*
|
||||
* If the project is being built for speed (i.e. not for minimum size) then
|
||||
* align functions and branches in executable sections to improve performance.
|
||||
*/
|
||||
|
||||
#ifdef _ASMLANGUAGE
|
||||
|
||||
#if defined(CONFIG_X86)
|
||||
|
||||
#ifdef PERF_OPT
|
||||
#define PERFOPT_ALIGN .balign 16
|
||||
#else
|
||||
#define PERFOPT_ALIGN .balign 1
|
||||
#endif
|
||||
|
||||
#elif defined(CONFIG_ARM)
|
||||
|
||||
#define PERFOPT_ALIGN .balign 4
|
||||
|
||||
#elif defined(CONFIG_ARC)
|
||||
|
||||
#define PERFOPT_ALIGN .balign 4
|
||||
|
||||
#elif defined(CONFIG_NIOS2) || defined(CONFIG_RISCV) || \
|
||||
defined(CONFIG_XTENSA)
|
||||
#define PERFOPT_ALIGN .balign 4
|
||||
|
||||
#elif defined(CONFIG_ARCH_POSIX)
|
||||
|
||||
#else
|
||||
|
||||
#error Architecture unsupported
|
||||
|
||||
#endif
|
||||
|
||||
#define GC_SECTION(sym) SECTION.text.##sym, "ax"
|
||||
|
||||
#endif /* _ASMLANGUAGE */
|
||||
|
||||
/* force inlining a function */
|
||||
|
||||
#if !defined(_ASMLANGUAGE)
|
||||
#ifdef CONFIG_COVERAGE
|
||||
/*
|
||||
* The always_inline attribute forces a function to be inlined,
|
||||
* even ignoring -fno-inline. So for code coverage, do not
|
||||
* force inlining of these functions to keep their bodies around
|
||||
* so their number of executions can be counted.
|
||||
*
|
||||
* Note that "inline" is kept here for kobject_hash.c and
|
||||
* priv_stacks_hash.c. These are built without compiler flags
|
||||
* used for coverage. ALWAYS_INLINE cannot be empty as compiler
|
||||
* would complain about unused functions. Attaching unused
|
||||
* attribute would result in their text sections ballon more than
|
||||
* 10 times in size, as those functions are kept in text section.
|
||||
* So just keep "inline" here.
|
||||
*/
|
||||
#define ALWAYS_INLINE inline
|
||||
#else
|
||||
#define ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define Z_STRINGIFY(x) #x
|
||||
#define STRINGIFY(s) Z_STRINGIFY(s)
|
||||
|
||||
/* concatenate the values of the arguments into one */
|
||||
#define _DO_CONCAT(x, y) x##y
|
||||
#define _CONCAT(x, y) _DO_CONCAT(x, y)
|
||||
|
||||
/* Additionally used as a sentinel by gen_syscalls.py to identify what
|
||||
* functions are system calls
|
||||
*
|
||||
* Note POSIX unit tests don't still generate the system call stubs, so
|
||||
* until https://github.com/zephyrproject-rtos/zephyr/issues/5006 is
|
||||
* fixed via possibly #4174, we introduce this hack -- which will
|
||||
* disallow us to test system calls in POSIX unit testing (currently
|
||||
* not used).
|
||||
*/
|
||||
#ifndef ZTEST_UNITTEST
|
||||
#define __syscall static inline
|
||||
#else
|
||||
#define __syscall
|
||||
#endif /* #ifndef ZTEST_UNITTEST */
|
||||
|
||||
#ifndef BUILD_ASSERT
|
||||
/* compile-time assertion that makes the build fail */
|
||||
#define BUILD_ASSERT(EXPR) \
|
||||
enum _CONCAT(__build_assert_enum, __COUNTER__) { \
|
||||
_CONCAT(__build_assert, __COUNTER__) = 1 / !!(EXPR) \
|
||||
}
|
||||
#endif
|
||||
#ifndef BUILD_ASSERT_MSG
|
||||
/* build assertion with message -- common implementation swallows message. */
|
||||
#define BUILD_ASSERT_MSG(EXPR, MSG) BUILD_ASSERT(EXPR)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is meant to be used in conjunction with __in_section() and similar
|
||||
* where scattered structure instances are concatened together by the linker
|
||||
* and walked by the code at run time just like a contiguous array of such
|
||||
* structures.
|
||||
*
|
||||
* Assemblers and linkers may insert alignment padding by default whose
|
||||
* size is larger than the natural alignment for those structures when
|
||||
* gathering various section segments together, messing up the array walk.
|
||||
* To prevent this, we need to provide an explicit alignment not to rely
|
||||
* on the default that might just work by luck.
|
||||
*
|
||||
* Alignment statements in linker scripts are not sufficient as
|
||||
* the assembler may add padding by itself to each segment when switching
|
||||
* between sections within the same file even if it merges many such segments
|
||||
* into a single section in the end.
|
||||
*/
|
||||
#define Z_DECL_ALIGN(type) __aligned(__alignof(type)) type
|
||||
|
||||
/*
|
||||
* Convenience helper combining __in_section() and Z_DECL_ALIGN().
|
||||
* The section name is the struct type prepended with an underscore.
|
||||
* The subsection is "static" and the subsubsection is the variable name.
|
||||
*/
|
||||
#define Z_STRUCT_SECTION_ITERABLE(struct_type, name) \
|
||||
Z_DECL_ALIGN(struct struct_type) \
|
||||
name \
|
||||
__in_section(_##struct_type, static, name) __used
|
||||
|
||||
/*
|
||||
* Itterator for structure instances gathered by Z_STRUCT_SECTION_ITERABLE().
|
||||
* The linker must provide a _<struct_type>_list_start symbol and a
|
||||
* _<struct_type>_list_end symbol to mark the start and the end of the
|
||||
* list of struct objects to iterate over.
|
||||
*/
|
||||
#define Z_STRUCT_SECTION_FOREACH(struct_type, iterator) \
|
||||
extern struct struct_type _CONCAT(_##struct_type, _list_start)[]; \
|
||||
extern struct struct_type _CONCAT(_##struct_type, _list_end)[]; \
|
||||
for (struct struct_type *iterator = \
|
||||
_CONCAT(_##struct_type, _list_start); \
|
||||
({ __ASSERT(iterator <= _CONCAT(_##struct_type, _list_end), \
|
||||
"unexpected list end location"); \
|
||||
iterator < _CONCAT(_##struct_type, _list_end); }); \
|
||||
iterator++)
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_TOOLCHAIN_COMMON_H_ */
|
||||
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2014,2017 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_TOOLCHAIN_GCC_H_
|
||||
#define ZEPHYR_INCLUDE_TOOLCHAIN_GCC_H_
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief GCC toolchain abstraction
|
||||
*
|
||||
* Macros to abstract compiler capabilities for GCC toolchain.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Older versions of GCC do not define __BYTE_ORDER__, so it must be manually
|
||||
* detected and defined using arch-specific definitions.
|
||||
*/
|
||||
|
||||
#ifndef _LINKER
|
||||
|
||||
#ifndef __ORDER_BIG_ENDIAN__
|
||||
#define __ORDER_BIG_ENDIAN__ (1)
|
||||
#endif
|
||||
|
||||
#ifndef __ORDER_LITTLE_ENDIAN__
|
||||
#define __ORDER_LITTLE_ENDIAN__ (2)
|
||||
#endif
|
||||
|
||||
#ifndef __BYTE_ORDER__
|
||||
#if defined(__BIG_ENDIAN__) || defined(__ARMEB__) || \
|
||||
defined(__THUMBEB__) || defined(__AARCH64EB__) || \
|
||||
defined(__MIPSEB__) || defined(__TC32EB__)
|
||||
|
||||
#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
|
||||
|
||||
#elif defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \
|
||||
defined(__THUMBEL__) || defined(__AARCH64EL__) || \
|
||||
defined(__MIPSEL__) || defined(__TC32EL__)
|
||||
|
||||
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
|
||||
|
||||
#else
|
||||
#error "__BYTE_ORDER__ is not defined and cannot be automatically resolved"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* C++11 has static_assert built in */
|
||||
#ifdef __cplusplus
|
||||
#define BUILD_ASSERT(EXPR) static_assert(EXPR, "")
|
||||
#define BUILD_ASSERT_MSG(EXPR, MSG) static_assert(EXPR, MSG)
|
||||
/*
|
||||
* GCC 4.6 and higher have the C11 _Static_assert built in, and its
|
||||
* output is easier to understand than the common BUILD_ASSERT macros.
|
||||
*/
|
||||
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) || \
|
||||
(__STDC_VERSION__) >= 201100
|
||||
#define BUILD_ASSERT(EXPR) _Static_assert(EXPR, "")
|
||||
#define BUILD_ASSERT_MSG(EXPR, MSG) _Static_assert(EXPR, MSG)
|
||||
#endif
|
||||
|
||||
#include <toolchain/common.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define ALIAS_OF(of) __attribute__((alias(#of)))
|
||||
|
||||
#define FUNC_ALIAS(real_func, new_alias, return_type) \
|
||||
return_type new_alias() ALIAS_OF(real_func)
|
||||
|
||||
#if defined(CONFIG_ARCH_POSIX)
|
||||
#include <arch/posix/posix_trace.h>
|
||||
|
||||
/*let's not segfault if this were to happen for some reason*/
|
||||
#define CODE_UNREACHABLE \
|
||||
{ \
|
||||
posix_print_error_and_exit("CODE_UNREACHABLE reached from %s:%d\n", \
|
||||
__FILE__, __LINE__); \
|
||||
__builtin_unreachable(); \
|
||||
}
|
||||
#else
|
||||
#define CODE_UNREACHABLE __builtin_unreachable()
|
||||
#endif
|
||||
#define FUNC_NORETURN __attribute__((__noreturn__))
|
||||
|
||||
/* The GNU assembler for Cortex-M3 uses # for immediate values, not
|
||||
* comments, so the @nobits# trick does not work.
|
||||
*/
|
||||
#if defined(CONFIG_ARM)
|
||||
#define _NODATA_SECTION(segment) __attribute__((section(#segment)))
|
||||
#else
|
||||
#define _NODATA_SECTION(segment) \
|
||||
__attribute__((section(#segment ",\"wa\",@nobits#")))
|
||||
#endif
|
||||
|
||||
/* Unaligned access */
|
||||
#define UNALIGNED_GET(p) \
|
||||
__extension__({ \
|
||||
struct __attribute__((__packed__)) { \
|
||||
__typeof__(*(p)) __v; \
|
||||
} *__p = (__typeof__(__p))(p); \
|
||||
__p->__v; \
|
||||
})
|
||||
|
||||
#if __GNUC__ >= 7 && defined(CONFIG_ARM)
|
||||
|
||||
/* Version of UNALIGNED_PUT() which issues a compiler_barrier() after
|
||||
* the store. It is required to workaround an apparent optimization
|
||||
* bug in GCC for ARM Cortex-M3 and higher targets, when multiple
|
||||
* byte, half-word and word stores (strb, strh, str instructions),
|
||||
* which support unaligned access, can be coalesced into store double
|
||||
* (strd) instruction, which doesn't support unaligned access (the
|
||||
* compilers in question do this optimization ignoring __packed__
|
||||
* attribute).
|
||||
*/
|
||||
#define UNALIGNED_PUT(v, p) \
|
||||
do { \
|
||||
struct __attribute__((__packed__)) { \
|
||||
__typeof__(*p) __v; \
|
||||
} *__p = (__typeof__(__p))(p); \
|
||||
__p->__v = (v); \
|
||||
compiler_barrier(); \
|
||||
} while (false)
|
||||
|
||||
#else
|
||||
|
||||
#define UNALIGNED_PUT(v, p) \
|
||||
do { \
|
||||
struct __attribute__((__packed__)) { \
|
||||
__typeof__(*p) __v; \
|
||||
} *__p = (__typeof__(__p))(p); \
|
||||
__p->__v = (v); \
|
||||
} while (false)
|
||||
|
||||
#endif
|
||||
|
||||
/* Double indirection to ensure section names are expanded before
|
||||
* stringification
|
||||
*/
|
||||
#define __GENERIC_SECTION(segment) __attribute__((section(STRINGIFY(segment))))
|
||||
#define Z_GENERIC_SECTION(segment) __GENERIC_SECTION(segment)
|
||||
|
||||
#define ___in_section(a, b, c) \
|
||||
__attribute__((section("." Z_STRINGIFY(a) "." Z_STRINGIFY(b) "." Z_STRINGIFY(c))))
|
||||
#define __in_section(a, b, c) ___in_section(a, b, c)
|
||||
|
||||
#define __in_section_unique(seg) ___in_section(seg, __FILE__, __COUNTER__)
|
||||
|
||||
/* When using XIP, using '__ramfunc' places a function into RAM instead
|
||||
* of FLASH. Make sure '__ramfunc' is defined only when
|
||||
* CONFIG_ARCH_HAS_RAMFUNC_SUPPORT is defined, so that the compiler can
|
||||
* report an error if '__ramfunc' is used but the architecture does not
|
||||
* support it.
|
||||
*/
|
||||
#if !defined(CONFIG_XIP)
|
||||
#define __ramfunc
|
||||
#elif defined(CONFIG_ARCH_HAS_RAMFUNC_SUPPORT)
|
||||
#define __ramfunc __attribute__((noinline)) \
|
||||
__attribute__((long_call, section(".ramfunc")))
|
||||
#endif /* !CONFIG_XIP */
|
||||
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((__packed__))
|
||||
#endif
|
||||
#ifndef __aligned
|
||||
#define __aligned(x) __attribute__((__aligned__(x)))
|
||||
#endif
|
||||
#define __may_alias __attribute__((__may_alias__))
|
||||
#ifndef __printf_like
|
||||
#define __printf_like(f, a) __attribute__((format(printf, f, a)))
|
||||
#endif
|
||||
#define __used __attribute__((__used__))
|
||||
#ifndef __deprecated
|
||||
#define __deprecated __attribute__((deprecated))
|
||||
#endif
|
||||
#define ARG_UNUSED(x) (void)(x)
|
||||
|
||||
#ifndef likely
|
||||
#define likely(x) __builtin_expect((bool)!!(x), true)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(x) __builtin_expect((bool)!!(x), false)
|
||||
#endif
|
||||
|
||||
#define popcount(x) __builtin_popcount(x)
|
||||
|
||||
#ifndef __weak
|
||||
#define __weak __attribute__((__weak__))
|
||||
#endif
|
||||
#define __unused __attribute__((__unused__))
|
||||
|
||||
/* Builtins with availability that depend on the compiler version. */
|
||||
#if __GNUC__ >= 5
|
||||
#define HAS_BUILTIN___builtin_add_overflow 1
|
||||
#define HAS_BUILTIN___builtin_sub_overflow 1
|
||||
#define HAS_BUILTIN___builtin_mul_overflow 1
|
||||
#define HAS_BUILTIN___builtin_div_overflow 1
|
||||
#endif
|
||||
#if __GNUC__ >= 4
|
||||
#define HAS_BUILTIN___builtin_clz 1
|
||||
#define HAS_BUILTIN___builtin_clzl 1
|
||||
#define HAS_BUILTIN___builtin_clzll 1
|
||||
#define HAS_BUILTIN___builtin_ctz 1
|
||||
#define HAS_BUILTIN___builtin_ctzl 1
|
||||
#define HAS_BUILTIN___builtin_ctzll 1
|
||||
#endif
|
||||
|
||||
/* Be *very* careful with this, you cannot filter out with -wno-deprecated,
|
||||
* which has implications for -Werror
|
||||
*/
|
||||
#define __DEPRECATED_MACRO _Pragma("GCC warning \"Macro is deprecated\"")
|
||||
|
||||
/* These macros allow having ARM asm functions callable from thumb */
|
||||
|
||||
#if defined(_ASMLANGUAGE)
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
|
||||
#if defined(CONFIG_ISA_THUMB2)
|
||||
|
||||
#define FUNC_CODE() .thumb;
|
||||
#define FUNC_INSTR(a)
|
||||
|
||||
#elif defined(CONFIG_ISA_ARM)
|
||||
|
||||
#define FUNC_CODE() .code 32
|
||||
#define FUNC_INSTR(a)
|
||||
|
||||
#else
|
||||
|
||||
#error unknown instruction set
|
||||
|
||||
#endif /* ISA */
|
||||
|
||||
#else
|
||||
|
||||
#define FUNC_CODE()
|
||||
#define FUNC_INSTR(a)
|
||||
|
||||
#endif /* !CONFIG_ARM */
|
||||
|
||||
#endif /* _ASMLANGUAGE */
|
||||
|
||||
/*
|
||||
* These macros are used to declare assembly language symbols that need
|
||||
* to be typed properly(func or data) to be visible to the OMF tool.
|
||||
* So that the build tool could mark them as an entry point to be linked
|
||||
* correctly. This is an elfism. Use #if 0 for a.out.
|
||||
*/
|
||||
|
||||
#if defined(_ASMLANGUAGE)
|
||||
|
||||
#if defined(CONFIG_ARM) || defined(CONFIG_NIOS2) || defined(CONFIG_RISCV) || defined(CONFIG_XTENSA)
|
||||
#define GTEXT(sym) \
|
||||
.global sym; \
|
||||
.type sym, % function
|
||||
#define GDATA(sym) \
|
||||
.global sym; \
|
||||
.type sym, % object
|
||||
#define WTEXT(sym) \
|
||||
.weak sym; \
|
||||
.type sym, % function
|
||||
#define WDATA(sym) \
|
||||
.weak sym; \
|
||||
.type sym, % object
|
||||
#elif defined(CONFIG_ARC)
|
||||
/*
|
||||
* Need to use assembly macros because ';' is interpreted as the start of
|
||||
* a single line comment in the ARC assembler.
|
||||
*/
|
||||
|
||||
.macro glbl_text symbol
|
||||
.globl \symbol
|
||||
.type \symbol,
|
||||
% function
|
||||
.endm
|
||||
|
||||
.macro glbl_data symbol
|
||||
.globl \symbol
|
||||
.type \symbol,
|
||||
% object
|
||||
.endm
|
||||
|
||||
.macro weak_data symbol
|
||||
.weak \symbol
|
||||
.type \symbol,
|
||||
% object
|
||||
.endm
|
||||
|
||||
#define GTEXT(sym) glbl_text sym
|
||||
#define GDATA(sym) glbl_data sym
|
||||
#define WDATA(sym) weak_data sym
|
||||
|
||||
#else /* !CONFIG_ARM && !CONFIG_ARC */
|
||||
#define GTEXT(sym) \
|
||||
.globl sym; \
|
||||
.type sym, @function
|
||||
#define GDATA(sym) \
|
||||
.globl sym; \
|
||||
.type sym, @object
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These macros specify the section in which a given function or variable
|
||||
* resides.
|
||||
*
|
||||
* - SECTION_FUNC allows only one function to reside in a sub-section
|
||||
* - SECTION_SUBSEC_FUNC allows multiple functions to reside in a sub-section
|
||||
* This ensures that garbage collection only discards the section
|
||||
* if all functions in the sub-section are not referenced.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_ARC)
|
||||
/*
|
||||
* Need to use assembly macros because ';' is interpreted as the start of
|
||||
* a single line comment in the ARC assembler.
|
||||
*
|
||||
* Also, '\()' is needed in the .section directive of these macros for
|
||||
* correct substitution of the 'section' variable.
|
||||
*/
|
||||
|
||||
.macro section_var section, symbol.section.\section\().\symbol
|
||||
\symbol :.endm
|
||||
|
||||
.macro section_func section,
|
||||
symbol
|
||||
.section.\section\()
|
||||
.\symbol,
|
||||
"ax" FUNC_CODE()
|
||||
PERFOPT_ALIGN
|
||||
\symbol : FUNC_INSTR(\symbol)
|
||||
.endm
|
||||
|
||||
.macro section_subsec_func section,
|
||||
subsection, symbol.section.\section\().\subsection, "ax" PERFOPT_ALIGN
|
||||
\symbol :.endm
|
||||
|
||||
#define SECTION_VAR(sect, sym) section_var sect, sym
|
||||
#define SECTION_FUNC(sect, sym) section_func sect, sym
|
||||
#define SECTION_SUBSEC_FUNC(sect, subsec, sym) \
|
||||
section_subsec_func sect, subsec, sym
|
||||
#else /* !CONFIG_ARC */
|
||||
|
||||
#define SECTION_VAR(sect, sym) \
|
||||
.section.sect.##sym; \
|
||||
sym:
|
||||
#define SECTION_FUNC(sect, sym) \
|
||||
.section.sect.sym, "ax"; \
|
||||
FUNC_CODE() \
|
||||
PERFOPT_ALIGN; \
|
||||
sym: \
|
||||
FUNC_INSTR(sym)
|
||||
#define SECTION_SUBSEC_FUNC(sect, subsec, sym) \
|
||||
.section.sect.subsec, "ax"; \
|
||||
PERFOPT_ALIGN; \
|
||||
sym:
|
||||
|
||||
#endif /* CONFIG_ARC */
|
||||
|
||||
#endif /* _ASMLANGUAGE */
|
||||
|
||||
#if defined(CONFIG_ARM) && defined(_ASMLANGUAGE)
|
||||
#if defined(CONFIG_ISA_THUMB2)
|
||||
/* '.syntax unified' is a gcc-ism used in thumb-2 asm files */
|
||||
#define _ASM_FILE_PROLOGUE \
|
||||
.text; \
|
||||
.syntax unified; \
|
||||
.thumb
|
||||
#else
|
||||
#define _ASM_FILE_PROLOGUE \
|
||||
.text; \
|
||||
.code 32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These macros generate absolute symbols for GCC
|
||||
*/
|
||||
|
||||
/* create an extern reference to the absolute symbol */
|
||||
|
||||
#define GEN_OFFSET_EXTERN(name) extern const char name[]
|
||||
|
||||
#define GEN_ABS_SYM_BEGIN(name) \
|
||||
EXTERN_C void name(void); \
|
||||
void name(void) \
|
||||
{
|
||||
#define GEN_ABS_SYM_END }
|
||||
|
||||
#if defined(CONFIG_ARM)
|
||||
|
||||
/*
|
||||
* GNU/ARM backend does not have a proper operand modifier which does not
|
||||
* produces prefix # followed by value, such as %0 for PowerPC, Intel, and
|
||||
* MIPS. The workaround performed here is using %B0 which converts
|
||||
* the value to ~(value). Thus "n"(~(value)) is set in operand constraint
|
||||
* to output (value) in the ARM specific GEN_OFFSET macro.
|
||||
*/
|
||||
|
||||
#define GEN_ABSOLUTE_SYM(name, value) \
|
||||
__asm__(".globl\t" #name "\n\t.equ\t" #name \
|
||||
",%B0" \
|
||||
"\n\t.type\t" #name ",%%object" \
|
||||
: \
|
||||
: "n"(~(value)))
|
||||
|
||||
#elif defined(CONFIG_X86) || defined(CONFIG_ARC)
|
||||
|
||||
#define GEN_ABSOLUTE_SYM(name, value) \
|
||||
__asm__(".globl\t" #name "\n\t.equ\t" #name \
|
||||
",%c0" \
|
||||
"\n\t.type\t" #name ",@object" \
|
||||
: \
|
||||
: "n"(value))
|
||||
|
||||
#elif defined(CONFIG_NIOS2) || defined(CONFIG_RISCV) || defined(CONFIG_XTENSA)
|
||||
|
||||
/* No special prefixes necessary for constants in this arch AFAICT */
|
||||
#define GEN_ABSOLUTE_SYM(name, value) \
|
||||
__asm__(".globl\t" #name "\n\t.equ\t" #name \
|
||||
",%0" \
|
||||
"\n\t.type\t" #name ",%%object" \
|
||||
: \
|
||||
: "n"(value))
|
||||
|
||||
#elif defined(CONFIG_ARCH_POSIX)
|
||||
#define GEN_ABSOLUTE_SYM(name, value) \
|
||||
__asm__(".globl\t" #name "\n\t.equ\t" #name \
|
||||
",%c0" \
|
||||
"\n\t.type\t" #name ",@object" \
|
||||
: \
|
||||
: "n"(value))
|
||||
#else
|
||||
#error processor architecture not supported
|
||||
#endif
|
||||
|
||||
#define compiler_barrier() \
|
||||
do { \
|
||||
__asm__ __volatile__("" :: \
|
||||
: "memory"); \
|
||||
} while (false)
|
||||
|
||||
/** @brief Return larger value of two provided expressions.
|
||||
*
|
||||
* Macro ensures that expressions are evaluated only once.
|
||||
*
|
||||
* @note Macro has limited usage compared to the standard macro as it cannot be
|
||||
* used:
|
||||
* - to generate constant integer, e.g. __aligned(Z_MAX(4,5))
|
||||
* - static variable, e.g. array like static u8_t array[Z_MAX(...)];
|
||||
*/
|
||||
#define Z_MAX(a, b) ({ \
|
||||
/* random suffix to avoid naming conflict */ \
|
||||
__typeof__(a) _value_a_ = (a); \
|
||||
__typeof__(b) _value_b_ = (b); \
|
||||
_value_a_ > _value_b_ ? _value_a_ : _value_b_; \
|
||||
})
|
||||
|
||||
/** @brief Return smaller value of two provided expressions.
|
||||
*
|
||||
* Macro ensures that expressions are evaluated only once. See @ref Z_MAX for
|
||||
* macro limitations.
|
||||
*/
|
||||
#define Z_MIN(a, b) ({ \
|
||||
/* random suffix to avoid naming conflict */ \
|
||||
__typeof__(a) _value_a_ = (a); \
|
||||
__typeof__(b) _value_b_ = (b); \
|
||||
_value_a_ < _value_b_ ? _value_a_ : _value_b_; \
|
||||
})
|
||||
|
||||
#endif /* !_LINKER */
|
||||
#endif /* ZEPHYR_INCLUDE_TOOLCHAIN_GCC_H_ */
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_TOOLCHAIN_XCC_H_
|
||||
#define ZEPHYR_INCLUDE_TOOLCHAIN_XCC_H_
|
||||
|
||||
/* toolchain/gcc.h errors out if __BYTE_ORDER__ cannot be determined
|
||||
* there. However, __BYTE_ORDER__ is actually being defined later in
|
||||
* this file. So define __BYTE_ORDER__ to skip the check in gcc.h
|
||||
* and undefine after including gcc.h.
|
||||
*/
|
||||
#define __BYTE_ORDER__
|
||||
#include <toolchain/gcc.h>
|
||||
#undef __BYTE_ORDER__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* XCC doesn't support __COUNTER__ but this should be good enough */
|
||||
#define __COUNTER__ __LINE__
|
||||
|
||||
#undef __in_section_unique
|
||||
#define __in_section_unique(seg) \
|
||||
__attribute__((section("." STRINGIFY(seg) "." STRINGIFY(__COUNTER__))))
|
||||
|
||||
#ifndef __GCC_LINKER_CMD__
|
||||
#include <xtensa/config/core.h>
|
||||
|
||||
/*
|
||||
* XCC does not define the following macros with the expected names, but the
|
||||
* HAL defines similar ones. Thus we include it and define the missing macros
|
||||
* ourselves.
|
||||
*/
|
||||
#if XCHAL_MEMORY_ORDER == XTHAL_BIGENDIAN
|
||||
#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
|
||||
#elif XCHAL_MEMORY_ORDER == XTHAL_LITTLEENDIAN
|
||||
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
|
||||
#else
|
||||
#error "Cannot determine __BYTE_ORDER__"
|
||||
#endif
|
||||
|
||||
#endif /* __GCC_LINKER_CMD__ */
|
||||
|
||||
#define __builtin_unreachable() \
|
||||
do { \
|
||||
__ASSERT(false, "Unreachable code"); \
|
||||
} while (true)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
#ifndef WORK_Q_H
|
||||
#define WORK_Q_H
|
||||
#include "atomic.h"
|
||||
#include "zephyr.h"
|
||||
|
||||
#if defined(BFLB_BLE)
|
||||
struct k_work_q {
|
||||
struct k_fifo fifo;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
bl_timer_t timer;
|
||||
struct k_delayed_work *delay_work;
|
||||
} timer_rec_d;
|
||||
|
||||
int k_work_q_start();
|
||||
|
||||
enum {
|
||||
K_WORK_STATE_PENDING,
|
||||
K_WORK_STATE_PERIODIC,
|
||||
};
|
||||
struct k_work;
|
||||
/* work define*/
|
||||
typedef void (*k_work_handler_t)(struct k_work *work);
|
||||
struct k_work {
|
||||
void *_reserved;
|
||||
k_work_handler_t handler;
|
||||
atomic_t flags[1];
|
||||
};
|
||||
|
||||
#define _K_WORK_INITIALIZER(work_handler) \
|
||||
{ \
|
||||
._reserved = NULL, \
|
||||
.handler = work_handler, \
|
||||
.flags = { 0 } \
|
||||
}
|
||||
|
||||
#define K_WORK_INITIALIZER __DEPRECATED_MACRO _K_WORK_INITIALIZER
|
||||
|
||||
int k_work_init(struct k_work *work, k_work_handler_t handler);
|
||||
void k_work_submit(struct k_work *work);
|
||||
|
||||
/*delay work define*/
|
||||
struct k_delayed_work {
|
||||
struct k_work work;
|
||||
struct k_work_q *work_q;
|
||||
k_timer_t timer;
|
||||
};
|
||||
|
||||
void k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler);
|
||||
int k_delayed_work_submit(struct k_delayed_work *work, uint32_t delay);
|
||||
/* Added by bouffalolab */
|
||||
int k_delayed_work_submit_periodic(struct k_delayed_work *work, s32_t period);
|
||||
int k_delayed_work_cancel(struct k_delayed_work *work);
|
||||
s32_t k_delayed_work_remaining_get(struct k_delayed_work *work);
|
||||
void k_delayed_work_del_timer(struct k_delayed_work *work);
|
||||
/* Added by bouffalolab */
|
||||
int k_delayed_work_free(struct k_delayed_work *work);
|
||||
#endif
|
||||
#endif /* WORK_Q_H */
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __Z_TYPES_H__
|
||||
#define __Z_TYPES_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef signed char s8_t;
|
||||
typedef signed short s16_t;
|
||||
typedef signed int s32_t;
|
||||
typedef signed long long s64_t;
|
||||
|
||||
typedef unsigned char u8_t;
|
||||
typedef unsigned short u16_t;
|
||||
typedef unsigned int u32_t;
|
||||
typedef unsigned long long u64_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __Z_TYPES_H__ */
|
||||
@@ -0,0 +1,61 @@
|
||||
/* log.c - logging helpers */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* Helper for printk parameters to convert from binary to hex.
|
||||
* We declare multiple buffers so the helper can be used multiple times
|
||||
* in a single printk call.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <zephyr/types.h>
|
||||
#include <zephyr.h>
|
||||
#include <misc/util.h>
|
||||
#include <bluetooth.h>
|
||||
#include <hci_host.h>
|
||||
|
||||
const char *bt_hex_real(const void *buf, size_t len)
|
||||
{
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
#if defined(CONFIG_BT_DEBUG_MONITOR)
|
||||
static char str[255];
|
||||
#else
|
||||
static char str[128];
|
||||
#endif
|
||||
const u8_t *b = buf;
|
||||
int i;
|
||||
|
||||
len = MIN(len, (sizeof(str) - 1) / 2);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
str[i * 2] = hex[b[i] >> 4];
|
||||
str[i * 2 + 1] = hex[b[i] & 0xf];
|
||||
}
|
||||
|
||||
str[i * 2] = '\0';
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
const char *bt_addr_str_real(const bt_addr_t *addr)
|
||||
{
|
||||
static char str[BT_ADDR_STR_LEN];
|
||||
|
||||
bt_addr_to_str(addr, str, sizeof(str));
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
const char *bt_addr_le_str_real(const bt_addr_le_t *addr)
|
||||
{
|
||||
static char str[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
bt_addr_le_to_str(addr, str, sizeof(str));
|
||||
|
||||
return str;
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/** @file
|
||||
* @brief Bluetooth subsystem logging helpers.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef __BT_LOG_H
|
||||
#define __BT_LOG_H
|
||||
|
||||
#if defined(BL_MCU_SDK)
|
||||
#include "bflb_platform.h"
|
||||
#endif
|
||||
|
||||
#include <zephyr.h>
|
||||
|
||||
#include <bluetooth.h>
|
||||
#include <hci_host.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "FreeRTOSConfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !defined(BT_DBG_ENABLED)
|
||||
#define BT_DBG_ENABLED 1
|
||||
#endif
|
||||
|
||||
#if BT_DBG_ENABLED
|
||||
#define LOG_LEVEL LOG_LEVEL_DBG
|
||||
#else
|
||||
#define LOG_LEVEL CONFIG_BT_LOG_LEVEL
|
||||
#endif
|
||||
|
||||
//LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL);
|
||||
|
||||
#if defined(BFLB_BLE)
|
||||
|
||||
#if defined(BL_MCU_SDK)
|
||||
#define BT_DBG(fmt, ...) //bflb_platform_printf(fmt", %s\r\n", ##__VA_ARGS__, __func__)
|
||||
#define BT_ERR(fmt, ...) bflb_platform_printf(fmt ", %s\r\n", ##__VA_ARGS__, __func__)
|
||||
#else
|
||||
#define BT_DBG(fmt, ...) //printf(fmt", %s\r\n", ##__VA_ARGS__, __func__)
|
||||
#define BT_ERR(fmt, ...) printf(fmt ", %s\r\n", ##__VA_ARGS__, __func__)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_STACK_PTS) || defined(CONFIG_BT_MESH_PTS)
|
||||
#if defined(BL_MCU_SDK)
|
||||
#define BT_PTS(fmt, ...) bflb_platform_printf(fmt "\r\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define BT_PTS(fmt, ...) printf(fmt "\r\n", ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#if defined(BL_MCU_SDK)
|
||||
#define BT_WARN(fmt, ...) bflb_platform_printf(fmt ", %s\r\n", ##__VA_ARGS__, __func__)
|
||||
#define BT_INFO(fmt, ...) //bflb_platform_printf(fmt", %s\r\n", ##__VA_ARGS__, __func__)
|
||||
#else
|
||||
#define BT_WARN(fmt, ...) printf(fmt ", %s\r\n", ##__VA_ARGS__, __func__)
|
||||
#define BT_INFO(fmt, ...) //printf(fmt", %s\r\n", ##__VA_ARGS__, __func__)
|
||||
#endif
|
||||
|
||||
#else /*BFLB_BLE*/
|
||||
|
||||
#define BT_DBG(fmt, ...) LOG_DBG(fmt, ##__VA_ARGS__)
|
||||
#define BT_ERR(fmt, ...) LOG_ERR(fmt, ##__VA_ARGS__)
|
||||
#define BT_WARN(fmt, ...) LOG_WRN(fmt, ##__VA_ARGS__)
|
||||
#define BT_INFO(fmt, ...) LOG_INF(fmt, ##__VA_ARGS__)
|
||||
|
||||
#if defined(CONFIG_BT_ASSERT_VERBOSE)
|
||||
#define BT_ASSERT_PRINT(fmt, ...) printk(fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define BT_ASSERT_PRINT(fmt, ...)
|
||||
#endif /* CONFIG_BT_ASSERT_VERBOSE */
|
||||
|
||||
#if defined(CONFIG_BT_ASSERT_PANIC)
|
||||
#define BT_ASSERT_DIE k_panic
|
||||
#else
|
||||
#define BT_ASSERT_DIE k_oops
|
||||
#endif /* CONFIG_BT_ASSERT_PANIC */
|
||||
|
||||
#endif /*BFLB_BLE*/
|
||||
|
||||
#if defined(CONFIG_BT_ASSERT)
|
||||
#if defined(BFLB_BLE)
|
||||
extern void vAssertCalled(void);
|
||||
#define BT_ASSERT(cond) \
|
||||
if ((cond) == 0) \
|
||||
vAssertCalled()
|
||||
#else
|
||||
#define BT_ASSERT(cond) \
|
||||
if (!(cond)) { \
|
||||
BT_ASSERT_PRINT("assert: '" #cond \
|
||||
"' failed\n"); \
|
||||
BT_ASSERT_DIE(); \
|
||||
}
|
||||
#endif /*BFLB_BLE*/
|
||||
#else
|
||||
#if defined(BFLB_BLE)
|
||||
#define BT_ASSERT(cond)
|
||||
#else
|
||||
#define BT_ASSERT(cond) __ASSERT_NO_MSG(cond)
|
||||
#endif /*BFLB_BLE*/
|
||||
#endif /* CONFIG_BT_ASSERT*/
|
||||
|
||||
#define BT_HEXDUMP_DBG(_data, _length, _str) \
|
||||
LOG_HEXDUMP_DBG((const u8_t *)_data, _length, _str)
|
||||
|
||||
#if defined(BFLB_BLE)
|
||||
static inline char *log_strdup(const char *str)
|
||||
{
|
||||
return (char *)str;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* NOTE: These helper functions always encodes into the same buffer storage.
|
||||
* It is the responsibility of the user of this function to copy the information
|
||||
* in this string if needed.
|
||||
*/
|
||||
const char *bt_hex_real(const void *buf, size_t len);
|
||||
const char *bt_addr_str_real(const bt_addr_t *addr);
|
||||
const char *bt_addr_le_str_real(const bt_addr_le_t *addr);
|
||||
|
||||
/* NOTE: log_strdup does not guarantee a duplication of the string.
|
||||
* It is therefore still the responsibility of the user to handle the
|
||||
* restrictions in the underlying function call.
|
||||
*/
|
||||
#define bt_hex(buf, len) log_strdup(bt_hex_real(buf, len))
|
||||
#define bt_addr_str(addr) log_strdup(bt_addr_str_real(addr))
|
||||
#define bt_addr_le_str(addr) log_strdup(bt_addr_le_str_real(addr))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BT_LOG_H */
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Kernel asynchronous event polling interface.
|
||||
*
|
||||
* This polling mechanism allows waiting on multiple events concurrently,
|
||||
* either events triggered directly, or from kernel objects or other kernel
|
||||
* constructs.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <zephyr/types.h>
|
||||
#include <misc/slist.h>
|
||||
#include <misc/dlist.h>
|
||||
#include <misc/__assert.h>
|
||||
|
||||
struct k_sem g_poll_sem;
|
||||
|
||||
void k_poll_event_init(struct k_poll_event *event, u32_t type,
|
||||
int mode, void *obj)
|
||||
{
|
||||
__ASSERT(mode == K_POLL_MODE_NOTIFY_ONLY,
|
||||
"only NOTIFY_ONLY mode is supported\n");
|
||||
__ASSERT(type < (1 << _POLL_NUM_TYPES), "invalid type\n");
|
||||
__ASSERT(obj, "must provide an object\n");
|
||||
|
||||
event->poller = NULL;
|
||||
/* event->tag is left uninitialized: the user will set it if needed */
|
||||
event->type = type;
|
||||
event->state = K_POLL_STATE_NOT_READY;
|
||||
event->mode = mode;
|
||||
event->unused = 0;
|
||||
event->obj = obj;
|
||||
}
|
||||
|
||||
/* must be called with interrupts locked */
|
||||
static inline int is_condition_met(struct k_poll_event *event, u32_t *state)
|
||||
{
|
||||
switch (event->type) {
|
||||
case K_POLL_TYPE_SEM_AVAILABLE:
|
||||
if (k_sem_count_get(event->sem) > 0) {
|
||||
*state = K_POLL_STATE_SEM_AVAILABLE;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case K_POLL_TYPE_DATA_AVAILABLE:
|
||||
if (!k_queue_is_empty(event->queue)) {
|
||||
*state = K_POLL_STATE_FIFO_DATA_AVAILABLE;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case K_POLL_TYPE_SIGNAL:
|
||||
if (event->signal->signaled) {
|
||||
*state = K_POLL_STATE_SIGNALED;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case K_POLL_TYPE_IGNORE:
|
||||
return 0;
|
||||
default:
|
||||
__ASSERT(0, "invalid event type (0x%x)\n", event->type);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void add_event(sys_dlist_t *events, struct k_poll_event *event,
|
||||
struct _poller *poller)
|
||||
{
|
||||
sys_dlist_append(events, &event->_node);
|
||||
}
|
||||
|
||||
/* must be called with interrupts locked */
|
||||
static inline int register_event(struct k_poll_event *event,
|
||||
struct _poller *poller)
|
||||
{
|
||||
switch (event->type) {
|
||||
case K_POLL_TYPE_SEM_AVAILABLE:
|
||||
__ASSERT(event->sem, "invalid semaphore\n");
|
||||
add_event(&event->sem->poll_events, event, poller);
|
||||
break;
|
||||
case K_POLL_TYPE_DATA_AVAILABLE:
|
||||
__ASSERT(event->queue, "invalid queue\n");
|
||||
add_event(&event->queue->poll_events, event, poller);
|
||||
break;
|
||||
case K_POLL_TYPE_SIGNAL:
|
||||
__ASSERT(event->signal, "invalid poll signal\n");
|
||||
add_event(&event->signal->poll_events, event, poller);
|
||||
break;
|
||||
case K_POLL_TYPE_IGNORE:
|
||||
/* nothing to do */
|
||||
break;
|
||||
default:
|
||||
__ASSERT(0, "invalid event type\n");
|
||||
break;
|
||||
}
|
||||
|
||||
event->poller = poller;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* must be called with interrupts locked */
|
||||
static inline void clear_event_registration(struct k_poll_event *event)
|
||||
{
|
||||
event->poller = NULL;
|
||||
|
||||
switch (event->type) {
|
||||
case K_POLL_TYPE_SEM_AVAILABLE:
|
||||
__ASSERT(event->sem, "invalid semaphore\n");
|
||||
sys_dlist_remove(&event->_node);
|
||||
break;
|
||||
case K_POLL_TYPE_DATA_AVAILABLE:
|
||||
__ASSERT(event->queue, "invalid queue\n");
|
||||
sys_dlist_remove(&event->_node);
|
||||
break;
|
||||
case K_POLL_TYPE_SIGNAL:
|
||||
__ASSERT(event->signal, "invalid poll signal\n");
|
||||
sys_dlist_remove(&event->_node);
|
||||
break;
|
||||
case K_POLL_TYPE_IGNORE:
|
||||
/* nothing to do */
|
||||
break;
|
||||
default:
|
||||
__ASSERT(0, "invalid event type\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* must be called with interrupts locked */
|
||||
static inline void clear_event_registrations(struct k_poll_event *events,
|
||||
int last_registered,
|
||||
unsigned int key)
|
||||
{
|
||||
for (; last_registered >= 0; last_registered--) {
|
||||
clear_event_registration(&events[last_registered]);
|
||||
irq_unlock(key);
|
||||
key = irq_lock();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void set_event_ready(struct k_poll_event *event, u32_t state)
|
||||
{
|
||||
event->poller = NULL;
|
||||
event->state |= state;
|
||||
}
|
||||
|
||||
static bool polling_events(struct k_poll_event *events, int num_events,
|
||||
s32_t timeout, int *last_registered)
|
||||
{
|
||||
int rc;
|
||||
bool polling = true;
|
||||
unsigned int key;
|
||||
|
||||
for (int ii = 0; ii < num_events; ii++) {
|
||||
u32_t state;
|
||||
key = irq_lock();
|
||||
if (is_condition_met(&events[ii], &state)) {
|
||||
set_event_ready(&events[ii], state);
|
||||
polling = false;
|
||||
} else if (timeout != K_NO_WAIT && polling) {
|
||||
rc = register_event(&events[ii], NULL);
|
||||
if (rc == 0) {
|
||||
++(*last_registered);
|
||||
} else {
|
||||
__ASSERT(0, "unexpected return code\n");
|
||||
}
|
||||
}
|
||||
irq_unlock(key);
|
||||
}
|
||||
return polling;
|
||||
}
|
||||
|
||||
int k_poll(struct k_poll_event *events, int num_events, s32_t timeout)
|
||||
{
|
||||
__ASSERT(events, "NULL events\n");
|
||||
__ASSERT(num_events > 0, "zero events\n");
|
||||
|
||||
int last_registered = -1;
|
||||
unsigned int key;
|
||||
bool polling = true;
|
||||
|
||||
/* find events whose condition is already fulfilled */
|
||||
polling = polling_events(events, num_events, timeout, &last_registered);
|
||||
|
||||
if (polling == false) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
k_sem_take(&g_poll_sem, timeout);
|
||||
|
||||
last_registered = -1;
|
||||
polling_events(events, num_events, timeout, &last_registered);
|
||||
exit:
|
||||
key = irq_lock();
|
||||
clear_event_registrations(events, last_registered, key);
|
||||
irq_unlock(key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* must be called with interrupts locked */
|
||||
static int _signal_poll_event(struct k_poll_event *event, u32_t state,
|
||||
int *must_reschedule)
|
||||
{
|
||||
*must_reschedule = 0;
|
||||
set_event_ready(event, state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int k_poll_signal_raise(struct k_poll_signal *signal, int result)
|
||||
{
|
||||
unsigned int key = irq_lock();
|
||||
struct k_poll_event *poll_event;
|
||||
int must_reschedule;
|
||||
|
||||
signal->result = result;
|
||||
signal->signaled = 1;
|
||||
|
||||
poll_event = (struct k_poll_event *)sys_dlist_get(&signal->poll_events);
|
||||
if (!poll_event) {
|
||||
irq_unlock(key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rc = _signal_poll_event(poll_event, K_POLL_STATE_SIGNALED,
|
||||
&must_reschedule);
|
||||
|
||||
k_sem_give(&g_poll_sem);
|
||||
irq_unlock(key);
|
||||
return rc;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @file rpa.c
|
||||
* Resolvable Private Address Generation and Resolution
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <include/atomic.h>
|
||||
#include <misc/util.h>
|
||||
#include <misc/byteorder.h>
|
||||
#include <misc/stack.h>
|
||||
|
||||
#include <constants.h>
|
||||
#include <aes.h>
|
||||
#include <utils.h>
|
||||
#include <cmac_mode.h>
|
||||
#include <../include/bluetooth/crypto.h>
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_RPA)
|
||||
#define LOG_MODULE_NAME bt_rpa
|
||||
#include "log.h"
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY) || defined(CONFIG_BT_PRIVACY) || defined(CONFIG_BT_SMP)
|
||||
static int ah(const u8_t irk[16], const u8_t r[3], u8_t out[3])
|
||||
{
|
||||
u8_t res[16];
|
||||
int err;
|
||||
|
||||
BT_DBG("irk %s", bt_hex(irk, 16));
|
||||
BT_DBG("r %s", bt_hex(r, 3));
|
||||
|
||||
/* r' = padding || r */
|
||||
memcpy(res, r, 3);
|
||||
(void)memset(res + 3, 0, 13);
|
||||
|
||||
err = bt_encrypt_le(irk, res, res);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The output of the random address function ah is:
|
||||
* ah(h, r) = e(k, r') mod 2^24
|
||||
* The output of the security function e is then truncated to 24 bits
|
||||
* by taking the least significant 24 bits of the output of e as the
|
||||
* result of ah.
|
||||
*/
|
||||
memcpy(out, res, 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
bool bt_rpa_irk_matches(const u8_t irk[16], const bt_addr_t *addr)
|
||||
{
|
||||
u8_t hash[3];
|
||||
int err;
|
||||
|
||||
BT_DBG("IRK %s bdaddr %s", bt_hex(irk, 16), bt_addr_str(addr));
|
||||
|
||||
err = ah(irk, addr->val + 3, hash);
|
||||
if (err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !memcmp(addr->val, hash, 3);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_PRIVACY) || defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
int bt_rpa_create(const u8_t irk[16], bt_addr_t *rpa)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_rand(rpa->val + 3, 3);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_ADDR_SET_RPA(rpa);
|
||||
|
||||
err = ah(irk, rpa->val + 3, rpa->val);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_DBG("Created RPA %s", bt_addr_str((bt_addr_t *)rpa->val));
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int bt_rpa_create(const u8_t irk[16], bt_addr_t *rpa)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif /* CONFIG_BT_PRIVACY */
|
||||
@@ -0,0 +1,16 @@
|
||||
/* rpa.h - Bluetooth Resolvable Private Addresses (RPA) generation and
|
||||
* resolution
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "bluetooth.h"
|
||||
#include "hci_host.h"
|
||||
|
||||
bool bt_rpa_irk_matches(const u8_t irk[16], const bt_addr_t *addr);
|
||||
int bt_rpa_create(const u8_t irk[16], bt_addr_t *rpa);
|
||||
@@ -0,0 +1,116 @@
|
||||
# Kconfig - Cryptography primitive options for TinyCrypt version 2.0
|
||||
|
||||
#
|
||||
# Copyright (c) 2015 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
config TINYCRYPT
|
||||
bool
|
||||
prompt "TinyCrypt Support"
|
||||
default n
|
||||
help
|
||||
This option enables the TinyCrypt cryptography library.
|
||||
|
||||
config TINYCRYPT_CTR_PRNG
|
||||
bool
|
||||
prompt "PRNG in counter mode"
|
||||
depends on TINYCRYPT
|
||||
default n
|
||||
help
|
||||
This option enables support for the pseudo-random number
|
||||
generator in counter mode.
|
||||
|
||||
config TINYCRYPT_SHA256
|
||||
bool
|
||||
prompt "SHA-256 Hash function support"
|
||||
depends on TINYCRYPT
|
||||
default n
|
||||
help
|
||||
This option enables support for SHA-256
|
||||
hash function primitive.
|
||||
|
||||
config TINYCRYPT_SHA256_HMAC
|
||||
bool
|
||||
prompt "HMAC (via SHA256) message auth support"
|
||||
depends on TINYCRYPT_SHA256
|
||||
default n
|
||||
help
|
||||
This option enables support for HMAC using SHA-256
|
||||
message authentication code.
|
||||
|
||||
config TINYCRYPT_SHA256_HMAC_PRNG
|
||||
bool
|
||||
prompt "PRNG (via HMAC-SHA256) support"
|
||||
depends on TINYCRYPT_SHA256_HMAC
|
||||
default n
|
||||
help
|
||||
This option enables support for pseudo-random number
|
||||
generator.
|
||||
|
||||
config TINYCRYPT_ECC_DH
|
||||
bool
|
||||
prompt "ECC_DH anonymous key agreement protocol"
|
||||
depends on TINYCRYPT
|
||||
select ENTROPY_GENERATOR
|
||||
default n
|
||||
help
|
||||
This option enables support for the Elliptic curve
|
||||
Diffie-Hellman anonymous key agreement protocol.
|
||||
|
||||
Enabling ECC requires a cryptographically secure random number
|
||||
generator.
|
||||
|
||||
config TINYCRYPT_ECC_DSA
|
||||
bool
|
||||
prompt "ECC_DSA digital signature algorithm"
|
||||
depends on TINYCRYPT
|
||||
select ENTROPY_GENERATOR
|
||||
default n
|
||||
help
|
||||
This option enables support for the Elliptic Curve Digital
|
||||
Signature Algorithm (ECDSA).
|
||||
|
||||
Enabling ECC requires a cryptographically secure random number
|
||||
generator.
|
||||
|
||||
config TINYCRYPT_AES
|
||||
bool
|
||||
prompt "AES-128 decrypt/encrypt"
|
||||
depends on TINYCRYPT
|
||||
default n
|
||||
help
|
||||
This option enables support for AES-128 decrypt and encrypt.
|
||||
|
||||
config TINYCRYPT_AES_CBC
|
||||
bool
|
||||
prompt "AES-128 block cipher"
|
||||
depends on TINYCRYPT_AES
|
||||
default n
|
||||
help
|
||||
This option enables support for AES-128 block cipher mode.
|
||||
|
||||
config TINYCRYPT_AES_CTR
|
||||
bool
|
||||
prompt "AES-128 counter mode"
|
||||
depends on TINYCRYPT_AES
|
||||
default n
|
||||
help
|
||||
This option enables support for AES-128 counter mode.
|
||||
|
||||
config TINYCRYPT_AES_CCM
|
||||
bool
|
||||
prompt "AES-128 CCM mode"
|
||||
depends on TINYCRYPT_AES
|
||||
default n
|
||||
help
|
||||
This option enables support for AES-128 CCM mode.
|
||||
|
||||
config TINYCRYPT_AES_CMAC
|
||||
bool
|
||||
prompt "AES-128 CMAC mode"
|
||||
depends on TINYCRYPT_AES
|
||||
default n
|
||||
help
|
||||
This option enables support for AES-128 CMAC mode.
|
||||
@@ -0,0 +1,71 @@
|
||||
The TinyCrypt library in Zephyr is a downstream of an externally maintained
|
||||
open source project. The original upstream code can be found at:
|
||||
|
||||
https://github.com/01org/tinycrypt
|
||||
|
||||
At revision c214460d7f760e2a75908cb41000afcc0bfca282, version 0.2.7
|
||||
|
||||
Any changes to the local version should include Zephyr's TinyCrypt
|
||||
maintainer in the review. That can be found via the git history.
|
||||
|
||||
The following is the license information for this code:
|
||||
|
||||
================================================================================
|
||||
|
||||
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) 2013, 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.
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -0,0 +1,165 @@
|
||||
/* 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__ */
|
||||
@@ -0,0 +1,537 @@
|
||||
/* 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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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 1
|
||||
|
||||
int default_CSPRNG(uint8_t *dest, unsigned int size);
|
||||
|
||||
#endif /* __UECC_PLATFORM_SPECIFIC_H_ */
|
||||
@@ -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 init 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 init
|
||||
*/
|
||||
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__*/
|
||||
@@ -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
|
||||
* init)
|
||||
* @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__ */
|
||||
@@ -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__ */
|
||||
@@ -0,0 +1,122 @@
|
||||
/* 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>
|
||||
#include <string.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 Set the value 'val' into the buffer 'to', 'len' times, in a way
|
||||
* which does not risk getting optimized out by the compiler
|
||||
* In cases where the compiler does not set __GNUC__ and where the
|
||||
* optimization level removes the memset, it may be necessary to
|
||||
* implement a _set_secure function and define the
|
||||
* TINYCRYPT_ARCH_HAS_SET_SECURE, which then can ensure that the
|
||||
* memset does not get optimized out.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
#ifdef TINYCRYPT_ARCH_HAS_SET_SECURE
|
||||
extern void _set_secure(void *to, uint8_t val, unsigned int len);
|
||||
#else /* ! TINYCRYPT_ARCH_HAS_SET_SECURE */
|
||||
static inline void _set_secure(void *to, uint8_t val, unsigned int len)
|
||||
{
|
||||
(void)memset(to, val, len);
|
||||
#ifdef __GNUC__
|
||||
__asm__ __volatile__("" ::"g"(to)
|
||||
: "memory");
|
||||
#endif /* __GNUC__ */
|
||||
}
|
||||
#endif /* TINYCRYPT_ARCH_HAS_SET_SECURE */
|
||||
|
||||
/*
|
||||
* @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__ */
|
||||
@@ -0,0 +1,183 @@
|
||||
/* 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 <aes.h>
|
||||
#include <constants.h>
|
||||
#include <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;
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/* 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 "aes.h"
|
||||
#include "utils.h"
|
||||
#include "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;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/* 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 "cbc_mode.h"
|
||||
#include "constants.h"
|
||||
#include "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) {
|
||||
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 < outlen; ++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;
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
/* 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 "ccm_mode.h"
|
||||
#include "constants.h"
|
||||
#include "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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
/* 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 "aes.h"
|
||||
#include "cmac_mode.h"
|
||||
#include "constants.h"
|
||||
#include "utils.h"
|
||||
|
||||
/* max number of calls until change the key (2^48).*/
|
||||
static const 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;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/* 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 "constants.h"
|
||||
#include "ctr_mode.h"
|
||||
#include "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;
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
/* 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 "ctr_prng.h"
|
||||
#include "utils.h"
|
||||
#include "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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,923 @@
|
||||
/* 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 "ecc.h"
|
||||
#include "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;
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/* 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 "constants.h"
|
||||
#include "ecc.h"
|
||||
#include "ecc_dh.h"
|
||||
#if defined(BFLB_BLE)
|
||||
#include "utils.h"
|
||||
#endif
|
||||
#include <string.h>
|
||||
#if defined(BL_MCU_SDK)
|
||||
#include "ecc_platform_specific.h"
|
||||
#endif
|
||||
|
||||
#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: */
|
||||
_set_secure(_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: */
|
||||
_set_secure(_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: */
|
||||
_set_secure(p2, 0, sizeof(p2));
|
||||
_set_secure(tmp, 0, sizeof(tmp));
|
||||
_set_secure(_private, 0, sizeof(_private));
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
/* 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 "constants.h"
|
||||
#include "ecc.h"
|
||||
#include "ecc_dsa.h"
|
||||
#if defined(BL_MCU_SDK)
|
||||
#include "ecc_platform_specific.h"
|
||||
#endif
|
||||
|
||||
#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);
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/* 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 */
|
||||
@@ -0,0 +1,145 @@
|
||||
/* 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 "hmac.h"
|
||||
#include "constants.h"
|
||||
#include "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[TC_SHA256_BLOCK_SIZE];
|
||||
struct tc_hmac_state_struct dummy_state;
|
||||
|
||||
if (key_size <= TC_SHA256_BLOCK_SIZE) {
|
||||
/*
|
||||
* The next three calls are 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;
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/* 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 "hmac_prng.h"
|
||||
#include "hmac.h"
|
||||
#include "constants.h"
|
||||
#include "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
|
||||
*/
|
||||
static void update(TCHmacPrng_t prng, const uint8_t *data, unsigned int datalen, const uint8_t *additional_data, unsigned int additional_datalen)
|
||||
{
|
||||
const uint8_t separator0 = 0x00;
|
||||
const uint8_t separator1 = 0x01;
|
||||
|
||||
/* configure the new prng key into the prng's instance of hmac */
|
||||
tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key));
|
||||
|
||||
/* 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));
|
||||
|
||||
if (data && datalen)
|
||||
(void)tc_hmac_update(&prng->h, data, datalen);
|
||||
if (additional_data && additional_datalen)
|
||||
(void)tc_hmac_update(&prng->h, additional_data, additional_datalen);
|
||||
|
||||
(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);
|
||||
|
||||
if (data == 0 || datalen == 0)
|
||||
return;
|
||||
|
||||
/* configure the new prng key into the prng's instance of hmac */
|
||||
tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key));
|
||||
|
||||
/* 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, data, datalen);
|
||||
if (additional_data && additional_datalen)
|
||||
(void)tc_hmac_update(&prng->h, additional_data, additional_datalen);
|
||||
(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));
|
||||
|
||||
update(prng, personalization, plen, 0, 0);
|
||||
|
||||
/* 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, additional_input, additionallen);
|
||||
}
|
||||
} else {
|
||||
/* call update only for the seed */
|
||||
update(prng, seed, seedlen, 0, 0);
|
||||
}
|
||||
|
||||
/* ... 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) {
|
||||
/* configure the new prng key into the prng's instance of hmac */
|
||||
tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key));
|
||||
|
||||
/* 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, 0, 0, 0, 0);
|
||||
|
||||
return TC_CRYPTO_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/* 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 "sha256.h"
|
||||
#include "constants.h"
|
||||
#include "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;
|
||||
}
|
||||
@@ -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 "utils.h"
|
||||
#include "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;
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*****************************************************************************************
|
||||
*
|
||||
* @file utils.c
|
||||
*
|
||||
* @brief entry
|
||||
*
|
||||
* Copyright (C) Bouffalo Lab 2019
|
||||
*
|
||||
* History: 2019-11 crealted by Lanlan Gong @ Shanghai
|
||||
*
|
||||
*****************************************************************************************/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void reverse_bytearray(uint8_t *src, uint8_t *result, int array_size)
|
||||
{
|
||||
for (int i = 0; i < array_size; i++) {
|
||||
result[array_size - i - 1] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int find_msb_set(uint32_t data)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
uint32_t mask = 0x80000000;
|
||||
|
||||
if (!data) {
|
||||
return 0;
|
||||
}
|
||||
while ((data & mask) == 0) {
|
||||
count += 1u;
|
||||
mask = mask >> 1u;
|
||||
}
|
||||
return (32 - count);
|
||||
}
|
||||
|
||||
unsigned int find_lsb_set(uint32_t data)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
uint32_t mask = 0x00000001;
|
||||
|
||||
if (!data) {
|
||||
return 0;
|
||||
}
|
||||
while ((data & mask) == 0) {
|
||||
count += 1u;
|
||||
mask = mask << 1u;
|
||||
}
|
||||
return (1 + count);
|
||||
}
|
||||
|
||||
int char2hex(char c, uint8_t *x)
|
||||
{
|
||||
if (c >= '0' && c <= '9') {
|
||||
*x = c - '0';
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
*x = c - 'a' + 10;
|
||||
} else if (c >= 'A' && c <= 'F') {
|
||||
*x = c - 'A' + 10;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hex2char(uint8_t x, char *c)
|
||||
{
|
||||
if (x <= 9) {
|
||||
*c = x + '0';
|
||||
} else if (x <= 15) {
|
||||
*c = x - 10 + 'a';
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen)
|
||||
{
|
||||
if ((hexlen + 1) < buflen * 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < buflen; i++) {
|
||||
if (hex2char(buf[i] >> 4, &hex[2 * i]) < 0) {
|
||||
return 0;
|
||||
}
|
||||
if (hex2char(buf[i] & 0xf, &hex[2 * i + 1]) < 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
hex[2 * buflen] = '\0';
|
||||
return 2 * buflen;
|
||||
}
|
||||
|
||||
size_t hex2bin(const char *hex, size_t hexlen, uint8_t *buf, size_t buflen)
|
||||
{
|
||||
uint8_t dec;
|
||||
|
||||
if (buflen < hexlen / 2 + hexlen % 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if hexlen is uneven, insert leading zero nibble */
|
||||
if (hexlen % 2) {
|
||||
if (char2hex(hex[0], &dec) < 0) {
|
||||
return 0;
|
||||
}
|
||||
buf[0] = dec;
|
||||
hex++;
|
||||
buf++;
|
||||
}
|
||||
|
||||
/* regular hex conversion */
|
||||
for (size_t i = 0; i < hexlen / 2; i++) {
|
||||
if (char2hex(hex[2 * i], &dec) < 0) {
|
||||
return 0;
|
||||
}
|
||||
buf[i] = dec << 4;
|
||||
|
||||
if (char2hex(hex[2 * i + 1], &dec) < 0) {
|
||||
return 0;
|
||||
}
|
||||
buf[i] += dec;
|
||||
}
|
||||
|
||||
return hexlen / 2 + hexlen % 2;
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
* Copyright (c) 2016 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Workqueue support functions
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <log.h>
|
||||
#include "errno.h"
|
||||
|
||||
struct k_thread work_q_thread;
|
||||
#if !defined(BFLB_BLE)
|
||||
static BT_STACK_NOINIT(work_q_stack, CONFIG_BT_WORK_QUEUE_STACK_SIZE);
|
||||
#endif
|
||||
struct k_work_q g_work_queue_main;
|
||||
|
||||
static void k_work_submit_to_queue(struct k_work_q *work_q,
|
||||
struct k_work *work)
|
||||
{
|
||||
if (!atomic_test_and_set_bit(work->flags, K_WORK_STATE_PENDING)) {
|
||||
k_fifo_put(&work_q->fifo, work);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BFLB_BLE)
|
||||
static void work_queue_main(void *p1)
|
||||
{
|
||||
struct k_work *work;
|
||||
UNUSED(p1);
|
||||
|
||||
while (1) {
|
||||
work = k_fifo_get(&g_work_queue_main.fifo, K_FOREVER);
|
||||
|
||||
if (atomic_test_and_clear_bit(work->flags, K_WORK_STATE_PENDING)) {
|
||||
work->handler(work);
|
||||
}
|
||||
|
||||
k_yield();
|
||||
}
|
||||
}
|
||||
|
||||
int k_work_q_start(void)
|
||||
{
|
||||
k_fifo_init(&g_work_queue_main.fifo, 20);
|
||||
return k_thread_create(&work_q_thread, "work_q_thread",
|
||||
CONFIG_BT_WORK_QUEUE_STACK_SIZE,
|
||||
work_queue_main, CONFIG_BT_WORK_QUEUE_PRIO);
|
||||
}
|
||||
|
||||
int k_work_init(struct k_work *work, k_work_handler_t handler)
|
||||
{
|
||||
ASSERT(work, "work is NULL");
|
||||
|
||||
atomic_clear(work->flags);
|
||||
work->handler = handler;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void k_work_submit(struct k_work *work)
|
||||
{
|
||||
k_work_submit_to_queue(&g_work_queue_main, work);
|
||||
}
|
||||
|
||||
static void work_timeout(void *timer)
|
||||
{
|
||||
/* Parameter timer type is */
|
||||
struct k_delayed_work *w = (struct k_delayed_work *)k_timer_get_id(timer);
|
||||
if (w->work_q == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* submit work to workqueue */
|
||||
if (!atomic_test_bit(w->work.flags, K_WORK_STATE_PERIODIC)) {
|
||||
k_work_submit_to_queue(w->work_q, &w->work);
|
||||
/* detach from workqueue, for cancel to return appropriate status */
|
||||
w->work_q = NULL;
|
||||
} else {
|
||||
/* For periodic timer, restart it.*/
|
||||
k_timer_reset(&w->timer);
|
||||
k_work_submit_to_queue(w->work_q, &w->work);
|
||||
}
|
||||
}
|
||||
|
||||
void k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler)
|
||||
{
|
||||
ASSERT(work, "delay work is NULL");
|
||||
/* Added by bouffalolab */
|
||||
k_work_init(&work->work, handler);
|
||||
k_timer_init(&work->timer, work_timeout, work);
|
||||
work->work_q = NULL;
|
||||
}
|
||||
|
||||
static int k_delayed_work_submit_to_queue(struct k_work_q *work_q,
|
||||
struct k_delayed_work *work,
|
||||
uint32_t delay)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Work cannot be active in multiple queues */
|
||||
if (work->work_q && work->work_q != work_q) {
|
||||
err = -EADDRINUSE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Cancel if work has been submitted */
|
||||
if (work->work_q == work_q) {
|
||||
err = k_delayed_work_cancel(work);
|
||||
|
||||
if (err < 0) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (!delay) {
|
||||
/* Submit work if no ticks is 0 */
|
||||
k_work_submit_to_queue(work_q, &work->work);
|
||||
work->work_q = NULL;
|
||||
} else {
|
||||
/* Add timeout */
|
||||
/* Attach workqueue so the timeout callback can submit it */
|
||||
k_timer_start(&work->timer, delay);
|
||||
work->work_q = work_q;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
|
||||
int k_delayed_work_submit(struct k_delayed_work *work, uint32_t delay)
|
||||
{
|
||||
atomic_clear_bit(work->work.flags, K_WORK_STATE_PERIODIC);
|
||||
return k_delayed_work_submit_to_queue(&g_work_queue_main, work, delay);
|
||||
}
|
||||
|
||||
/* Added by bouffalolab */
|
||||
int k_delayed_work_submit_periodic(struct k_delayed_work *work, s32_t period)
|
||||
{
|
||||
atomic_set_bit(work->work.flags, K_WORK_STATE_PERIODIC);
|
||||
return k_delayed_work_submit_to_queue(&g_work_queue_main, work, period);
|
||||
}
|
||||
|
||||
int k_delayed_work_cancel(struct k_delayed_work *work)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (atomic_test_bit(work->work.flags, K_WORK_STATE_PENDING)) {
|
||||
err = -EINPROGRESS;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!work->work_q) {
|
||||
err = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
k_timer_stop(&work->timer);
|
||||
work->work_q = NULL;
|
||||
work->timer.timeout = 0;
|
||||
work->timer.start_ms = 0;
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
s32_t k_delayed_work_remaining_get(struct k_delayed_work *work)
|
||||
{
|
||||
int32_t remain;
|
||||
k_timer_t *timer;
|
||||
|
||||
if (work == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
timer = &work->timer;
|
||||
remain = timer->timeout - (k_now_ms() - timer->start_ms);
|
||||
if (remain < 0) {
|
||||
remain = 0;
|
||||
}
|
||||
return remain;
|
||||
}
|
||||
|
||||
void k_delayed_work_del_timer(struct k_delayed_work *work)
|
||||
{
|
||||
if (NULL == work || NULL == work->timer.timer.hdl)
|
||||
return;
|
||||
|
||||
k_timer_delete(&work->timer);
|
||||
work->timer.timer.hdl = NULL;
|
||||
}
|
||||
|
||||
/* Added by bouffalolab */
|
||||
int k_delayed_work_free(struct k_delayed_work *work)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (atomic_test_bit(work->work.flags, K_WORK_STATE_PENDING)) {
|
||||
err = -EINPROGRESS;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
k_delayed_work_del_timer(work);
|
||||
work->work_q = NULL;
|
||||
work->timer.timeout = 0;
|
||||
work->timer.start_ms = 0;
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
#else
|
||||
static void work_q_main(void *work_q_ptr, void *p2, void *p3)
|
||||
{
|
||||
struct k_work_q *work_q = work_q_ptr;
|
||||
|
||||
ARG_UNUSED(p2);
|
||||
ARG_UNUSED(p3);
|
||||
|
||||
while (1) {
|
||||
struct k_work *work;
|
||||
k_work_handler_t handler;
|
||||
|
||||
work = k_queue_get(&work_q->queue, K_FOREVER);
|
||||
if (!work) {
|
||||
continue;
|
||||
}
|
||||
|
||||
handler = work->handler;
|
||||
|
||||
/* Reset pending state so it can be resubmitted by handler */
|
||||
if (atomic_test_and_clear_bit(work->flags,
|
||||
K_WORK_STATE_PENDING)) {
|
||||
handler(work);
|
||||
}
|
||||
|
||||
/* Make sure we don't hog up the CPU if the FIFO never (or
|
||||
* very rarely) gets empty.
|
||||
*/
|
||||
k_yield();
|
||||
}
|
||||
}
|
||||
|
||||
void k_work_q_start(struct k_work_q *work_q, k_thread_stack_t *stack,
|
||||
size_t stack_size, int prio)
|
||||
{
|
||||
k_queue_init(&work_q->queue, 20);
|
||||
k_thread_create(&work_q->thread, stack, stack_size, work_q_main,
|
||||
work_q, 0, 0, prio, 0, 0);
|
||||
_k_object_init(work_q);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_CLOCK_EXISTS
|
||||
static void work_timeout(struct _timeout *t)
|
||||
{
|
||||
struct k_delayed_work *w = CONTAINER_OF(t, struct k_delayed_work,
|
||||
timeout);
|
||||
|
||||
/* submit work to workqueue */
|
||||
k_work_submit_to_queue(w->work_q, &w->work);
|
||||
}
|
||||
|
||||
void k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler)
|
||||
{
|
||||
k_work_init(&work->work, handler);
|
||||
_init_timeout(&work->timeout, work_timeout);
|
||||
work->work_q = NULL;
|
||||
|
||||
_k_object_init(work);
|
||||
}
|
||||
|
||||
int k_delayed_work_submit_to_queue(struct k_work_q *work_q,
|
||||
struct k_delayed_work *work,
|
||||
s32_t delay)
|
||||
{
|
||||
unsigned int key = irq_lock();
|
||||
int err;
|
||||
|
||||
/* Work cannot be active in multiple queues */
|
||||
if (work->work_q && work->work_q != work_q) {
|
||||
err = -EADDRINUSE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Cancel if work has been submitted */
|
||||
if (work->work_q == work_q) {
|
||||
err = k_delayed_work_cancel(work);
|
||||
if (err < 0) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Attach workqueue so the timeout callback can submit it */
|
||||
work->work_q = work_q;
|
||||
|
||||
if (!delay) {
|
||||
/* Submit work if no ticks is 0 */
|
||||
k_work_submit_to_queue(work_q, &work->work);
|
||||
} else {
|
||||
/* Add timeout */
|
||||
_add_timeout(NULL, &work->timeout, NULL,
|
||||
_TICK_ALIGN + _ms_to_ticks(delay));
|
||||
}
|
||||
|
||||
err = 0;
|
||||
|
||||
done:
|
||||
irq_unlock(key);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int k_delayed_work_cancel(struct k_delayed_work *work)
|
||||
{
|
||||
unsigned int key = irq_lock();
|
||||
|
||||
if (!work->work_q) {
|
||||
irq_unlock(key);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (k_work_pending(&work->work)) {
|
||||
/* Remove from the queue if already submitted */
|
||||
if (!k_queue_remove(&work->work_q->queue, &work->work)) {
|
||||
irq_unlock(key);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
_abort_timeout(&work->timeout);
|
||||
}
|
||||
|
||||
/* Detach from workqueue */
|
||||
work->work_q = NULL;
|
||||
|
||||
atomic_clear_bit(work->work.flags, K_WORK_STATE_PENDING);
|
||||
irq_unlock(key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SYS_CLOCK_EXISTS */
|
||||
#endif /* BFLB_BLE */
|
||||
@@ -0,0 +1,560 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <zephyr.h>
|
||||
//#include <soc.h>
|
||||
//#include <init.h>
|
||||
//#include <device.h>
|
||||
//#include <clock_control.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <include/atomic.h>
|
||||
|
||||
#include <misc/util.h>
|
||||
#include <misc/stack.h>
|
||||
#include <misc/byteorder.h>
|
||||
|
||||
#include <bluetooth.h>
|
||||
#include <hci_host.h>
|
||||
#include <hci_driver.h>
|
||||
|
||||
#ifdef CONFIG_CLOCK_CONTROL_NRF5
|
||||
#include <drivers/clock_control/nrf5_clock_control.h>
|
||||
#endif
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
||||
#include "log.h"
|
||||
|
||||
//#include "util/util.h"
|
||||
//#include "hal/ccm.h"
|
||||
//#include "hal/radio.h"
|
||||
//#include "ll_sw/pdu.h"
|
||||
//#include "ll_sw/ctrl.h"
|
||||
#include "hci_internal.h"
|
||||
//#include "init.h"
|
||||
//#include "hal/debug.h"
|
||||
#if defined(BFLB_BLE)
|
||||
#include "bl_hci_wrapper.h"
|
||||
#endif
|
||||
|
||||
#define NODE_RX(_node) CONTAINER_OF(_node, struct radio_pdu_node_rx, \
|
||||
hdr.onion.node)
|
||||
|
||||
#if !defined(BFLB_BLE)
|
||||
static K_SEM_DEFINE(sem_prio_recv, 0, BT_UINT_MAX);
|
||||
#endif
|
||||
|
||||
K_FIFO_DEFINE(recv_fifo);
|
||||
#if (BFLB_BLE_CO_THREAD)
|
||||
extern struct k_sem g_poll_sem;
|
||||
static int recv_fifo_count = 0;
|
||||
#endif
|
||||
|
||||
#if !defined(BFLB_BLE)
|
||||
struct k_thread prio_recv_thread_data;
|
||||
static BT_STACK_NOINIT(prio_recv_thread_stack,
|
||||
CONFIG_BT_CTLR_RX_PRIO_STACK_SIZE);
|
||||
#endif
|
||||
|
||||
struct k_thread recv_thread_data;
|
||||
#if !defined(BFLB_BLE)
|
||||
static BT_STACK_NOINIT(recv_thread_stack, CONFIG_BT_RX_STACK_SIZE);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_INIT_STACKS)
|
||||
static u32_t prio_ts;
|
||||
static u32_t rx_ts;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
static struct k_poll_signal hbuf_signal =
|
||||
K_POLL_SIGNAL_INITIALIZER(hbuf_signal);
|
||||
static sys_slist_t hbuf_pend;
|
||||
static s32_t hbuf_count;
|
||||
#endif
|
||||
|
||||
#if !defined(BFLB_BLE)
|
||||
static void prio_recv_thread(void *p1, void *p2, void *p3)
|
||||
{
|
||||
while (1) {
|
||||
struct radio_pdu_node_rx *node_rx;
|
||||
u8_t num_cmplt;
|
||||
u16_t handle;
|
||||
|
||||
while ((num_cmplt = radio_rx_get(&node_rx, &handle))) {
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
struct net_buf *buf;
|
||||
|
||||
buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER);
|
||||
hci_num_cmplt_encode(buf, handle, num_cmplt);
|
||||
BT_DBG("Num Complete: 0x%04x:%u", handle, num_cmplt);
|
||||
bt_recv_prio(buf);
|
||||
k_yield();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (node_rx) {
|
||||
radio_rx_dequeue();
|
||||
|
||||
BT_DBG("RX node enqueue");
|
||||
k_fifo_put(&recv_fifo, node_rx);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
BT_DBG("sem take...");
|
||||
k_sem_take(&sem_prio_recv, K_FOREVER);
|
||||
BT_DBG("sem taken");
|
||||
|
||||
#if defined(CONFIG_INIT_STACKS)
|
||||
if (k_uptime_get_32() - prio_ts > K_SECONDS(5)) {
|
||||
STACK_ANALYZE("prio recv thread stack",
|
||||
prio_recv_thread_stack);
|
||||
prio_ts = k_uptime_get_32();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct net_buf *encode_node(struct radio_pdu_node_rx *node_rx,
|
||||
s8_t class)
|
||||
{
|
||||
struct net_buf *buf = NULL;
|
||||
|
||||
/* Check if we need to generate an HCI event or ACL data */
|
||||
switch (class) {
|
||||
case HCI_CLASS_EVT_DISCARDABLE:
|
||||
case HCI_CLASS_EVT_REQUIRED:
|
||||
case HCI_CLASS_EVT_CONNECTION:
|
||||
if (class == HCI_CLASS_EVT_DISCARDABLE) {
|
||||
buf = bt_buf_get_rx(BT_BUF_EVT, K_NO_WAIT);
|
||||
} else {
|
||||
buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER);
|
||||
}
|
||||
if (buf) {
|
||||
hci_evt_encode(node_rx, buf);
|
||||
}
|
||||
break;
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
case HCI_CLASS_ACL_DATA:
|
||||
/* generate ACL data */
|
||||
buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER);
|
||||
hci_acl_encode(node_rx, buf);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
LL_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
radio_rx_fc_set(node_rx->hdr.handle, 0);
|
||||
node_rx->hdr.onion.next = 0;
|
||||
radio_rx_mem_release(&node_rx);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static inline struct net_buf *process_node(struct radio_pdu_node_rx *node_rx)
|
||||
{
|
||||
s8_t class = hci_get_class(node_rx);
|
||||
struct net_buf *buf = NULL;
|
||||
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
if (hbuf_count != -1) {
|
||||
bool pend = !sys_slist_is_empty(&hbuf_pend);
|
||||
|
||||
/* controller to host flow control enabled */
|
||||
switch (class) {
|
||||
case HCI_CLASS_EVT_DISCARDABLE:
|
||||
case HCI_CLASS_EVT_REQUIRED:
|
||||
break;
|
||||
case HCI_CLASS_EVT_CONNECTION:
|
||||
/* for conn-related events, only pend is relevant */
|
||||
hbuf_count = 1;
|
||||
/* fallthrough */
|
||||
case HCI_CLASS_ACL_DATA:
|
||||
if (pend || !hbuf_count) {
|
||||
sys_slist_append(&hbuf_pend,
|
||||
&node_rx->hdr.onion.node);
|
||||
BT_DBG("FC: Queuing item: %d", class);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LL_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* process regular node from radio */
|
||||
buf = encode_node(node_rx, class);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
static inline struct net_buf *process_hbuf(struct radio_pdu_node_rx *n)
|
||||
{
|
||||
/* shadow total count in case of preemption */
|
||||
struct radio_pdu_node_rx *node_rx = NULL;
|
||||
s32_t hbuf_total = hci_hbuf_total;
|
||||
struct net_buf *buf = NULL;
|
||||
sys_snode_t *node = NULL;
|
||||
s8_t class;
|
||||
int reset;
|
||||
|
||||
reset = atomic_test_and_clear_bit(&hci_state_mask, HCI_STATE_BIT_RESET);
|
||||
if (reset) {
|
||||
/* flush queue, no need to free, the LL has already done it */
|
||||
sys_slist_init(&hbuf_pend);
|
||||
}
|
||||
|
||||
if (hbuf_total <= 0) {
|
||||
hbuf_count = -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* available host buffers */
|
||||
hbuf_count = hbuf_total - (hci_hbuf_sent - hci_hbuf_acked);
|
||||
|
||||
/* host acked ACL packets, try to dequeue from hbuf */
|
||||
node = sys_slist_peek_head(&hbuf_pend);
|
||||
if (!node) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return early if this iteration already has a node to process */
|
||||
node_rx = NODE_RX(node);
|
||||
class = hci_get_class(node_rx);
|
||||
if (n) {
|
||||
if (class == HCI_CLASS_EVT_CONNECTION ||
|
||||
(class == HCI_CLASS_ACL_DATA && hbuf_count)) {
|
||||
/* node to process later, schedule an iteration */
|
||||
BT_DBG("FC: signalling");
|
||||
k_poll_signal_raise(&hbuf_signal, 0x0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (class) {
|
||||
case HCI_CLASS_EVT_CONNECTION:
|
||||
BT_DBG("FC: dequeueing event");
|
||||
(void)sys_slist_get(&hbuf_pend);
|
||||
break;
|
||||
case HCI_CLASS_ACL_DATA:
|
||||
if (hbuf_count) {
|
||||
BT_DBG("FC: dequeueing ACL data");
|
||||
(void)sys_slist_get(&hbuf_pend);
|
||||
} else {
|
||||
/* no buffers, HCI will signal */
|
||||
node = NULL;
|
||||
}
|
||||
break;
|
||||
case HCI_CLASS_EVT_DISCARDABLE:
|
||||
case HCI_CLASS_EVT_REQUIRED:
|
||||
default:
|
||||
LL_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
buf = encode_node(node_rx, class);
|
||||
/* Update host buffers after encoding */
|
||||
hbuf_count = hbuf_total - (hci_hbuf_sent - hci_hbuf_acked);
|
||||
/* next node */
|
||||
node = sys_slist_peek_head(&hbuf_pend);
|
||||
if (node) {
|
||||
node_rx = NODE_RX(node);
|
||||
class = hci_get_class(node_rx);
|
||||
|
||||
if (class == HCI_CLASS_EVT_CONNECTION ||
|
||||
(class == HCI_CLASS_ACL_DATA && hbuf_count)) {
|
||||
/* more to process, schedule an
|
||||
* iteration
|
||||
*/
|
||||
BT_DBG("FC: signalling");
|
||||
k_poll_signal_raise(&hbuf_signal, 0x0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(BFLB_BLE)
|
||||
#if (BFLB_BLE_CO_THREAD)
|
||||
void co_rx_thread()
|
||||
{
|
||||
struct net_buf *buf = NULL;
|
||||
buf = net_buf_get(&recv_fifo, K_NO_WAIT);
|
||||
if (buf) {
|
||||
BT_DBG("Calling bt_recv(%p)", buf);
|
||||
bt_recv(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void co_tx_rx_thread(void *p1)
|
||||
{
|
||||
UNUSED(p1);
|
||||
BT_DBG("using %s\n", __func__);
|
||||
while (1) {
|
||||
if (k_sem_count_get(&g_poll_sem) > 0) {
|
||||
co_tx_thread();
|
||||
}
|
||||
|
||||
if (recv_fifo_count > 0) {
|
||||
recv_fifo_count--;
|
||||
co_rx_thread();
|
||||
}
|
||||
|
||||
k_sleep(portTICK_PERIOD_MS);
|
||||
k_yield();
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
static void recv_thread(void *p1)
|
||||
{
|
||||
UNUSED(p1);
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
/* @todo: check if the events structure really needs to be static */
|
||||
static struct k_poll_event events[2] = {
|
||||
K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SIGNAL,
|
||||
K_POLL_MODE_NOTIFY_ONLY,
|
||||
&hbuf_signal, 0),
|
||||
K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE,
|
||||
K_POLL_MODE_NOTIFY_ONLY,
|
||||
&recv_fifo, 0),
|
||||
};
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
#if defined(BFLB_BLE)
|
||||
struct net_buf *buf = NULL;
|
||||
buf = net_buf_get(&recv_fifo, K_FOREVER);
|
||||
if (buf) {
|
||||
BT_DBG("Calling bt_recv(%p)", buf);
|
||||
bt_recv(buf);
|
||||
}
|
||||
#else
|
||||
struct radio_pdu_node_rx *node_rx = NULL;
|
||||
struct net_buf *buf = NULL;
|
||||
|
||||
BT_DBG("blocking");
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
int err;
|
||||
|
||||
err = k_poll(events, 2, K_FOREVER);
|
||||
LL_ASSERT(err == 0);
|
||||
if (events[0].state == K_POLL_STATE_SIGNALED) {
|
||||
events[0].signal->signaled = 0;
|
||||
} else if (events[1].state ==
|
||||
K_POLL_STATE_FIFO_DATA_AVAILABLE) {
|
||||
node_rx = k_fifo_get(events[1].fifo, 0);
|
||||
}
|
||||
|
||||
events[0].state = K_POLL_STATE_NOT_READY;
|
||||
events[1].state = K_POLL_STATE_NOT_READY;
|
||||
|
||||
/* process host buffers first if any */
|
||||
buf = process_hbuf(node_rx);
|
||||
|
||||
#else
|
||||
node_rx = k_fifo_get(&recv_fifo, K_FOREVER);
|
||||
#endif
|
||||
BT_DBG("unblocked");
|
||||
|
||||
if (node_rx && !buf) {
|
||||
/* process regular node from radio */
|
||||
buf = process_node(node_rx);
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
if (buf->len) {
|
||||
BT_DBG("Packet in: type:%u len:%u",
|
||||
bt_buf_get_type(buf), buf->len);
|
||||
bt_recv(buf);
|
||||
} else {
|
||||
net_buf_unref(buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
k_yield();
|
||||
|
||||
#if defined(CONFIG_INIT_STACKS)
|
||||
if (k_uptime_get_32() - rx_ts > K_SECONDS(5)) {
|
||||
STACK_ANALYZE("recv thread stack", recv_thread_stack);
|
||||
rx_ts = k_uptime_get_32();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(BFLB_BLE)
|
||||
static int cmd_handle(struct net_buf *buf)
|
||||
{
|
||||
struct net_buf *evt;
|
||||
|
||||
evt = hci_cmd_handle(buf);
|
||||
if (evt) {
|
||||
BT_DBG("Replying with event of %u bytes", evt->len);
|
||||
bt_recv_prio(evt);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
static int acl_handle(struct net_buf *buf)
|
||||
{
|
||||
struct net_buf *evt;
|
||||
int err;
|
||||
|
||||
err = hci_acl_handle(buf, &evt);
|
||||
if (evt) {
|
||||
BT_DBG("Replying with event of %u bytes", evt->len);
|
||||
bt_recv_prio(evt);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_CONN */
|
||||
#endif
|
||||
|
||||
static int hci_driver_send(struct net_buf *buf)
|
||||
{
|
||||
#if !defined(BFLB_BLE)
|
||||
u8_t type;
|
||||
#endif
|
||||
int err;
|
||||
|
||||
BT_DBG("enter");
|
||||
|
||||
if (!buf->len) {
|
||||
BT_ERR("Empty HCI packet");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if defined(BFLB_BLE)
|
||||
err = bl_onchiphci_send_2_controller(buf);
|
||||
net_buf_unref(buf);
|
||||
return err;
|
||||
#else
|
||||
type = bt_buf_get_type(buf);
|
||||
switch (type) {
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
case BT_BUF_ACL_OUT:
|
||||
err = acl_handle(buf);
|
||||
break;
|
||||
#endif /* CONFIG_BT_CONN */
|
||||
case BT_BUF_CMD:
|
||||
err = cmd_handle(buf);
|
||||
|
||||
break;
|
||||
default:
|
||||
BT_ERR("Unknown HCI type %u", type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
net_buf_unref(buf);
|
||||
} else {
|
||||
}
|
||||
|
||||
BT_DBG("exit: %d", err);
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
static int hci_driver_open(void)
|
||||
{
|
||||
#if !defined(BFLB_BLE)
|
||||
u32_t err;
|
||||
|
||||
DEBUG_INIT();
|
||||
k_sem_init(&sem_prio_recv, 0, BT_UINT_MAX);
|
||||
|
||||
err = ll_init(&sem_prio_recv);
|
||||
|
||||
if (err) {
|
||||
BT_ERR("LL initialization failed: %u", err);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(BFLB_BLE)
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
hci_init(&hbuf_signal);
|
||||
#else
|
||||
hci_init(NULL);
|
||||
#endif
|
||||
#endif
|
||||
k_fifo_init(&recv_fifo, 20);
|
||||
|
||||
#if defined(BFLB_BLE)
|
||||
#if (BFLB_BLE_CO_THREAD)
|
||||
k_thread_create(&recv_thread_data, "co_tx_rx_thread",
|
||||
CONFIG_BT_RX_STACK_SIZE,
|
||||
co_tx_rx_thread,
|
||||
K_PRIO_COOP(CONFIG_BT_RX_PRIO));
|
||||
#else
|
||||
k_thread_create(&recv_thread_data, "recv_thread",
|
||||
CONFIG_BT_RX_STACK_SIZE /*K_THREAD_STACK_SIZEOF(recv_thread_stack)*/,
|
||||
recv_thread,
|
||||
K_PRIO_COOP(CONFIG_BT_RX_PRIO));
|
||||
#endif
|
||||
#else
|
||||
k_thread_create(&prio_recv_thread_data, prio_recv_thread_stack,
|
||||
K_THREAD_STACK_SIZEOF(prio_recv_thread_stack),
|
||||
prio_recv_thread, NULL, NULL, NULL,
|
||||
K_PRIO_COOP(CONFIG_BT_CTLR_RX_PRIO), 0, K_NO_WAIT);
|
||||
#endif
|
||||
|
||||
BT_DBG("Success.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hci_driver_enque_recvq(struct net_buf *buf)
|
||||
{
|
||||
net_buf_put(&recv_fifo, buf);
|
||||
#if (BFLB_BLE_CO_THREAD)
|
||||
recv_fifo_count++;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const struct bt_hci_driver drv = {
|
||||
.name = "Controller",
|
||||
.bus = BT_HCI_DRIVER_BUS_VIRTUAL,
|
||||
.open = hci_driver_open,
|
||||
.send = hci_driver_send,
|
||||
};
|
||||
|
||||
#if defined(BFLB_BLE)
|
||||
int hci_driver_init(void)
|
||||
{
|
||||
bt_hci_driver_register(&drv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int _hci_driver_init(struct device *unused)
|
||||
{
|
||||
ARG_UNUSED(unused);
|
||||
|
||||
bt_hci_driver_register(&drv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
//SYS_INIT(_hci_driver_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _HCI_CONTROLLER_H_
|
||||
#define _HCI_CONTROLLER_H_
|
||||
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
extern s32_t hci_hbuf_total;
|
||||
extern u32_t hci_hbuf_sent;
|
||||
extern u32_t hci_hbuf_acked;
|
||||
extern atomic_t hci_state_mask;
|
||||
|
||||
#define HCI_STATE_BIT_RESET 0
|
||||
#endif
|
||||
|
||||
#define HCI_CLASS_EVT_REQUIRED 0
|
||||
#define HCI_CLASS_EVT_DISCARDABLE 1
|
||||
#define HCI_CLASS_EVT_CONNECTION 2
|
||||
#define HCI_CLASS_ACL_DATA 3
|
||||
|
||||
#if defined(CONFIG_SOC_FAMILY_NRF5)
|
||||
#define BT_HCI_VS_HW_PLAT BT_HCI_VS_HW_PLAT_NORDIC
|
||||
#if defined(CONFIG_SOC_SERIES_NRF51X)
|
||||
#define BT_HCI_VS_HW_VAR BT_HCI_VS_HW_VAR_NORDIC_NRF51X;
|
||||
#elif defined(CONFIG_SOC_SERIES_NRF52X)
|
||||
#define BT_HCI_VS_HW_VAR BT_HCI_VS_HW_VAR_NORDIC_NRF52X;
|
||||
#endif
|
||||
#else
|
||||
#define BT_HCI_VS_HW_PLAT 0
|
||||
#define BT_HCI_VS_HW_VAR 0
|
||||
#endif /* CONFIG_SOC_FAMILY_NRF5 */
|
||||
|
||||
void hci_init(struct k_poll_signal *signal_host_buf);
|
||||
struct net_buf *hci_cmd_handle(struct net_buf *cmd);
|
||||
#if !defined(BFLB_BLE)
|
||||
void hci_evt_encode(struct radio_pdu_node_rx *node_rx, struct net_buf *buf);
|
||||
s8_t hci_get_class(struct radio_pdu_node_rx *node_rx);
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
int hci_acl_handle(struct net_buf *acl, struct net_buf **evt);
|
||||
void hci_acl_encode(struct radio_pdu_node_rx *node_rx, struct net_buf *buf);
|
||||
void hci_num_cmplt_encode(struct net_buf *buf, u16_t handle, u8_t num);
|
||||
#endif
|
||||
#endif //!defined(BFLB_BLE)
|
||||
#endif /* _HCI_CONTROLLER_H_ */
|
||||
@@ -0,0 +1,343 @@
|
||||
/** @file
|
||||
* @brief Advance Audio Distribution Profile.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <atomic.h>
|
||||
#include <byteorder.h>
|
||||
#include <util.h>
|
||||
#include <printk.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <bluetooth.h>
|
||||
#include <l2cap.h>
|
||||
#include <avdtp.h>
|
||||
#include <a2dp.h>
|
||||
#include <sdp.h>
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_A2DP)
|
||||
#define LOG_MODULE_NAME bt_a2dp
|
||||
#include "log.h"
|
||||
|
||||
#include "hci_core.h"
|
||||
#include "conn_internal.h"
|
||||
#include "avdtp_internal.h"
|
||||
#include "a2dp_internal.h"
|
||||
#include "a2dp-codec.h"
|
||||
#include "oi_codec_sbc.h"
|
||||
|
||||
#define A2DP_NO_SPACE (-1)
|
||||
|
||||
struct bt_a2dp {
|
||||
struct bt_avdtp session;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
OI_CODEC_SBC_DECODER_CONTEXT decoder_context;
|
||||
uint32_t context_data[CODEC_DATA_WORDS(SBC_MAX_CHANNELS, SBC_CODEC_FAST_FILTER_BUFFERS)];
|
||||
int16_t decode_buf[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];
|
||||
} A2DP_SBC_DECODER;
|
||||
|
||||
static A2DP_SBC_DECODER sbc_decoder;
|
||||
|
||||
/* Connections */
|
||||
static struct bt_a2dp connection[CONFIG_BT_MAX_CONN];
|
||||
static struct bt_avdtp_stream stream[CONFIG_BT_MAX_CONN];
|
||||
|
||||
static struct bt_sdp_attribute a2dp_attrs[] = {
|
||||
BT_SDP_NEW_SERVICE,
|
||||
BT_SDP_LIST(
|
||||
BT_SDP_ATTR_SVCLASS_ID_LIST,
|
||||
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
|
||||
BT_SDP_DATA_ELEM_LIST(
|
||||
{ BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
|
||||
BT_SDP_ARRAY_16(BT_SDP_AUDIO_SINK_SVCLASS) }, )),
|
||||
BT_SDP_LIST(
|
||||
BT_SDP_ATTR_PROTO_DESC_LIST,
|
||||
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 16),
|
||||
BT_SDP_DATA_ELEM_LIST(
|
||||
{ BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
|
||||
BT_SDP_DATA_ELEM_LIST(
|
||||
{ BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
|
||||
BT_SDP_ARRAY_16(BT_SDP_PROTO_L2CAP) },
|
||||
{ BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
|
||||
BT_SDP_ARRAY_16(BT_L2CAP_PSM_AVDTP) }, ) },
|
||||
{ BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
|
||||
BT_SDP_DATA_ELEM_LIST(
|
||||
{ BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
|
||||
BT_SDP_ARRAY_16(BT_L2CAP_PSM_AVDTP) },
|
||||
{ BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
|
||||
BT_SDP_ARRAY_16(0x0102) }, ) }, )),
|
||||
BT_SDP_LIST(
|
||||
BT_SDP_ATTR_PROFILE_DESC_LIST,
|
||||
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 8),
|
||||
BT_SDP_DATA_ELEM_LIST(
|
||||
{ BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
|
||||
BT_SDP_DATA_ELEM_LIST(
|
||||
{ BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
|
||||
BT_SDP_ARRAY_16(BT_SDP_ADVANCED_AUDIO_SVCLASS) },
|
||||
{ BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
|
||||
BT_SDP_ARRAY_16(0x0102) }, ) }, )),
|
||||
BT_SDP_SERVICE_NAME("A2DP sink"),
|
||||
};
|
||||
|
||||
static struct bt_sdp_record a2dp_rec = BT_SDP_RECORD(a2dp_attrs);
|
||||
|
||||
struct bt_a2dp_endpoint endpoint_1;
|
||||
struct bt_a2dp_endpoint endpoint_2;
|
||||
|
||||
struct bt_a2dp_codec_sbc_params sbc_info;
|
||||
|
||||
void bt_a2dp_set_sbc_codec_info()
|
||||
{
|
||||
sbc_info.config[0] =
|
||||
//Sampling Frequency
|
||||
A2DP_SBC_SAMP_FREQ_48000 |
|
||||
A2DP_SBC_SAMP_FREQ_44100 |
|
||||
A2DP_SBC_SAMP_FREQ_32000 |
|
||||
A2DP_SBC_SAMP_FREQ_16000 |
|
||||
//Channel Mode
|
||||
A2DP_SBC_CH_MODE_JOINT |
|
||||
A2DP_SBC_CH_MODE_STREO |
|
||||
A2DP_SBC_CH_MODE_DUAL |
|
||||
A2DP_SBC_CH_MODE_MONO;
|
||||
sbc_info.config[1] =
|
||||
//Block Length
|
||||
A2DP_SBC_BLK_LEN_16 |
|
||||
A2DP_SBC_BLK_LEN_12 |
|
||||
A2DP_SBC_BLK_LEN_8 |
|
||||
A2DP_SBC_BLK_LEN_4 |
|
||||
//Subbands
|
||||
A2DP_SBC_SUBBAND_8 |
|
||||
A2DP_SBC_SUBBAND_4 |
|
||||
//Allocation Method
|
||||
A2DP_SBC_ALLOC_MTHD_SNR |
|
||||
A2DP_SBC_ALLOC_MTHD_LOUDNESS;
|
||||
sbc_info.min_bitpool = 2;
|
||||
sbc_info.max_bitpool = 53;
|
||||
}
|
||||
|
||||
void a2d_reset(struct bt_a2dp *a2dp_conn)
|
||||
{
|
||||
(void)memset(a2dp_conn, 0, sizeof(struct bt_a2dp));
|
||||
}
|
||||
|
||||
void stream_reset(struct bt_avdtp_stream *stream_conn)
|
||||
{
|
||||
(void)memset(stream_conn, 0, sizeof(struct bt_avdtp_stream));
|
||||
}
|
||||
|
||||
struct bt_a2dp *get_new_connection(struct bt_conn *conn)
|
||||
{
|
||||
int8_t i, free;
|
||||
|
||||
free = A2DP_NO_SPACE;
|
||||
|
||||
if (!conn) {
|
||||
BT_ERR("Invalid Input (err: %d)", -EINVAL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find a space */
|
||||
for (i = 0; i < CONFIG_BT_MAX_CONN; i++) {
|
||||
if (connection[i].session.br_chan.chan.conn == conn) {
|
||||
BT_DBG("Conn already exists");
|
||||
if (!connection[i].session.streams->chan.chan.conn) {
|
||||
BT_DBG("Create AV stream");
|
||||
return &connection[i];
|
||||
} else {
|
||||
BT_DBG("A2DP signal stream and AV stream already exists");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!connection[i].session.br_chan.chan.conn &&
|
||||
free == A2DP_NO_SPACE) {
|
||||
BT_DBG("Create signal stream");
|
||||
free = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (free == A2DP_NO_SPACE) {
|
||||
BT_DBG("More connection cannot be supported");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Clean the memory area before returning */
|
||||
a2d_reset(&connection[free]);
|
||||
stream_reset(&stream[free]);
|
||||
connection[free].session.streams = &stream[free];
|
||||
|
||||
return &connection[free];
|
||||
}
|
||||
|
||||
int a2dp_accept(struct bt_conn *conn, struct bt_avdtp **session)
|
||||
{
|
||||
struct bt_a2dp *a2dp_conn;
|
||||
|
||||
a2dp_conn = get_new_connection(conn);
|
||||
if (!a2dp_conn) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*session = &(a2dp_conn->session);
|
||||
BT_DBG("session: %p", &(a2dp_conn->session));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int a2dp_sbc_decode_init()
|
||||
{
|
||||
OI_STATUS status = OI_CODEC_SBC_DecoderReset(&sbc_decoder.decoder_context,
|
||||
sbc_decoder.context_data,
|
||||
sizeof(sbc_decoder.context_data),
|
||||
2,
|
||||
2,
|
||||
false,
|
||||
false);
|
||||
if (!OI_SUCCESS(status)) {
|
||||
BT_ERR("decode init failed with error: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if PCM_PRINTF
|
||||
extern int16_t cool_edit[];
|
||||
extern uint32_t byte_index;
|
||||
#endif
|
||||
int a2dp_sbc_decode_process(uint8_t media_data[], uint16_t data_len)
|
||||
{
|
||||
//remove media header, expose sbc frame
|
||||
const OI_BYTE *data = media_data + 12 + 1;
|
||||
OI_UINT32 data_size = data_len - 12 - 1;
|
||||
|
||||
if (data_size <= 0) {
|
||||
BT_ERR("empty packet\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] != 0x9c) {
|
||||
BT_ERR("sbc frame syncword error \n");
|
||||
}
|
||||
|
||||
OI_INT16 *pcm = sbc_decoder.decode_buf;
|
||||
OI_UINT32 pcm_size = sizeof(sbc_decoder.decode_buf);
|
||||
|
||||
OI_INT16 frame_count = OI_CODEC_SBC_FrameCount((OI_BYTE *)data, data_size);
|
||||
BT_DBG("frame_count: %d\n", frame_count);
|
||||
|
||||
for (int i = 0; i < frame_count; i++) {
|
||||
OI_STATUS status = OI_CODEC_SBC_DecodeFrame(&sbc_decoder.decoder_context,
|
||||
&data,
|
||||
&data_size,
|
||||
pcm,
|
||||
&pcm_size);
|
||||
if (!OI_SUCCESS(status)) {
|
||||
BT_ERR("decoding failure with error: %d \n", status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if PCM_PRINTF
|
||||
memcpy((OI_INT8 *)cool_edit + byte_index, pcm, pcm_size);
|
||||
byte_index += pcm_size;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Callback for incoming requests */
|
||||
static struct bt_avdtp_ind_cb cb_ind = {
|
||||
/*TODO*/
|
||||
};
|
||||
|
||||
/* The above callback structures need to be packed and passed to AVDTP */
|
||||
static struct bt_avdtp_event_cb avdtp_cb = {
|
||||
.ind = &cb_ind,
|
||||
.accept = a2dp_accept
|
||||
};
|
||||
|
||||
int bt_a2dp_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Register event handlers with AVDTP */
|
||||
err = bt_avdtp_register(&avdtp_cb);
|
||||
if (err < 0) {
|
||||
BT_ERR("A2DP registration failed");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Register SDP record */
|
||||
err = bt_sdp_register_service(&a2dp_rec);
|
||||
if (err < 0) {
|
||||
BT_ERR("A2DP regist sdp record failed");
|
||||
return err;
|
||||
}
|
||||
|
||||
int reg_1 = bt_a2dp_register_endpoint(&endpoint_1, BT_A2DP_AUDIO, BT_A2DP_SINK);
|
||||
int reg_2 = bt_a2dp_register_endpoint(&endpoint_2, BT_A2DP_AUDIO, BT_A2DP_SINK);
|
||||
if (reg_1 || reg_2) {
|
||||
BT_ERR("A2DP registration endpoint 1 failed");
|
||||
return err;
|
||||
}
|
||||
|
||||
bt_a2dp_set_sbc_codec_info();
|
||||
|
||||
err = a2dp_sbc_decode_init();
|
||||
if (err < 0) {
|
||||
BT_ERR("sbc codec init failed");
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_DBG("A2DP Initialized successfully.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct bt_a2dp *bt_a2dp_connect(struct bt_conn *conn)
|
||||
{
|
||||
struct bt_a2dp *a2dp_conn;
|
||||
int err;
|
||||
|
||||
a2dp_conn = get_new_connection(conn);
|
||||
if (!a2dp_conn) {
|
||||
BT_ERR("Cannot allocate memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = bt_avdtp_connect(conn, &(a2dp_conn->session));
|
||||
if (err < 0) {
|
||||
/* If error occurs, undo the saving and return the error */
|
||||
a2d_reset(a2dp_conn);
|
||||
BT_DBG("AVDTP Connect failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BT_DBG("Connect request sent");
|
||||
return a2dp_conn;
|
||||
}
|
||||
|
||||
int bt_a2dp_register_endpoint(struct bt_a2dp_endpoint *endpoint,
|
||||
uint8_t media_type, uint8_t role)
|
||||
{
|
||||
int err;
|
||||
|
||||
BT_ASSERT(endpoint);
|
||||
|
||||
err = bt_avdtp_register_sep(media_type, role, &(endpoint->info));
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/** @file
|
||||
* @brief Advance Audio Distribution Profile Internal header.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* To be called when first SEP is being registered */
|
||||
int bt_a2dp_init(void);
|
||||
@@ -0,0 +1,537 @@
|
||||
/**
|
||||
* @file at.c
|
||||
* Generic AT command handling library implementation
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <net/buf.h>
|
||||
|
||||
#include "at.h"
|
||||
|
||||
static void next_list(struct at_client *at)
|
||||
{
|
||||
if (at->buf[at->pos] == ',') {
|
||||
at->pos++;
|
||||
}
|
||||
}
|
||||
|
||||
int at_check_byte(struct net_buf *buf, char check_byte)
|
||||
{
|
||||
const unsigned char *str = buf->data;
|
||||
|
||||
if (*str != check_byte) {
|
||||
return -EINVAL;
|
||||
}
|
||||
net_buf_pull(buf, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void skip_space(struct at_client *at)
|
||||
{
|
||||
while (at->buf[at->pos] == ' ') {
|
||||
at->pos++;
|
||||
}
|
||||
}
|
||||
|
||||
int at_get_number(struct at_client *at, uint32_t *val)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
skip_space(at);
|
||||
|
||||
for (i = 0U, *val = 0U;
|
||||
isdigit((unsigned char)at->buf[at->pos]);
|
||||
at->pos++, i++) {
|
||||
*val = *val * 10U + at->buf[at->pos] - '0';
|
||||
}
|
||||
|
||||
if (i == 0U) {
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
next_list(at);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool str_has_prefix(const char *str, const char *prefix)
|
||||
{
|
||||
if (strncmp(str, prefix, strlen(prefix)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int at_parse_result(const char *str, struct net_buf *buf,
|
||||
enum at_result *result)
|
||||
{
|
||||
/* Map the result and check for end lf */
|
||||
if ((!strncmp(str, "OK", 2)) && (at_check_byte(buf, '\n') == 0)) {
|
||||
*result = AT_RESULT_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((!strncmp(str, "ERROR", 5)) && (at_check_byte(buf, '\n')) == 0) {
|
||||
*result = AT_RESULT_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMSG;
|
||||
}
|
||||
|
||||
static int get_cmd_value(struct at_client *at, struct net_buf *buf,
|
||||
char stop_byte, enum at_cmd_state cmd_state)
|
||||
{
|
||||
int cmd_len = 0;
|
||||
uint8_t pos = at->pos;
|
||||
const char *str = (char *)buf->data;
|
||||
|
||||
while (cmd_len < buf->len && at->pos != at->buf_max_len) {
|
||||
if (*str != stop_byte) {
|
||||
at->buf[at->pos++] = *str;
|
||||
cmd_len++;
|
||||
str++;
|
||||
pos = at->pos;
|
||||
} else {
|
||||
cmd_len++;
|
||||
at->buf[at->pos] = '\0';
|
||||
at->pos = 0U;
|
||||
at->cmd_state = cmd_state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
net_buf_pull(buf, cmd_len);
|
||||
|
||||
if (pos == at->buf_max_len) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_response_string(struct at_client *at, struct net_buf *buf,
|
||||
char stop_byte, enum at_state state)
|
||||
{
|
||||
int cmd_len = 0;
|
||||
uint8_t pos = at->pos;
|
||||
const char *str = (char *)buf->data;
|
||||
|
||||
while (cmd_len < buf->len && at->pos != at->buf_max_len) {
|
||||
if (*str != stop_byte) {
|
||||
at->buf[at->pos++] = *str;
|
||||
cmd_len++;
|
||||
str++;
|
||||
pos = at->pos;
|
||||
} else {
|
||||
cmd_len++;
|
||||
at->buf[at->pos] = '\0';
|
||||
at->pos = 0U;
|
||||
at->state = state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
net_buf_pull(buf, cmd_len);
|
||||
|
||||
if (pos == at->buf_max_len) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void reset_buffer(struct at_client *at)
|
||||
{
|
||||
(void)memset(at->buf, 0, at->buf_max_len);
|
||||
at->pos = 0U;
|
||||
}
|
||||
|
||||
static int at_state_start(struct at_client *at, struct net_buf *buf)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = at_check_byte(buf, '\r');
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
at->state = AT_STATE_START_CR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at_state_start_cr(struct at_client *at, struct net_buf *buf)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = at_check_byte(buf, '\n');
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
at->state = AT_STATE_START_LF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at_state_start_lf(struct at_client *at, struct net_buf *buf)
|
||||
{
|
||||
reset_buffer(at);
|
||||
if (at_check_byte(buf, '+') == 0) {
|
||||
at->state = AT_STATE_GET_CMD_STRING;
|
||||
return 0;
|
||||
} else if (isalpha(*buf->data)) {
|
||||
at->state = AT_STATE_GET_RESULT_STRING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
static int at_state_get_cmd_string(struct at_client *at, struct net_buf *buf)
|
||||
{
|
||||
return get_response_string(at, buf, ':', AT_STATE_PROCESS_CMD);
|
||||
}
|
||||
|
||||
static bool is_cmer(struct at_client *at)
|
||||
{
|
||||
if (strncmp(at->buf, "CME ERROR", 9) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int at_state_process_cmd(struct at_client *at, struct net_buf *buf)
|
||||
{
|
||||
if (is_cmer(at)) {
|
||||
at->state = AT_STATE_PROCESS_AG_NW_ERR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (at->resp) {
|
||||
at->resp(at, buf);
|
||||
at->resp = NULL;
|
||||
return 0;
|
||||
}
|
||||
at->state = AT_STATE_UNSOLICITED_CMD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at_state_get_result_string(struct at_client *at, struct net_buf *buf)
|
||||
{
|
||||
return get_response_string(at, buf, '\r', AT_STATE_PROCESS_RESULT);
|
||||
}
|
||||
|
||||
static bool is_ring(struct at_client *at)
|
||||
{
|
||||
if (strncmp(at->buf, "RING", 4) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int at_state_process_result(struct at_client *at, struct net_buf *buf)
|
||||
{
|
||||
enum at_cme cme_err;
|
||||
enum at_result result;
|
||||
|
||||
if (is_ring(at)) {
|
||||
at->state = AT_STATE_UNSOLICITED_CMD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (at_parse_result(at->buf, buf, &result) == 0) {
|
||||
if (at->finish) {
|
||||
/* cme_err is 0 - Is invalid until result is
|
||||
* AT_RESULT_CME_ERROR
|
||||
*/
|
||||
cme_err = 0;
|
||||
at->finish(at, result, cme_err);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset the state to process unsolicited response */
|
||||
at->cmd_state = AT_CMD_START;
|
||||
at->state = AT_STATE_START;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cme_handle(struct at_client *at)
|
||||
{
|
||||
enum at_cme cme_err;
|
||||
uint32_t val;
|
||||
|
||||
if (!at_get_number(at, &val) && val <= CME_ERROR_NETWORK_NOT_ALLOWED) {
|
||||
cme_err = val;
|
||||
} else {
|
||||
cme_err = CME_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
if (at->finish) {
|
||||
at->finish(at, AT_RESULT_CME_ERROR, cme_err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at_state_process_ag_nw_err(struct at_client *at, struct net_buf *buf)
|
||||
{
|
||||
at->cmd_state = AT_CMD_GET_VALUE;
|
||||
return at_parse_cmd_input(at, buf, NULL, cme_handle,
|
||||
AT_CMD_TYPE_NORMAL);
|
||||
}
|
||||
|
||||
static int at_state_unsolicited_cmd(struct at_client *at, struct net_buf *buf)
|
||||
{
|
||||
if (at->unsolicited) {
|
||||
return at->unsolicited(at, buf);
|
||||
}
|
||||
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
/* The order of handler function should match the enum at_state */
|
||||
static handle_parse_input_t parser_cb[] = {
|
||||
at_state_start, /* AT_STATE_START */
|
||||
at_state_start_cr, /* AT_STATE_START_CR */
|
||||
at_state_start_lf, /* AT_STATE_START_LF */
|
||||
at_state_get_cmd_string, /* AT_STATE_GET_CMD_STRING */
|
||||
at_state_process_cmd, /* AT_STATE_PROCESS_CMD */
|
||||
at_state_get_result_string, /* AT_STATE_GET_RESULT_STRING */
|
||||
at_state_process_result, /* AT_STATE_PROCESS_RESULT */
|
||||
at_state_process_ag_nw_err, /* AT_STATE_PROCESS_AG_NW_ERR */
|
||||
at_state_unsolicited_cmd /* AT_STATE_UNSOLICITED_CMD */
|
||||
};
|
||||
|
||||
int at_parse_input(struct at_client *at, struct net_buf *buf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (buf->len) {
|
||||
if (at->state < AT_STATE_START || at->state >= AT_STATE_END) {
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = parser_cb[at->state](at, buf);
|
||||
if (ret < 0) {
|
||||
/* Reset the state in case of error */
|
||||
at->cmd_state = AT_CMD_START;
|
||||
at->state = AT_STATE_START;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at_cmd_start(struct at_client *at, struct net_buf *buf,
|
||||
const char *prefix, parse_val_t func,
|
||||
enum at_cmd_type type)
|
||||
{
|
||||
if (!str_has_prefix(at->buf, prefix)) {
|
||||
if (type == AT_CMD_TYPE_NORMAL) {
|
||||
at->state = AT_STATE_UNSOLICITED_CMD;
|
||||
}
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
if (type == AT_CMD_TYPE_OTHER) {
|
||||
/* Skip for Other type such as ..RING.. which does not have
|
||||
* values to get processed.
|
||||
*/
|
||||
at->cmd_state = AT_CMD_PROCESS_VALUE;
|
||||
} else {
|
||||
at->cmd_state = AT_CMD_GET_VALUE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at_cmd_get_value(struct at_client *at, struct net_buf *buf,
|
||||
const char *prefix, parse_val_t func,
|
||||
enum at_cmd_type type)
|
||||
{
|
||||
/* Reset buffer before getting the values */
|
||||
reset_buffer(at);
|
||||
return get_cmd_value(at, buf, '\r', AT_CMD_PROCESS_VALUE);
|
||||
}
|
||||
|
||||
static int at_cmd_process_value(struct at_client *at, struct net_buf *buf,
|
||||
const char *prefix, parse_val_t func,
|
||||
enum at_cmd_type type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = func(at);
|
||||
at->cmd_state = AT_CMD_STATE_END_LF;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int at_cmd_state_end_lf(struct at_client *at, struct net_buf *buf,
|
||||
const char *prefix, parse_val_t func,
|
||||
enum at_cmd_type type)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = at_check_byte(buf, '\n');
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
at->cmd_state = AT_CMD_START;
|
||||
at->state = AT_STATE_START;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The order of handler function should match the enum at_cmd_state */
|
||||
static handle_cmd_input_t cmd_parser_cb[] = {
|
||||
at_cmd_start, /* AT_CMD_START */
|
||||
at_cmd_get_value, /* AT_CMD_GET_VALUE */
|
||||
at_cmd_process_value, /* AT_CMD_PROCESS_VALUE */
|
||||
at_cmd_state_end_lf /* AT_CMD_STATE_END_LF */
|
||||
};
|
||||
|
||||
int at_parse_cmd_input(struct at_client *at, struct net_buf *buf,
|
||||
const char *prefix, parse_val_t func,
|
||||
enum at_cmd_type type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (buf->len) {
|
||||
if (at->cmd_state < AT_CMD_START ||
|
||||
at->cmd_state >= AT_CMD_STATE_END) {
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = cmd_parser_cb[at->cmd_state](at, buf, prefix, func, type);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
/* Check for main state, the end of cmd parsing and return. */
|
||||
if (at->state == AT_STATE_START) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int at_has_next_list(struct at_client *at)
|
||||
{
|
||||
return at->buf[at->pos] != '\0';
|
||||
}
|
||||
|
||||
int at_open_list(struct at_client *at)
|
||||
{
|
||||
skip_space(at);
|
||||
|
||||
/* The list shall start with '(' open parenthesis */
|
||||
if (at->buf[at->pos] != '(') {
|
||||
return -ENODATA;
|
||||
}
|
||||
at->pos++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int at_close_list(struct at_client *at)
|
||||
{
|
||||
skip_space(at);
|
||||
|
||||
if (at->buf[at->pos] != ')') {
|
||||
return -ENODATA;
|
||||
}
|
||||
at->pos++;
|
||||
|
||||
next_list(at);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int at_list_get_string(struct at_client *at, char *name, uint8_t len)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
skip_space(at);
|
||||
|
||||
if (at->buf[at->pos] != '"') {
|
||||
return -ENODATA;
|
||||
}
|
||||
at->pos++;
|
||||
|
||||
while (at->buf[at->pos] != '\0' && at->buf[at->pos] != '"') {
|
||||
if (i == len) {
|
||||
return -ENODATA;
|
||||
}
|
||||
name[i++] = at->buf[at->pos++];
|
||||
}
|
||||
|
||||
if (i == len) {
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
name[i] = '\0';
|
||||
|
||||
if (at->buf[at->pos] != '"') {
|
||||
return -ENODATA;
|
||||
}
|
||||
at->pos++;
|
||||
|
||||
skip_space(at);
|
||||
next_list(at);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int at_list_get_range(struct at_client *at, uint32_t *min, uint32_t *max)
|
||||
{
|
||||
uint32_t low, high;
|
||||
int ret;
|
||||
|
||||
ret = at_get_number(at, &low);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (at->buf[at->pos] == '-') {
|
||||
at->pos++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!isdigit((unsigned char)at->buf[at->pos])) {
|
||||
return -ENODATA;
|
||||
}
|
||||
out:
|
||||
ret = at_get_number(at, &high);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
*min = low;
|
||||
*max = high;
|
||||
|
||||
next_list(at);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void at_register_unsolicited(struct at_client *at, at_resp_cb_t unsolicited)
|
||||
{
|
||||
at->unsolicited = unsolicited;
|
||||
}
|
||||
|
||||
void at_register(struct at_client *at, at_resp_cb_t resp, at_finish_cb_t finish)
|
||||
{
|
||||
at->resp = resp;
|
||||
at->finish = finish;
|
||||
at->state = AT_STATE_START;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/** @file at.h
|
||||
* @brief Internal APIs for AT command handling.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
enum at_result {
|
||||
AT_RESULT_OK,
|
||||
AT_RESULT_ERROR,
|
||||
AT_RESULT_CME_ERROR
|
||||
};
|
||||
|
||||
enum at_cme {
|
||||
CME_ERROR_AG_FAILURE = 0,
|
||||
CME_ERROR_NO_CONNECTION_TO_PHONE = 1,
|
||||
CME_ERROR_OPERATION_NOT_ALLOWED = 3,
|
||||
CME_ERROR_OPERATION_NOT_SUPPORTED = 4,
|
||||
CME_ERROR_PH_SIM_PIN_REQUIRED = 5,
|
||||
CME_ERROR_SIM_NOT_INSERTED = 10,
|
||||
CME_ERROR_SIM_PIN_REQUIRED = 11,
|
||||
CME_ERROR_SIM_PUK_REQUIRED = 12,
|
||||
CME_ERROR_SIM_FAILURE = 13,
|
||||
CME_ERROR_SIM_BUSY = 14,
|
||||
CME_ERROR_INCORRECT_PASSWORD = 16,
|
||||
CME_ERROR_SIM_PIN2_REQUIRED = 17,
|
||||
CME_ERROR_SIM_PUK2_REQUIRED = 18,
|
||||
CME_ERROR_MEMORY_FULL = 20,
|
||||
CME_ERROR_INVALID_INDEX = 21,
|
||||
CME_ERROR_MEMORY_FAILURE = 23,
|
||||
CME_ERROR_TEXT_STRING_TOO_LONG = 24,
|
||||
CME_ERROR_INVALID_CHARS_IN_TEXT_STRING = 25,
|
||||
CME_ERROR_DIAL_STRING_TO_LONG = 26,
|
||||
CME_ERROR_INVALID_CHARS_IN_DIAL_STRING = 27,
|
||||
CME_ERROR_NO_NETWORK_SERVICE = 30,
|
||||
CME_ERROR_NETWORK_TIMEOUT = 31,
|
||||
CME_ERROR_NETWORK_NOT_ALLOWED = 32,
|
||||
CME_ERROR_UNKNOWN = 33,
|
||||
};
|
||||
|
||||
enum at_state {
|
||||
AT_STATE_START,
|
||||
AT_STATE_START_CR,
|
||||
AT_STATE_START_LF,
|
||||
AT_STATE_GET_CMD_STRING,
|
||||
AT_STATE_PROCESS_CMD,
|
||||
AT_STATE_GET_RESULT_STRING,
|
||||
AT_STATE_PROCESS_RESULT,
|
||||
AT_STATE_PROCESS_AG_NW_ERR,
|
||||
AT_STATE_UNSOLICITED_CMD,
|
||||
AT_STATE_END
|
||||
};
|
||||
|
||||
enum at_cmd_state {
|
||||
AT_CMD_START,
|
||||
AT_CMD_GET_VALUE,
|
||||
AT_CMD_PROCESS_VALUE,
|
||||
AT_CMD_STATE_END_LF,
|
||||
AT_CMD_STATE_END
|
||||
};
|
||||
|
||||
enum at_cmd_type {
|
||||
AT_CMD_TYPE_NORMAL,
|
||||
AT_CMD_TYPE_UNSOLICITED,
|
||||
AT_CMD_TYPE_OTHER
|
||||
};
|
||||
|
||||
struct at_client;
|
||||
|
||||
/* Callback at_resp_cb_t used to parse response value received for the
|
||||
* particular AT command. Eg: +CIND=<value>
|
||||
*/
|
||||
typedef int (*at_resp_cb_t)(struct at_client *at, struct net_buf *buf);
|
||||
|
||||
/* Callback at_finish_cb used to monitor the success or failure of the AT
|
||||
* command received from server.
|
||||
* Argument 'cme_err' is valid only when argument 'result' is equal to
|
||||
* AT_RESULT_CME_ERROR
|
||||
*/
|
||||
typedef int (*at_finish_cb_t)(struct at_client *at, enum at_result result,
|
||||
enum at_cme cme_err);
|
||||
typedef int (*parse_val_t)(struct at_client *at);
|
||||
typedef int (*handle_parse_input_t)(struct at_client *at, struct net_buf *buf);
|
||||
typedef int (*handle_cmd_input_t)(struct at_client *at, struct net_buf *buf,
|
||||
const char *prefix, parse_val_t func,
|
||||
enum at_cmd_type type);
|
||||
|
||||
struct at_client {
|
||||
char *buf;
|
||||
uint8_t pos;
|
||||
uint8_t buf_max_len;
|
||||
uint8_t state;
|
||||
uint8_t cmd_state;
|
||||
at_resp_cb_t resp;
|
||||
at_resp_cb_t unsolicited;
|
||||
at_finish_cb_t finish;
|
||||
};
|
||||
|
||||
/* Register the callback functions */
|
||||
void at_register(struct at_client *at, at_resp_cb_t resp,
|
||||
at_finish_cb_t finish);
|
||||
void at_register_unsolicited(struct at_client *at, at_resp_cb_t unsolicited);
|
||||
int at_get_number(struct at_client *at, uint32_t *val);
|
||||
/* This parsing will only works for non-fragmented net_buf */
|
||||
int at_parse_input(struct at_client *at, struct net_buf *buf);
|
||||
/* This command parsing will only works for non-fragmented net_buf */
|
||||
int at_parse_cmd_input(struct at_client *at, struct net_buf *buf,
|
||||
const char *prefix, parse_val_t func,
|
||||
enum at_cmd_type type);
|
||||
int at_check_byte(struct net_buf *buf, char check_byte);
|
||||
int at_list_get_range(struct at_client *at, uint32_t *min, uint32_t *max);
|
||||
int at_list_get_string(struct at_client *at, char *name, uint8_t len);
|
||||
int at_close_list(struct at_client *at);
|
||||
int at_open_list(struct at_client *at);
|
||||
int at_has_next_list(struct at_client *at);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,265 @@
|
||||
/* att_internal.h - Attribute protocol handling */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define BT_ATT_DEFAULT_LE_MTU 23
|
||||
|
||||
#if BT_L2CAP_RX_MTU < CONFIG_BT_L2CAP_TX_MTU
|
||||
#define BT_ATT_MTU BT_L2CAP_RX_MTU
|
||||
#else
|
||||
#define BT_ATT_MTU CONFIG_BT_L2CAP_TX_MTU
|
||||
#endif
|
||||
|
||||
struct bt_att_hdr {
|
||||
u8_t code;
|
||||
} __packed;
|
||||
|
||||
#define BT_ATT_OP_ERROR_RSP 0x01
|
||||
struct bt_att_error_rsp {
|
||||
u8_t request;
|
||||
u16_t handle;
|
||||
u8_t error;
|
||||
} __packed;
|
||||
|
||||
#define BT_ATT_OP_MTU_REQ 0x02
|
||||
struct bt_att_exchange_mtu_req {
|
||||
u16_t mtu;
|
||||
} __packed;
|
||||
|
||||
#define BT_ATT_OP_MTU_RSP 0x03
|
||||
struct bt_att_exchange_mtu_rsp {
|
||||
u16_t mtu;
|
||||
} __packed;
|
||||
|
||||
/* Find Information Request */
|
||||
#define BT_ATT_OP_FIND_INFO_REQ 0x04
|
||||
struct bt_att_find_info_req {
|
||||
u16_t start_handle;
|
||||
u16_t end_handle;
|
||||
} __packed;
|
||||
|
||||
/* Format field values for BT_ATT_OP_FIND_INFO_RSP */
|
||||
#define BT_ATT_INFO_16 0x01
|
||||
#define BT_ATT_INFO_128 0x02
|
||||
|
||||
struct bt_att_info_16 {
|
||||
u16_t handle;
|
||||
u16_t uuid;
|
||||
} __packed;
|
||||
|
||||
struct bt_att_info_128 {
|
||||
u16_t handle;
|
||||
u8_t uuid[16];
|
||||
} __packed;
|
||||
|
||||
/* Find Information Response */
|
||||
#define BT_ATT_OP_FIND_INFO_RSP 0x05
|
||||
struct bt_att_find_info_rsp {
|
||||
u8_t format;
|
||||
u8_t info[0];
|
||||
} __packed;
|
||||
|
||||
/* Find By Type Value Request */
|
||||
#define BT_ATT_OP_FIND_TYPE_REQ 0x06
|
||||
struct bt_att_find_type_req {
|
||||
u16_t start_handle;
|
||||
u16_t end_handle;
|
||||
u16_t type;
|
||||
u8_t value[0];
|
||||
} __packed;
|
||||
|
||||
struct bt_att_handle_group {
|
||||
u16_t start_handle;
|
||||
u16_t end_handle;
|
||||
} __packed;
|
||||
|
||||
/* Find By Type Value Response */
|
||||
#define BT_ATT_OP_FIND_TYPE_RSP 0x07
|
||||
struct bt_att_find_type_rsp {
|
||||
struct bt_att_handle_group list[0];
|
||||
} __packed;
|
||||
|
||||
/* Read By Type Request */
|
||||
#define BT_ATT_OP_READ_TYPE_REQ 0x08
|
||||
struct bt_att_read_type_req {
|
||||
u16_t start_handle;
|
||||
u16_t end_handle;
|
||||
u8_t uuid[0];
|
||||
} __packed;
|
||||
|
||||
struct bt_att_data {
|
||||
u16_t handle;
|
||||
u8_t value[0];
|
||||
} __packed;
|
||||
|
||||
/* Read By Type Response */
|
||||
#define BT_ATT_OP_READ_TYPE_RSP 0x09
|
||||
struct bt_att_read_type_rsp {
|
||||
u8_t len;
|
||||
struct bt_att_data data[0];
|
||||
} __packed;
|
||||
|
||||
/* Read Request */
|
||||
#define BT_ATT_OP_READ_REQ 0x0a
|
||||
struct bt_att_read_req {
|
||||
u16_t handle;
|
||||
} __packed;
|
||||
|
||||
/* Read Response */
|
||||
#define BT_ATT_OP_READ_RSP 0x0b
|
||||
struct bt_att_read_rsp {
|
||||
u8_t value[0];
|
||||
} __packed;
|
||||
|
||||
/* Read Blob Request */
|
||||
#define BT_ATT_OP_READ_BLOB_REQ 0x0c
|
||||
struct bt_att_read_blob_req {
|
||||
u16_t handle;
|
||||
u16_t offset;
|
||||
} __packed;
|
||||
|
||||
/* Read Blob Response */
|
||||
#define BT_ATT_OP_READ_BLOB_RSP 0x0d
|
||||
struct bt_att_read_blob_rsp {
|
||||
u8_t value[0];
|
||||
} __packed;
|
||||
|
||||
/* Read Multiple Request */
|
||||
#define BT_ATT_READ_MULT_MIN_LEN_REQ 0x04
|
||||
|
||||
#define BT_ATT_OP_READ_MULT_REQ 0x0e
|
||||
struct bt_att_read_mult_req {
|
||||
u16_t handles[0];
|
||||
} __packed;
|
||||
|
||||
/* Read Multiple Respose */
|
||||
#define BT_ATT_OP_READ_MULT_RSP 0x0f
|
||||
struct bt_att_read_mult_rsp {
|
||||
u8_t value[0];
|
||||
} __packed;
|
||||
|
||||
/* Read by Group Type Request */
|
||||
#define BT_ATT_OP_READ_GROUP_REQ 0x10
|
||||
struct bt_att_read_group_req {
|
||||
u16_t start_handle;
|
||||
u16_t end_handle;
|
||||
u8_t uuid[0];
|
||||
} __packed;
|
||||
|
||||
struct bt_att_group_data {
|
||||
u16_t start_handle;
|
||||
u16_t end_handle;
|
||||
u8_t value[0];
|
||||
} __packed;
|
||||
|
||||
/* Read by Group Type Response */
|
||||
#define BT_ATT_OP_READ_GROUP_RSP 0x11
|
||||
struct bt_att_read_group_rsp {
|
||||
u8_t len;
|
||||
struct bt_att_group_data data[0];
|
||||
} __packed;
|
||||
|
||||
/* Write Request */
|
||||
#define BT_ATT_OP_WRITE_REQ 0x12
|
||||
struct bt_att_write_req {
|
||||
u16_t handle;
|
||||
u8_t value[0];
|
||||
} __packed;
|
||||
|
||||
/* Write Response */
|
||||
#define BT_ATT_OP_WRITE_RSP 0x13
|
||||
|
||||
/* Prepare Write Request */
|
||||
#define BT_ATT_OP_PREPARE_WRITE_REQ 0x16
|
||||
struct bt_att_prepare_write_req {
|
||||
u16_t handle;
|
||||
u16_t offset;
|
||||
u8_t value[0];
|
||||
} __packed;
|
||||
|
||||
/* Prepare Write Respond */
|
||||
#define BT_ATT_OP_PREPARE_WRITE_RSP 0x17
|
||||
struct bt_att_prepare_write_rsp {
|
||||
u16_t handle;
|
||||
u16_t offset;
|
||||
u8_t value[0];
|
||||
} __packed;
|
||||
|
||||
/* Execute Write Request */
|
||||
#define BT_ATT_FLAG_CANCEL 0x00
|
||||
#define BT_ATT_FLAG_EXEC 0x01
|
||||
|
||||
#define BT_ATT_OP_EXEC_WRITE_REQ 0x18
|
||||
struct bt_att_exec_write_req {
|
||||
u8_t flags;
|
||||
} __packed;
|
||||
|
||||
/* Execute Write Response */
|
||||
#define BT_ATT_OP_EXEC_WRITE_RSP 0x19
|
||||
|
||||
/* Handle Value Notification */
|
||||
#define BT_ATT_OP_NOTIFY 0x1b
|
||||
struct bt_att_notify {
|
||||
u16_t handle;
|
||||
u8_t value[0];
|
||||
} __packed;
|
||||
|
||||
/* Handle Value Indication */
|
||||
#define BT_ATT_OP_INDICATE 0x1d
|
||||
struct bt_att_indicate {
|
||||
u16_t handle;
|
||||
u8_t value[0];
|
||||
} __packed;
|
||||
|
||||
/* Handle Value Confirm */
|
||||
#define BT_ATT_OP_CONFIRM 0x1e
|
||||
|
||||
struct bt_att_signature {
|
||||
u8_t value[12];
|
||||
} __packed;
|
||||
|
||||
/* Write Command */
|
||||
#define BT_ATT_OP_WRITE_CMD 0x52
|
||||
struct bt_att_write_cmd {
|
||||
u16_t handle;
|
||||
u8_t value[0];
|
||||
} __packed;
|
||||
|
||||
/* Signed Write Command */
|
||||
#define BT_ATT_OP_SIGNED_WRITE_CMD 0xd2
|
||||
struct bt_att_signed_write_cmd {
|
||||
u16_t handle;
|
||||
u8_t value[0];
|
||||
} __packed;
|
||||
|
||||
void att_pdu_sent(struct bt_conn *conn, void *user_data);
|
||||
|
||||
void att_cfm_sent(struct bt_conn *conn, void *user_data);
|
||||
|
||||
void att_rsp_sent(struct bt_conn *conn, void *user_data);
|
||||
|
||||
void att_req_sent(struct bt_conn *conn, void *user_data);
|
||||
|
||||
void bt_att_init(void);
|
||||
u16_t bt_att_get_mtu(struct bt_conn *conn);
|
||||
|
||||
#if defined(CONFIG_BLE_AT_CMD)
|
||||
void set_mtu_size(u16_t size);
|
||||
#endif
|
||||
|
||||
struct net_buf *bt_att_create_pdu(struct bt_conn *conn, u8_t op,
|
||||
size_t len);
|
||||
|
||||
/* Send ATT PDU over a connection */
|
||||
int bt_att_send(struct bt_conn *conn, struct net_buf *buf, bt_conn_tx_cb_t cb,
|
||||
void *user_data);
|
||||
|
||||
/* Send ATT Request over a connection */
|
||||
int bt_att_req_send(struct bt_conn *conn, struct bt_att_req *req);
|
||||
|
||||
/* Cancel ATT request */
|
||||
void bt_att_req_cancel(struct bt_conn *conn, struct bt_att_req *req);
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* avdtp_internal.h - avdtp handling
|
||||
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <avdtp.h>
|
||||
|
||||
/* @brief A2DP ROLE's */
|
||||
#define A2DP_SRC_ROLE 0x00
|
||||
#define A2DP_SNK_ROLE 0x01
|
||||
|
||||
/* @brief AVDTP Role */
|
||||
#define BT_AVDTP_INT 0x00
|
||||
#define BT_AVDTP_ACP 0x01
|
||||
|
||||
#define BT_L2CAP_PSM_AVDTP 0x0019
|
||||
|
||||
/* AVDTP SIGNAL HEADER - Packet Type*/
|
||||
#define BT_AVDTP_PACKET_TYPE_SINGLE 0x00
|
||||
#define BT_AVDTP_PACKET_TYPE_START 0x01
|
||||
#define BT_AVDTP_PACKET_TYPE_CONTINUE 0x02
|
||||
#define BT_AVDTP_PACKET_TYPE_END 0x03
|
||||
|
||||
/* AVDTP SIGNAL HEADER - MESSAGE TYPE */
|
||||
#define BT_AVDTP_CMD 0x00
|
||||
#define BT_AVDTP_GEN_REJECT 0x01
|
||||
#define BT_AVDTP_ACCEPT 0x02
|
||||
#define BT_AVDTP_REJECT 0x03
|
||||
|
||||
/* @brief AVDTP SIGNAL HEADER - Signal Identifier */
|
||||
#define BT_AVDTP_DISCOVER 0x01
|
||||
#define BT_AVDTP_GET_CAPABILITIES 0x02
|
||||
#define BT_AVDTP_SET_CONFIGURATION 0x03
|
||||
#define BT_AVDTP_GET_CONFIGURATION 0x04
|
||||
#define BT_AVDTP_RECONFIGURE 0x05
|
||||
#define BT_AVDTP_OPEN 0x06
|
||||
#define BT_AVDTP_START 0x07
|
||||
#define BT_AVDTP_CLOSE 0x08
|
||||
#define BT_AVDTP_SUSPEND 0x09
|
||||
#define BT_AVDTP_ABORT 0x0a
|
||||
#define BT_AVDTP_SECURITY_CONTROL 0x0b
|
||||
#define BT_AVDTP_GET_ALL_CAPABILITIES 0x0c
|
||||
#define BT_AVDTP_DELAYREPORT 0x0d
|
||||
|
||||
/* @brief AVDTP STREAM STATE */
|
||||
#define BT_AVDTP_STREAM_STATE_IDLE 0x01
|
||||
#define BT_AVDTP_STREAM_STATE_CONFIGURED 0x02
|
||||
#define BT_AVDTP_STREAM_STATE_OPEN 0x03
|
||||
#define BT_AVDTP_STREAM_STATE_STREAMING 0x04
|
||||
#define BT_AVDTP_STREAM_STATE_CLOSING 0x05
|
||||
|
||||
/* @brief AVDTP Media TYPE */
|
||||
#define BT_AVDTP_SERVICE_CAT_MEDIA_TRANSPORT 0x01
|
||||
#define BT_AVDTP_SERVICE_CAT_REPORTING 0x02
|
||||
#define BT_AVDTP_SERVICE_CAT_RECOVERY 0x03
|
||||
#define BT_AVDTP_SERVICE_CAT_CONTENT_PROTECTION 0x04
|
||||
#define BT_AVDTP_SERVICE_CAT_HDR_COMPRESSION 0x05
|
||||
#define BT_AVDTP_SERVICE_CAT_MULTIPLEXING 0x06
|
||||
#define BT_AVDTP_SERVICE_CAT_MEDIA_CODEC 0x07
|
||||
#define BT_AVDTP_SERVICE_CAT_DELAYREPORTING 0x08
|
||||
|
||||
/* @brief AVDTP Content Protection Capabilities */
|
||||
#define BT_AVDTP_CONTENT_PROTECTION_MSB 0x00
|
||||
#define BT_AVDTP_CONTENT_PROTECTION_LSB_DTCP 0x01
|
||||
#define BT_AVDTP_CONTENT_PROTECTION_LSB_SCMS_T 0x02
|
||||
|
||||
/* AVDTP Error Codes */
|
||||
#define BT_AVDTP_SUCCESS 0x00
|
||||
#define BT_AVDTP_ERR_BAD_HDR_FORMAT 0x01
|
||||
#define BT_AVDTP_ERR_BAD_LENGTH 0x11
|
||||
#define BT_AVDTP_ERR_BAD_ACP_SEID 0x12
|
||||
#define BT_AVDTP_ERR_SEP_IN_USE 0x13
|
||||
#define BT_AVDTP_ERR_SEP_NOT_IN_USE 0x14
|
||||
#define BT_AVDTP_ERR_BAD_SERV_CATEGORY 0x17
|
||||
#define BT_AVDTP_ERR_BAD_PAYLOAD_FORMAT 0x18
|
||||
#define BT_AVDTP_ERR_NOT_SUPPORTED_COMMAND 0x19
|
||||
#define BT_AVDTP_ERR_INVALID_CAPABILITIES 0x1a
|
||||
#define BT_AVDTP_ERR_BAD_RECOVERY_TYPE 0x22
|
||||
#define BT_AVDTP_ERR_BAD_MEDIA_TRANSPORT_FORMAT 0x23
|
||||
#define BT_AVDTP_ERR_BAD_RECOVERY_FORMAT 0x25
|
||||
#define BT_AVDTP_ERR_BAD_ROHC_FORMAT 0x26
|
||||
#define BT_AVDTP_ERR_BAD_CP_FORMAT 0x27
|
||||
#define BT_AVDTP_ERR_BAD_MULTIPLEXING_FORMAT 0x28
|
||||
#define BT_AVDTP_ERR_UNSUPPORTED_CONFIGURAION 0x29
|
||||
#define BT_AVDTP_ERR_BAD_STATE 0x31
|
||||
|
||||
#define BT_AVDTP_MAX_MTU CONFIG_BT_L2CAP_RX_MTU
|
||||
|
||||
#define BT_AVDTP_MIN_SEID 0x01
|
||||
#define BT_AVDTP_MAX_SEID 0x3E
|
||||
|
||||
struct bt_avdtp;
|
||||
struct bt_avdtp_req;
|
||||
|
||||
typedef int (*bt_avdtp_func_t)(struct bt_avdtp *session,
|
||||
struct bt_avdtp_req *req);
|
||||
|
||||
struct bt_avdtp_req {
|
||||
uint8_t sig;
|
||||
uint8_t tid;
|
||||
bt_avdtp_func_t func;
|
||||
struct k_delayed_work timeout_work;
|
||||
};
|
||||
|
||||
struct bt_avdtp_single_sig_hdr {
|
||||
uint8_t hdr;
|
||||
uint8_t signal_id;
|
||||
} __packed;
|
||||
|
||||
#define BT_AVDTP_SIG_HDR_LEN sizeof(struct bt_avdtp_single_sig_hdr)
|
||||
|
||||
struct bt_avdtp_ind_cb {
|
||||
/*
|
||||
* discovery_ind;
|
||||
* get_capabilities_ind;
|
||||
* set_configuration_ind;
|
||||
* open_ind;
|
||||
* start_ind;
|
||||
* suspend_ind;
|
||||
* close_ind;
|
||||
*/
|
||||
};
|
||||
|
||||
struct bt_avdtp_cap {
|
||||
uint8_t cat;
|
||||
uint8_t len;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
struct bt_avdtp_sep {
|
||||
uint8_t seid;
|
||||
uint8_t len;
|
||||
struct bt_avdtp_cap caps[0];
|
||||
};
|
||||
|
||||
struct bt_avdtp_discover_params {
|
||||
struct bt_avdtp_req req;
|
||||
uint8_t status;
|
||||
struct bt_avdtp_sep *caps;
|
||||
};
|
||||
|
||||
/** @brief Global AVDTP session structure. */
|
||||
struct bt_avdtp {
|
||||
struct bt_l2cap_br_chan br_chan;
|
||||
struct bt_avdtp_stream *streams; /* List of AV streams */
|
||||
struct bt_avdtp_req *req;
|
||||
};
|
||||
|
||||
struct bt_avdtp_event_cb {
|
||||
struct bt_avdtp_ind_cb *ind;
|
||||
int (*accept)(struct bt_conn *conn, struct bt_avdtp **session);
|
||||
};
|
||||
|
||||
/* Initialize AVDTP layer*/
|
||||
int bt_avdtp_init(void);
|
||||
|
||||
/* Application register with AVDTP layer */
|
||||
int bt_avdtp_register(struct bt_avdtp_event_cb *cb);
|
||||
|
||||
/* AVDTP connect */
|
||||
int bt_avdtp_connect(struct bt_conn *conn, struct bt_avdtp *session);
|
||||
|
||||
/* AVDTP disconnect */
|
||||
int bt_avdtp_disconnect(struct bt_avdtp *session);
|
||||
|
||||
/* AVDTP SEP register function */
|
||||
int bt_avdtp_register_sep(uint8_t media_type, uint8_t role,
|
||||
struct bt_avdtp_seid_lsep *sep);
|
||||
|
||||
/* AVDTP Discover Request */
|
||||
int bt_avdtp_discover(struct bt_avdtp *session,
|
||||
struct bt_avdtp_discover_params *param);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,341 @@
|
||||
/** @file
|
||||
* @brief Internal APIs for Bluetooth connection handling.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
typedef enum __packed {
|
||||
BT_CONN_DISCONNECTED,
|
||||
BT_CONN_CONNECT_SCAN,
|
||||
BT_CONN_CONNECT_DIR_ADV,
|
||||
BT_CONN_CONNECT,
|
||||
BT_CONN_CONNECTED,
|
||||
BT_CONN_DISCONNECT,
|
||||
} bt_conn_state_t;
|
||||
|
||||
/* bt_conn flags: the flags defined here represent connection parameters */
|
||||
enum {
|
||||
BT_CONN_AUTO_CONNECT,
|
||||
BT_CONN_BR_LEGACY_SECURE, /* 16 digits legacy PIN tracker */
|
||||
BT_CONN_USER, /* user I/O when pairing */
|
||||
BT_CONN_BR_PAIRING, /* BR connection in pairing context */
|
||||
BT_CONN_BR_NOBOND, /* SSP no bond pairing tracker */
|
||||
BT_CONN_BR_PAIRING_INITIATOR, /* local host starts authentication */
|
||||
BT_CONN_CLEANUP, /* Disconnected, pending cleanup */
|
||||
BT_CONN_AUTO_PHY_UPDATE, /* Auto-update PHY */
|
||||
BT_CONN_SLAVE_PARAM_UPDATE, /* If slave param update timer fired */
|
||||
BT_CONN_SLAVE_PARAM_SET, /* If slave param were set from app */
|
||||
BT_CONN_SLAVE_PARAM_L2CAP, /* If should force L2CAP for CPUP */
|
||||
BT_CONN_FORCE_PAIR, /* Pairing even with existing keys. */
|
||||
|
||||
BT_CONN_AUTO_PHY_COMPLETE, /* Auto-initiated PHY procedure done */
|
||||
BT_CONN_AUTO_FEATURE_EXCH, /* Auto-initiated LE Feat done */
|
||||
BT_CONN_AUTO_VERSION_INFO, /* Auto-initiated LE version done */
|
||||
|
||||
/* Total number of flags - must be at the end of the enum */
|
||||
BT_CONN_NUM_FLAGS,
|
||||
};
|
||||
|
||||
struct bt_conn_le {
|
||||
bt_addr_le_t dst;
|
||||
|
||||
bt_addr_le_t init_addr;
|
||||
bt_addr_le_t resp_addr;
|
||||
|
||||
u16_t interval;
|
||||
u16_t interval_min;
|
||||
u16_t interval_max;
|
||||
|
||||
u16_t latency;
|
||||
u16_t timeout;
|
||||
u16_t pending_latency;
|
||||
u16_t pending_timeout;
|
||||
|
||||
u8_t features[8];
|
||||
|
||||
struct bt_keys *keys;
|
||||
|
||||
#if defined(CONFIG_BT_STACK_PTS)
|
||||
u8_t own_adder_type;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(CONFIG_BT_BREDR)
|
||||
/* For now reserve space for 2 pages of LMP remote features */
|
||||
#define LMP_MAX_PAGES 2
|
||||
|
||||
struct bt_conn_br {
|
||||
bt_addr_t dst;
|
||||
u8_t remote_io_capa;
|
||||
u8_t remote_auth;
|
||||
u8_t pairing_method;
|
||||
/* remote LMP features pages per 8 bytes each */
|
||||
u8_t features[LMP_MAX_PAGES][8];
|
||||
|
||||
struct bt_keys_link_key *link_key;
|
||||
};
|
||||
|
||||
struct bt_conn_sco {
|
||||
/* Reference to ACL Connection */
|
||||
struct bt_conn *acl;
|
||||
u16_t pkt_type;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct bt_conn_iso {
|
||||
/* Reference to ACL Connection */
|
||||
struct bt_conn *acl;
|
||||
/* CIG ID */
|
||||
uint8_t cig_id;
|
||||
/* CIS ID */
|
||||
uint8_t cis_id;
|
||||
};
|
||||
|
||||
typedef void (*bt_conn_tx_cb_t)(struct bt_conn *conn, void *user_data);
|
||||
|
||||
struct bt_conn_tx {
|
||||
sys_snode_t node;
|
||||
|
||||
bt_conn_tx_cb_t cb;
|
||||
void *user_data;
|
||||
|
||||
/* Number of pending packets without a callback after this one */
|
||||
u32_t pending_no_cb;
|
||||
};
|
||||
|
||||
struct bt_conn {
|
||||
u16_t handle;
|
||||
u8_t type;
|
||||
u8_t role;
|
||||
|
||||
ATOMIC_DEFINE(flags, BT_CONN_NUM_FLAGS);
|
||||
|
||||
/* Which local identity address this connection uses */
|
||||
u8_t id;
|
||||
|
||||
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
|
||||
bt_security_t sec_level;
|
||||
bt_security_t required_sec_level;
|
||||
u8_t encrypt;
|
||||
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
|
||||
|
||||
/* Connection error or reason for disconnect */
|
||||
u8_t err;
|
||||
|
||||
bt_conn_state_t state;
|
||||
|
||||
u16_t rx_len;
|
||||
struct net_buf *rx;
|
||||
|
||||
/* Sent but not acknowledged TX packets with a callback */
|
||||
sys_slist_t tx_pending;
|
||||
/* Sent but not acknowledged TX packets without a callback before
|
||||
* the next packet (if any) in tx_pending.
|
||||
*/
|
||||
u32_t pending_no_cb;
|
||||
|
||||
/* Completed TX for which we need to call the callback */
|
||||
sys_slist_t tx_complete;
|
||||
struct k_work tx_complete_work;
|
||||
|
||||
/* Queue for outgoing ACL data */
|
||||
struct k_fifo tx_queue;
|
||||
|
||||
/* Active L2CAP channels */
|
||||
sys_slist_t channels;
|
||||
|
||||
atomic_t ref;
|
||||
|
||||
/* Delayed work for connection update and other deferred tasks */
|
||||
struct k_delayed_work update_work;
|
||||
|
||||
union {
|
||||
struct bt_conn_le le;
|
||||
#if defined(CONFIG_BT_BREDR)
|
||||
struct bt_conn_br br;
|
||||
struct bt_conn_sco sco;
|
||||
#endif
|
||||
#if defined(CONFIG_BT_AUDIO)
|
||||
struct bt_conn_iso iso;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(CONFIG_BT_REMOTE_VERSION)
|
||||
struct bt_conn_rv {
|
||||
u8_t version;
|
||||
u16_t manufacturer;
|
||||
u16_t subversion;
|
||||
} rv;
|
||||
#endif
|
||||
};
|
||||
|
||||
void bt_conn_reset_rx_state(struct bt_conn *conn);
|
||||
|
||||
/* Process incoming data for a connection */
|
||||
void bt_conn_recv(struct bt_conn *conn, struct net_buf *buf, u8_t flags);
|
||||
|
||||
/* Send data over a connection */
|
||||
int bt_conn_send_cb(struct bt_conn *conn, struct net_buf *buf,
|
||||
bt_conn_tx_cb_t cb, void *user_data);
|
||||
|
||||
static inline int bt_conn_send(struct bt_conn *conn, struct net_buf *buf)
|
||||
{
|
||||
return bt_conn_send_cb(conn, buf, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Add a new LE connection */
|
||||
struct bt_conn *bt_conn_add_le(u8_t id, const bt_addr_le_t *peer);
|
||||
|
||||
/** Connection parameters for ISO connections */
|
||||
struct bt_iso_create_param {
|
||||
uint8_t id;
|
||||
uint8_t num_conns;
|
||||
struct bt_conn **conns;
|
||||
struct bt_iso_chan **chans;
|
||||
};
|
||||
|
||||
/* Bind ISO connections parameters */
|
||||
int bt_conn_bind_iso(struct bt_iso_create_param *param);
|
||||
|
||||
/* Connect ISO connections */
|
||||
int bt_conn_connect_iso(struct bt_conn **conns, uint8_t num_conns);
|
||||
|
||||
/* Add a new ISO connection */
|
||||
struct bt_conn *bt_conn_add_iso(struct bt_conn *acl);
|
||||
|
||||
/* Cleanup ISO references */
|
||||
void bt_iso_cleanup(struct bt_conn *iso_conn);
|
||||
|
||||
/* Allocate new ISO connection */
|
||||
struct bt_conn *iso_conn_new(struct bt_conn *conns, size_t size);
|
||||
|
||||
/* Add a new BR/EDR connection */
|
||||
struct bt_conn *bt_conn_add_br(const bt_addr_t *peer);
|
||||
|
||||
/* Add a new SCO connection */
|
||||
struct bt_conn *bt_conn_add_sco(const bt_addr_t *peer, int link_type);
|
||||
|
||||
/* Cleanup SCO references */
|
||||
void bt_sco_cleanup(struct bt_conn *sco_conn);
|
||||
|
||||
/* Look up an existing sco connection by BT address */
|
||||
struct bt_conn *bt_conn_lookup_addr_sco(const bt_addr_t *peer);
|
||||
|
||||
/* Look up an existing connection by BT address */
|
||||
struct bt_conn *bt_conn_lookup_addr_br(const bt_addr_t *peer);
|
||||
|
||||
void bt_conn_pin_code_req(struct bt_conn *conn);
|
||||
u8_t bt_conn_get_io_capa(void);
|
||||
u8_t bt_conn_ssp_get_auth(const struct bt_conn *conn);
|
||||
void bt_conn_ssp_auth(struct bt_conn *conn, u32_t passkey);
|
||||
void bt_conn_ssp_auth_complete(struct bt_conn *conn, u8_t status);
|
||||
|
||||
void bt_conn_disconnect_all(u8_t id);
|
||||
|
||||
/* Look up an existing connection */
|
||||
struct bt_conn *bt_conn_lookup_handle(u16_t handle);
|
||||
|
||||
/* Compare an address with bt_conn destination address */
|
||||
int bt_conn_addr_le_cmp(const struct bt_conn *conn, const bt_addr_le_t *peer);
|
||||
|
||||
/* Helpers for identifying & looking up connections based on the the index to
|
||||
* the connection list. This is useful for O(1) lookups, but can't be used
|
||||
* e.g. as the handle since that's assigned to us by the controller.
|
||||
*/
|
||||
#define BT_CONN_ID_INVALID 0xff
|
||||
struct bt_conn *bt_conn_lookup_id(u8_t id);
|
||||
|
||||
/* Look up a connection state. For BT_ADDR_LE_ANY, returns the first connection
|
||||
* with the specific state
|
||||
*/
|
||||
struct bt_conn *bt_conn_lookup_state_le(const bt_addr_le_t *peer,
|
||||
const bt_conn_state_t state);
|
||||
|
||||
/* Set connection object in certain state and perform action related to state */
|
||||
void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state);
|
||||
|
||||
int bt_conn_le_conn_update(struct bt_conn *conn,
|
||||
const struct bt_le_conn_param *param);
|
||||
|
||||
void notify_remote_info(struct bt_conn *conn);
|
||||
|
||||
void notify_le_param_updated(struct bt_conn *conn);
|
||||
|
||||
bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param);
|
||||
|
||||
#if defined(CONFIG_BT_SMP)
|
||||
/* rand and ediv should be in BT order */
|
||||
int bt_conn_le_start_encryption(struct bt_conn *conn, u8_t rand[8],
|
||||
u8_t ediv[2], const u8_t *ltk, size_t len);
|
||||
|
||||
/* Notify higher layers that RPA was resolved */
|
||||
void bt_conn_identity_resolved(struct bt_conn *conn);
|
||||
#endif /* CONFIG_BT_SMP */
|
||||
|
||||
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
|
||||
/* Notify higher layers that connection security changed */
|
||||
void bt_conn_security_changed(struct bt_conn *conn, enum bt_security_err err);
|
||||
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
|
||||
|
||||
/* Prepare a PDU to be sent over a connection */
|
||||
#if defined(CONFIG_NET_BUF_LOG)
|
||||
struct net_buf *bt_conn_create_pdu_timeout_debug(struct net_buf_pool *pool,
|
||||
size_t reserve, s32_t timeout,
|
||||
const char *func, int line);
|
||||
#define bt_conn_create_pdu_timeout(_pool, _reserve, _timeout) \
|
||||
bt_conn_create_pdu_timeout_debug(_pool, _reserve, _timeout, \
|
||||
__func__, __LINE__)
|
||||
|
||||
#define bt_conn_create_pdu(_pool, _reserve) \
|
||||
bt_conn_create_pdu_timeout_debug(_pool, _reserve, K_FOREVER, \
|
||||
__func__, __line__)
|
||||
#else
|
||||
struct net_buf *bt_conn_create_pdu_timeout(struct net_buf_pool *pool,
|
||||
size_t reserve, s32_t timeout);
|
||||
|
||||
#define bt_conn_create_pdu(_pool, _reserve) \
|
||||
bt_conn_create_pdu_timeout(_pool, _reserve, K_FOREVER)
|
||||
#endif
|
||||
|
||||
/* Prepare a PDU to be sent over a connection */
|
||||
#if defined(CONFIG_NET_BUF_LOG)
|
||||
struct net_buf *bt_conn_create_frag_timeout_debug(size_t reserve, s32_t timeout,
|
||||
const char *func, int line);
|
||||
|
||||
#define bt_conn_create_frag_timeout(_reserve, _timeout) \
|
||||
bt_conn_create_frag_timeout_debug(_reserve, _timeout, \
|
||||
__func__, __LINE__)
|
||||
|
||||
#define bt_conn_create_frag(_reserve) \
|
||||
bt_conn_create_frag_timeout_debug(_reserve, K_FOREVER, \
|
||||
__func__, __LINE__)
|
||||
#else
|
||||
struct net_buf *bt_conn_create_frag_timeout(size_t reserve, s32_t timeout);
|
||||
|
||||
#define bt_conn_create_frag(_reserve) \
|
||||
bt_conn_create_frag_timeout(_reserve, K_FOREVER)
|
||||
#endif
|
||||
|
||||
/* Initialize connection management */
|
||||
int bt_conn_init(void);
|
||||
|
||||
/* Selects based on connecton type right semaphore for ACL packets */
|
||||
struct k_sem *bt_conn_get_pkts(struct bt_conn *conn);
|
||||
|
||||
/* k_poll related helpers for the TX thread */
|
||||
int bt_conn_prepare_events(struct k_poll_event events[]);
|
||||
void bt_conn_process_tx(struct bt_conn *conn);
|
||||
|
||||
#if defined(BFLB_BLE)
|
||||
/** @brief Get connection handle for a connection.
|
||||
*
|
||||
* @param conn Connection object.
|
||||
* @param conn_handle Place to store the Connection handle.
|
||||
*
|
||||
* @return 0 on success or negative error value on failure.
|
||||
*/
|
||||
int bt_hci_get_conn_handle(const struct bt_conn *conn, u16_t *conn_handle);
|
||||
#endif
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <misc/byteorder.h>
|
||||
|
||||
#include <bluetooth.h>
|
||||
#include <hci_host.h>
|
||||
#include <conn.h>
|
||||
|
||||
#include <constants.h>
|
||||
#include <hmac_prng.h>
|
||||
#include <aes.h>
|
||||
#include <utils.h>
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE)
|
||||
#define LOG_MODULE_NAME bt_crypto
|
||||
#include "log.h"
|
||||
|
||||
#include "hci_core.h"
|
||||
|
||||
static struct tc_hmac_prng_struct prng;
|
||||
|
||||
static int prng_reseed(struct tc_hmac_prng_struct *h)
|
||||
{
|
||||
u8_t seed[32];
|
||||
s64_t extra;
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < (sizeof(seed) / 8); i++) {
|
||||
struct bt_hci_rp_le_rand *rp;
|
||||
struct net_buf *rsp;
|
||||
|
||||
ret = bt_hci_cmd_send_sync(BT_HCI_OP_LE_RAND, NULL, &rsp);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
rp = (void *)rsp->data;
|
||||
memcpy(&seed[i * 8], rp->rand, 8);
|
||||
|
||||
net_buf_unref(rsp);
|
||||
}
|
||||
|
||||
extra = k_uptime_get();
|
||||
|
||||
ret = tc_hmac_prng_reseed(h, seed, sizeof(seed), (u8_t *)&extra,
|
||||
sizeof(extra));
|
||||
if (ret == TC_CRYPTO_FAIL) {
|
||||
BT_ERR("Failed to re-seed PRNG");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prng_init(void)
|
||||
{
|
||||
struct bt_hci_rp_le_rand *rp;
|
||||
struct net_buf *rsp;
|
||||
int ret;
|
||||
|
||||
/* Check first that HCI_LE_Rand is supported */
|
||||
if (!BT_CMD_TEST(bt_dev.supported_commands, 27, 7)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
ret = bt_hci_cmd_send_sync(BT_HCI_OP_LE_RAND, NULL, &rsp);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
rp = (void *)rsp->data;
|
||||
|
||||
ret = tc_hmac_prng_init(&prng, rp->rand, sizeof(rp->rand));
|
||||
|
||||
net_buf_unref(rsp);
|
||||
|
||||
if (ret == TC_CRYPTO_FAIL) {
|
||||
BT_ERR("Failed to initialize PRNG");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* re-seed is needed after init */
|
||||
return prng_reseed(&prng);
|
||||
}
|
||||
|
||||
int bt_rand(void *buf, size_t len)
|
||||
{
|
||||
#if !defined(CONFIG_BT_GEN_RANDOM_BY_SW)
|
||||
k_get_random_byte_array(buf, len);
|
||||
return 0;
|
||||
#else
|
||||
int ret;
|
||||
ret = tc_hmac_prng_generate(buf, len, &prng);
|
||||
if (ret == TC_HMAC_PRNG_RESEED_REQ) {
|
||||
ret = prng_reseed(&prng);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tc_hmac_prng_generate(buf, len, &prng);
|
||||
}
|
||||
|
||||
if (ret == TC_CRYPTO_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
#endif
|
||||
}
|
||||
|
||||
int bt_encrypt_le(const u8_t key[16], const u8_t plaintext[16],
|
||||
u8_t enc_data[16])
|
||||
{
|
||||
struct tc_aes_key_sched_struct s;
|
||||
u8_t tmp[16];
|
||||
|
||||
BT_DBG("key %s", bt_hex(key, 16));
|
||||
BT_DBG("plaintext %s", bt_hex(plaintext, 16));
|
||||
|
||||
sys_memcpy_swap(tmp, key, 16);
|
||||
|
||||
if (tc_aes128_set_encrypt_key(&s, tmp) == TC_CRYPTO_FAIL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sys_memcpy_swap(tmp, plaintext, 16);
|
||||
|
||||
if (tc_aes_encrypt(enc_data, tmp, &s) == TC_CRYPTO_FAIL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sys_mem_swap(enc_data, 16);
|
||||
|
||||
BT_DBG("enc_data %s", bt_hex(enc_data, 16));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_encrypt_be(const u8_t key[16], const u8_t plaintext[16],
|
||||
u8_t enc_data[16])
|
||||
{
|
||||
struct tc_aes_key_sched_struct s;
|
||||
|
||||
BT_DBG("key %s", bt_hex(key, 16));
|
||||
BT_DBG("plaintext %s", bt_hex(plaintext, 16));
|
||||
|
||||
if (tc_aes128_set_encrypt_key(&s, key) == TC_CRYPTO_FAIL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tc_aes_encrypt(enc_data, plaintext, &s) == TC_CRYPTO_FAIL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
BT_DBG("enc_data %s", bt_hex(enc_data, 16));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
int prng_init(void);
|
||||
@@ -0,0 +1,63 @@
|
||||
/* ecc.h - ECDH helpers */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* @brief Container for public key callback */
|
||||
struct bt_pub_key_cb {
|
||||
/** @brief Callback type for Public Key generation.
|
||||
*
|
||||
* Used to notify of the local public key or that the local key is not
|
||||
* available (either because of a failure to read it or because it is
|
||||
* being regenerated).
|
||||
*
|
||||
* @param key The local public key, or NULL in case of no key.
|
||||
*/
|
||||
void (*func)(const u8_t key[64]);
|
||||
|
||||
struct bt_pub_key_cb *_next;
|
||||
};
|
||||
|
||||
/* @brief Generate a new Public Key.
|
||||
*
|
||||
* Generate a new ECC Public Key. The callback will persist even after the
|
||||
* key has been generated, and will be used to notify of new generation
|
||||
* processes (NULL as key).
|
||||
*
|
||||
* @param cb Callback to notify the new key, or NULL to request an update
|
||||
* without registering any new callback.
|
||||
*
|
||||
* @return Zero on success or negative error code otherwise
|
||||
*/
|
||||
int bt_pub_key_gen(struct bt_pub_key_cb *cb);
|
||||
|
||||
/* @brief Get the current Public Key.
|
||||
*
|
||||
* Get the current ECC Public Key.
|
||||
*
|
||||
* @return Current key, or NULL if not available.
|
||||
*/
|
||||
const u8_t *bt_pub_key_get(void);
|
||||
|
||||
/* @typedef bt_dh_key_cb_t
|
||||
* @brief Callback type for DH Key calculation.
|
||||
*
|
||||
* Used to notify of the calculated DH Key.
|
||||
*
|
||||
* @param key The DH Key, or NULL in case of failure.
|
||||
*/
|
||||
typedef void (*bt_dh_key_cb_t)(const u8_t key[32]);
|
||||
|
||||
/* @brief Calculate a DH Key from a remote Public Key.
|
||||
*
|
||||
* Calculate a DH Key from the remote Public Key.
|
||||
*
|
||||
* @param remote_pk Remote Public Key.
|
||||
* @param cb Callback to notify the calculated key.
|
||||
*
|
||||
* @return Zero on success or negative error code otherwise
|
||||
*/
|
||||
int bt_dh_key_gen(const u8_t remote_pk[64], bt_dh_key_cb_t cb);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
/** @file
|
||||
* @brief Internal API for Generic Attribute Profile handling.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define BT_GATT_CENTRAL_ADDR_RES_NOT_SUPP 0
|
||||
#define BT_GATT_CENTRAL_ADDR_RES_SUPP 1
|
||||
|
||||
#include <gatt.h>
|
||||
|
||||
#define BT_GATT_PERM_READ_MASK (BT_GATT_PERM_READ | \
|
||||
BT_GATT_PERM_READ_ENCRYPT | \
|
||||
BT_GATT_PERM_READ_AUTHEN)
|
||||
#define BT_GATT_PERM_WRITE_MASK (BT_GATT_PERM_WRITE | \
|
||||
BT_GATT_PERM_WRITE_ENCRYPT | \
|
||||
BT_GATT_PERM_WRITE_AUTHEN)
|
||||
#define BT_GATT_PERM_ENCRYPT_MASK (BT_GATT_PERM_READ_ENCRYPT | \
|
||||
BT_GATT_PERM_WRITE_ENCRYPT)
|
||||
#define BT_GATT_PERM_AUTHEN_MASK (BT_GATT_PERM_READ_AUTHEN | \
|
||||
BT_GATT_PERM_WRITE_AUTHEN)
|
||||
|
||||
void bt_gatt_init(void);
|
||||
#if defined(BFLB_BLE)
|
||||
void bt_gatt_deinit(void);
|
||||
#endif
|
||||
void bt_gatt_connected(struct bt_conn *conn);
|
||||
void bt_gatt_encrypt_change(struct bt_conn *conn);
|
||||
void bt_gatt_disconnected(struct bt_conn *conn);
|
||||
|
||||
bool bt_gatt_change_aware(struct bt_conn *conn, bool req);
|
||||
|
||||
int bt_gatt_store_ccc(u8_t id, const bt_addr_le_t *addr);
|
||||
|
||||
int bt_gatt_clear(u8_t id, const bt_addr_le_t *addr);
|
||||
|
||||
#if defined(BFLB_BLE_MTU_CHANGE_CB)
|
||||
void bt_gatt_mtu_changed(struct bt_conn *conn, u16_t mtu);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_GATT_CLIENT)
|
||||
void bt_gatt_notification(struct bt_conn *conn, u16_t handle,
|
||||
const void *data, u16_t length);
|
||||
#else
|
||||
static inline void bt_gatt_notification(struct bt_conn *conn, u16_t handle,
|
||||
const void *data, u16_t length)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_BT_GATT_CLIENT */
|
||||
|
||||
struct bt_gatt_attr;
|
||||
|
||||
/* Check attribute permission */
|
||||
u8_t bt_gatt_check_perm(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||
u8_t mask);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,285 @@
|
||||
/* hci_core.h - Bluetooth HCI core access */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* LL connection parameters */
|
||||
#define LE_CONN_LATENCY 0x0000
|
||||
#define LE_CONN_TIMEOUT 0x002a
|
||||
|
||||
#if defined(CONFIG_BT_BREDR)
|
||||
#define LMP_FEAT_PAGES_COUNT 3
|
||||
#else
|
||||
#define LMP_FEAT_PAGES_COUNT 1
|
||||
#endif
|
||||
|
||||
/* SCO settings */
|
||||
#define BT_VOICE_CVSD_16BIT 0x0060
|
||||
#define BT_VOICE_MSBC_16BIT 0x0063
|
||||
|
||||
/* k_poll event tags */
|
||||
enum {
|
||||
BT_EVENT_CMD_TX,
|
||||
BT_EVENT_CONN_TX_QUEUE,
|
||||
};
|
||||
|
||||
/* bt_dev flags: the flags defined here represent BT controller state */
|
||||
enum {
|
||||
BT_DEV_ENABLE,
|
||||
BT_DEV_READY,
|
||||
BT_DEV_PRESET_ID,
|
||||
BT_DEV_USER_ID_ADDR,
|
||||
BT_DEV_HAS_PUB_KEY,
|
||||
BT_DEV_PUB_KEY_BUSY,
|
||||
|
||||
BT_DEV_ADVERTISING,
|
||||
BT_DEV_ADVERTISING_NAME,
|
||||
BT_DEV_ADVERTISING_CONNECTABLE,
|
||||
BT_DEV_KEEP_ADVERTISING,
|
||||
BT_DEV_SCANNING,
|
||||
BT_DEV_EXPLICIT_SCAN,
|
||||
BT_DEV_ACTIVE_SCAN,
|
||||
BT_DEV_SCAN_FILTER_DUP,
|
||||
BT_DEV_SCAN_WL,
|
||||
BT_DEV_AUTO_CONN,
|
||||
|
||||
BT_DEV_RPA_VALID,
|
||||
|
||||
BT_DEV_ID_PENDING,
|
||||
|
||||
#if defined(CONFIG_BT_BREDR)
|
||||
BT_DEV_ISCAN,
|
||||
BT_DEV_PSCAN,
|
||||
BT_DEV_INQUIRY,
|
||||
#endif /* CONFIG_BT_BREDR */
|
||||
|
||||
#if defined(CONFIG_BT_STACK_PTS)
|
||||
BT_DEV_ADV_ADDRESS_IS_PUBLIC,
|
||||
#endif
|
||||
|
||||
#if defined(BFLB_HOST_ASSISTANT)
|
||||
BT_DEV_ASSIST_RUN,
|
||||
#endif
|
||||
|
||||
/* Total number of flags - must be at the end of the enum */
|
||||
BT_DEV_NUM_FLAGS,
|
||||
};
|
||||
|
||||
/* Flags which should not be cleared upon HCI_Reset */
|
||||
#define BT_DEV_PERSISTENT_FLAGS (BIT(BT_DEV_ENABLE) | \
|
||||
BIT(BT_DEV_PRESET_ID) | \
|
||||
BIT(BT_DEV_USER_ID_ADDR))
|
||||
|
||||
struct bt_dev_le {
|
||||
/* LE features */
|
||||
u8_t features[8];
|
||||
/* LE states */
|
||||
u64_t states;
|
||||
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
/* Controller buffer information */
|
||||
u16_t mtu;
|
||||
struct k_sem pkts;
|
||||
#endif /* CONFIG_BT_CONN */
|
||||
|
||||
#if defined(CONFIG_BT_SMP)
|
||||
/* Size of the the controller resolving list */
|
||||
u8_t rl_size;
|
||||
/* Number of entries in the resolving list. rl_entries > rl_size
|
||||
* means that host-side resolving is used.
|
||||
*/
|
||||
u8_t rl_entries;
|
||||
#endif /* CONFIG_BT_SMP */
|
||||
|
||||
#if defined(CONFIG_BT_WHITELIST)
|
||||
/* Size of the controller whitelist. */
|
||||
u8_t wl_size;
|
||||
/* Number of entries in the resolving list. */
|
||||
u8_t wl_entries;
|
||||
#endif /* CONFIG_BT_WHITELIST */
|
||||
};
|
||||
|
||||
#if defined(CONFIG_BT_BREDR)
|
||||
struct bt_dev_br {
|
||||
/* Max controller's acceptable ACL packet length */
|
||||
u16_t mtu;
|
||||
struct k_sem pkts;
|
||||
u16_t esco_pkt_type;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* The theoretical max for these is 8 and 64, but there's no point
|
||||
* in allocating the full memory if we only support a small subset.
|
||||
* These values must be updated whenever the host implementation is
|
||||
* extended beyond the current values.
|
||||
*/
|
||||
#define BT_DEV_VS_FEAT_MAX 1
|
||||
#define BT_DEV_VS_CMDS_MAX 2
|
||||
|
||||
/* State tracking for the local Bluetooth controller */
|
||||
struct bt_dev {
|
||||
/* Local Identity Address(es) */
|
||||
bt_addr_le_t id_addr[CONFIG_BT_ID_MAX];
|
||||
u8_t id_count;
|
||||
|
||||
/* ID Address used for advertising */
|
||||
u8_t adv_id;
|
||||
|
||||
/* Current local Random Address */
|
||||
bt_addr_le_t random_addr;
|
||||
|
||||
/* Controller version & manufacturer information */
|
||||
u8_t hci_version;
|
||||
u8_t lmp_version;
|
||||
u16_t hci_revision;
|
||||
u16_t lmp_subversion;
|
||||
u16_t manufacturer;
|
||||
|
||||
/* LMP features (pages 0, 1, 2) */
|
||||
u8_t features[LMP_FEAT_PAGES_COUNT][8];
|
||||
|
||||
/* Supported commands */
|
||||
u8_t supported_commands[64];
|
||||
|
||||
#if defined(CONFIG_BT_HCI_VS_EXT)
|
||||
/* Vendor HCI support */
|
||||
u8_t vs_features[BT_DEV_VS_FEAT_MAX];
|
||||
u8_t vs_commands[BT_DEV_VS_CMDS_MAX];
|
||||
#endif
|
||||
|
||||
struct k_work init;
|
||||
|
||||
ATOMIC_DEFINE(flags, BT_DEV_NUM_FLAGS);
|
||||
|
||||
/* LE controller specific features */
|
||||
struct bt_dev_le le;
|
||||
|
||||
#if defined(CONFIG_BT_BREDR)
|
||||
/* BR/EDR controller specific features */
|
||||
struct bt_dev_br br;
|
||||
#endif
|
||||
|
||||
/* Number of commands controller can accept */
|
||||
struct k_sem ncmd_sem;
|
||||
|
||||
/* Last sent HCI command */
|
||||
struct net_buf *sent_cmd;
|
||||
|
||||
#if !defined(CONFIG_BT_RECV_IS_RX_THREAD)
|
||||
/* Queue for incoming HCI events & ACL data */
|
||||
struct k_fifo rx_queue;
|
||||
#endif
|
||||
|
||||
/* Queue for outgoing HCI commands */
|
||||
struct k_fifo cmd_tx_queue;
|
||||
|
||||
/* Registered HCI driver */
|
||||
const struct bt_hci_driver *drv;
|
||||
|
||||
#if defined(CONFIG_BT_PRIVACY)
|
||||
/* Local Identity Resolving Key */
|
||||
u8_t irk[CONFIG_BT_ID_MAX][16];
|
||||
|
||||
/* Work used for RPA rotation */
|
||||
struct k_delayed_work rpa_update;
|
||||
#endif
|
||||
|
||||
/* Local Name */
|
||||
#if defined(CONFIG_BT_DEVICE_NAME_DYNAMIC)
|
||||
char name[CONFIG_BT_DEVICE_NAME_MAX + 1];
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(CONFIG_BT_STACK_PTS)
|
||||
typedef enum __packed {
|
||||
dir_connect_req = 0x01, /*Send a direct connection require while the Lower test enters direct mode .*/
|
||||
|
||||
ad_type_service_uuid = 0x02,
|
||||
ad_type_local_name = 0x03,
|
||||
ad_type_flags = 0x04,
|
||||
ad_type_manu_data = 0x05,
|
||||
ad_type_tx_power_level = 0x06,
|
||||
ad_type_service_data = 0x07,
|
||||
ad_type_appearance = 0x08,
|
||||
|
||||
gatt_discover_chara = 0x09,
|
||||
gatt_exec_write_req = 0x0a,
|
||||
gatt_cancel_write_req = 0x0b,
|
||||
att_read_by_group_type_ind = 0x0c, /* CASE : GATT/SR/GAD/BV-01-C. Indicate PTS sends a GATT discover all primary services request to iut */
|
||||
att_find_by_type_value_ind = 0x0d, /* CASE : GATT/SR/GAD/BV-02-C. Indicate PTS sends a request to iut for discover it contains Primary Services by Service UUID */
|
||||
att_read_by_type_ind = 0x0e, /* CASE : GATT/SR/GAD/BV-04-C. Indicate PTS sends a request to iut for discover all characteristics of a specified service.*/
|
||||
|
||||
own_addr_type_random = 0x0f
|
||||
} event_id;
|
||||
|
||||
#endif
|
||||
|
||||
extern struct bt_dev bt_dev;
|
||||
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
|
||||
extern const struct bt_conn_auth_cb *bt_auth;
|
||||
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
|
||||
|
||||
bool bt_le_conn_params_valid(const struct bt_le_conn_param *param);
|
||||
|
||||
int bt_le_scan_update(bool fast_scan);
|
||||
|
||||
int bt_le_auto_conn(const struct bt_le_conn_param *conn_param);
|
||||
int bt_le_auto_conn_cancel(void);
|
||||
|
||||
bool bt_addr_le_is_bonded(u8_t id, const bt_addr_le_t *addr);
|
||||
const bt_addr_le_t *bt_lookup_id_addr(u8_t id, const bt_addr_le_t *addr);
|
||||
|
||||
int bt_send(struct net_buf *buf);
|
||||
|
||||
/* Don't require everyone to include keys.h */
|
||||
struct bt_keys;
|
||||
void bt_id_add(struct bt_keys *keys);
|
||||
void bt_id_del(struct bt_keys *keys);
|
||||
|
||||
int bt_setup_id_addr(void);
|
||||
void bt_finalize_init(void);
|
||||
|
||||
int bt_le_adv_start_internal(const struct bt_le_adv_param *param,
|
||||
const struct bt_data *ad, size_t ad_len,
|
||||
const struct bt_data *sd, size_t sd_len,
|
||||
const bt_addr_le_t *peer);
|
||||
#if defined(CONFIG_BLE_MULTI_ADV)
|
||||
int bt_le_adv_start_instant(const struct bt_le_adv_param *param,
|
||||
const uint8_t *ad_data, size_t ad_len,
|
||||
const uint8_t *sd_data, size_t sd_len);
|
||||
#endif
|
||||
|
||||
#if defined(BFLB_BLE)
|
||||
|
||||
int bt_le_read_rssi(u16_t handle, int8_t *rssi);
|
||||
int set_ad_and_rsp_d(u16_t hci_op, u8_t *data, u32_t ad_len);
|
||||
int set_adv_enable(bool enable);
|
||||
int set_adv_param(const struct bt_le_adv_param *param);
|
||||
int set_adv_channel_map(u8_t channel);
|
||||
int bt_get_local_public_address(bt_addr_le_t *adv_addr);
|
||||
int bt_get_local_ramdon_address(bt_addr_le_t *adv_addr);
|
||||
int bt_le_set_data_len(struct bt_conn *conn, u16_t tx_octets, u16_t tx_time);
|
||||
int hci_le_set_phy(struct bt_conn *conn);
|
||||
int hci_le_set_default_phy(struct bt_conn *conn, u8_t default_phy);
|
||||
|
||||
#if defined(CONFIG_SET_TX_PWR)
|
||||
int bt_set_tx_pwr(int8_t power);
|
||||
#endif
|
||||
|
||||
#if defined(BFLB_HOST_ASSISTANT)
|
||||
struct blhast_cb {
|
||||
void (*le_scan_cb)(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb);
|
||||
void (*le_adv_cb)(const struct bt_le_adv_param *param, const struct bt_data *ad,
|
||||
size_t ad_len, const struct bt_data *sd, size_t sd_len);
|
||||
};
|
||||
int bt_set_flow_control(void);
|
||||
int bt_set_event_mask(void);
|
||||
int bt_le_set_event_mask(void);
|
||||
void bt_hci_reset_complete(struct net_buf *buf);
|
||||
void bt_register_host_assist_cb(struct blhast_cb *cb);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,340 @@
|
||||
/**
|
||||
* @file hci_ecc.c
|
||||
* HCI ECC emulation
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <atomic.h>
|
||||
#include <misc/stack.h>
|
||||
#include <misc/byteorder.h>
|
||||
#include <constants.h>
|
||||
#include <utils.h>
|
||||
#include <ecc.h>
|
||||
#include <ecc_dh.h>
|
||||
|
||||
#include <bluetooth.h>
|
||||
#include <conn.h>
|
||||
#include <hci_host.h>
|
||||
#include <hci_driver.h>
|
||||
#include <../include/bluetooth/crypto.h>
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE)
|
||||
#include "log.h"
|
||||
|
||||
#include "hci_ecc.h"
|
||||
#ifdef CONFIG_BT_HCI_RAW
|
||||
#include <bluetooth/hci_raw.h>
|
||||
#include "hci_raw_internal.h"
|
||||
#else
|
||||
#include "hci_core.h"
|
||||
#endif
|
||||
|
||||
static struct k_thread ecc_thread_data;
|
||||
#if !defined(BFLB_BLE)
|
||||
static BT_STACK_NOINIT(ecc_thread_stack, 1024);
|
||||
#endif
|
||||
|
||||
/* based on Core Specification 4.2 Vol 3. Part H 2.3.5.6.1 */
|
||||
static const u32_t debug_private_key[8] = {
|
||||
0xcd3c1abd, 0x5899b8a6, 0xeb40b799, 0x4aff607b, 0xd2103f50, 0x74c9b3e3,
|
||||
0xa3c55f38, 0x3f49f6d4
|
||||
};
|
||||
|
||||
#if defined(CONFIG_BT_USE_DEBUG_KEYS)
|
||||
static const u8_t debug_public_key[64] = {
|
||||
0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc, 0xdb, 0xfd, 0xf4, 0xac,
|
||||
0x11, 0x91, 0xf4, 0xef, 0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
|
||||
0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20, 0x8b, 0xd2, 0x89, 0x15,
|
||||
0xd0, 0x8e, 0x1c, 0x74, 0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76,
|
||||
0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63, 0x6d, 0xeb, 0x2a, 0x65,
|
||||
0x49, 0x9c, 0x80, 0xdc
|
||||
};
|
||||
#endif
|
||||
|
||||
enum {
|
||||
PENDING_PUB_KEY,
|
||||
PENDING_DHKEY,
|
||||
|
||||
/* Total number of flags - must be at the end of the enum */
|
||||
NUM_FLAGS,
|
||||
};
|
||||
|
||||
static ATOMIC_DEFINE(flags, NUM_FLAGS);
|
||||
|
||||
static K_SEM_DEFINE(cmd_sem, 0, 1);
|
||||
|
||||
static struct {
|
||||
u8_t private_key[32];
|
||||
|
||||
union {
|
||||
u8_t pk[64];
|
||||
u8_t dhkey[32];
|
||||
};
|
||||
} ecc;
|
||||
|
||||
static void send_cmd_status(u16_t opcode, u8_t status)
|
||||
{
|
||||
struct bt_hci_evt_cmd_status *evt;
|
||||
struct bt_hci_evt_hdr *hdr;
|
||||
struct net_buf *buf;
|
||||
|
||||
BT_DBG("opcode %x status %x", opcode, status);
|
||||
|
||||
buf = bt_buf_get_evt(BT_HCI_EVT_CMD_STATUS, false, K_FOREVER);
|
||||
bt_buf_set_type(buf, BT_BUF_EVT);
|
||||
|
||||
hdr = net_buf_add(buf, sizeof(*hdr));
|
||||
hdr->evt = BT_HCI_EVT_CMD_STATUS;
|
||||
hdr->len = sizeof(*evt);
|
||||
|
||||
evt = net_buf_add(buf, sizeof(*evt));
|
||||
evt->ncmd = 1U;
|
||||
evt->opcode = sys_cpu_to_le16(opcode);
|
||||
evt->status = status;
|
||||
|
||||
bt_recv_prio(buf);
|
||||
}
|
||||
|
||||
static u8_t generate_keys(void)
|
||||
{
|
||||
#if !defined(CONFIG_BT_USE_DEBUG_KEYS)
|
||||
do {
|
||||
int rc;
|
||||
|
||||
rc = uECC_make_key(ecc.pk, ecc.private_key, &curve_secp256r1);
|
||||
if (rc == TC_CRYPTO_FAIL) {
|
||||
BT_ERR("Failed to create ECC public/private pair");
|
||||
return BT_HCI_ERR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
/* make sure generated key isn't debug key */
|
||||
} while (memcmp(ecc.private_key, debug_private_key, 32) == 0);
|
||||
#else
|
||||
sys_memcpy_swap(&ecc.pk, debug_public_key, 32);
|
||||
sys_memcpy_swap(&ecc.pk[32], &debug_public_key[32], 32);
|
||||
sys_memcpy_swap(ecc.private_key, debug_private_key, 32);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void emulate_le_p256_public_key_cmd(void)
|
||||
{
|
||||
struct bt_hci_evt_le_p256_public_key_complete *evt;
|
||||
struct bt_hci_evt_le_meta_event *meta;
|
||||
struct bt_hci_evt_hdr *hdr;
|
||||
struct net_buf *buf;
|
||||
u8_t status;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
status = generate_keys();
|
||||
|
||||
buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER);
|
||||
|
||||
hdr = net_buf_add(buf, sizeof(*hdr));
|
||||
hdr->evt = BT_HCI_EVT_LE_META_EVENT;
|
||||
hdr->len = sizeof(*meta) + sizeof(*evt);
|
||||
|
||||
meta = net_buf_add(buf, sizeof(*meta));
|
||||
meta->subevent = BT_HCI_EVT_LE_P256_PUBLIC_KEY_COMPLETE;
|
||||
|
||||
evt = net_buf_add(buf, sizeof(*evt));
|
||||
evt->status = status;
|
||||
|
||||
if (status) {
|
||||
(void)memset(evt->key, 0, sizeof(evt->key));
|
||||
} else {
|
||||
/* Convert X and Y coordinates from big-endian (provided
|
||||
* by crypto API) to little endian HCI.
|
||||
*/
|
||||
sys_memcpy_swap(evt->key, ecc.pk, 32);
|
||||
sys_memcpy_swap(&evt->key[32], &ecc.pk[32], 32);
|
||||
}
|
||||
|
||||
atomic_clear_bit(flags, PENDING_PUB_KEY);
|
||||
|
||||
bt_recv(buf);
|
||||
}
|
||||
|
||||
static void emulate_le_generate_dhkey(void)
|
||||
{
|
||||
struct bt_hci_evt_le_generate_dhkey_complete *evt;
|
||||
struct bt_hci_evt_le_meta_event *meta;
|
||||
struct bt_hci_evt_hdr *hdr;
|
||||
struct net_buf *buf;
|
||||
int ret;
|
||||
|
||||
ret = uECC_valid_public_key(ecc.pk, &curve_secp256r1);
|
||||
if (ret < 0) {
|
||||
BT_ERR("public key is not valid (ret %d)", ret);
|
||||
ret = TC_CRYPTO_FAIL;
|
||||
} else {
|
||||
ret = uECC_shared_secret(ecc.pk, ecc.private_key, ecc.dhkey,
|
||||
&curve_secp256r1);
|
||||
}
|
||||
|
||||
buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER);
|
||||
|
||||
hdr = net_buf_add(buf, sizeof(*hdr));
|
||||
hdr->evt = BT_HCI_EVT_LE_META_EVENT;
|
||||
hdr->len = sizeof(*meta) + sizeof(*evt);
|
||||
|
||||
meta = net_buf_add(buf, sizeof(*meta));
|
||||
meta->subevent = BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE;
|
||||
|
||||
evt = net_buf_add(buf, sizeof(*evt));
|
||||
|
||||
if (ret == TC_CRYPTO_FAIL) {
|
||||
evt->status = BT_HCI_ERR_UNSPECIFIED;
|
||||
(void)memset(evt->dhkey, 0, sizeof(evt->dhkey));
|
||||
} else {
|
||||
evt->status = 0U;
|
||||
/* Convert from big-endian (provided by crypto API) to
|
||||
* little-endian HCI.
|
||||
*/
|
||||
sys_memcpy_swap(evt->dhkey, ecc.dhkey, sizeof(ecc.dhkey));
|
||||
}
|
||||
|
||||
atomic_clear_bit(flags, PENDING_DHKEY);
|
||||
|
||||
bt_recv(buf);
|
||||
}
|
||||
|
||||
#if defined(BFLB_BLE)
|
||||
static void ecc_thread(void *p1)
|
||||
#else
|
||||
static void ecc_thread(void *p1, void *p2, void *p3)
|
||||
#endif
|
||||
{
|
||||
while (true) {
|
||||
k_sem_take(&cmd_sem, K_FOREVER);
|
||||
|
||||
if (atomic_test_bit(flags, PENDING_PUB_KEY)) {
|
||||
emulate_le_p256_public_key_cmd();
|
||||
} else if (atomic_test_bit(flags, PENDING_DHKEY)) {
|
||||
emulate_le_generate_dhkey();
|
||||
} else {
|
||||
__ASSERT(0, "Unhandled ECC command");
|
||||
}
|
||||
#if !defined(BFLB_BLE)
|
||||
STACK_ANALYZE("ecc stack", ecc_thread_stack);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_ecc_events(struct net_buf *buf)
|
||||
{
|
||||
struct bt_hci_cp_le_set_event_mask *cmd;
|
||||
|
||||
cmd = (void *)(buf->data + sizeof(struct bt_hci_cmd_hdr));
|
||||
|
||||
/*
|
||||
* don't enable controller ECC events as those will be generated from
|
||||
* emulation code
|
||||
*/
|
||||
cmd->events[0] &= ~0x80; /* LE Read Local P-256 PKey Compl */
|
||||
cmd->events[1] &= ~0x01; /* LE Generate DHKey Compl Event */
|
||||
}
|
||||
|
||||
static void le_gen_dhkey(struct net_buf *buf)
|
||||
{
|
||||
struct bt_hci_cp_le_generate_dhkey *cmd;
|
||||
u8_t status;
|
||||
|
||||
if (atomic_test_bit(flags, PENDING_PUB_KEY)) {
|
||||
status = BT_HCI_ERR_CMD_DISALLOWED;
|
||||
goto send_status;
|
||||
}
|
||||
|
||||
if (buf->len < sizeof(struct bt_hci_cp_le_generate_dhkey)) {
|
||||
status = BT_HCI_ERR_INVALID_PARAM;
|
||||
goto send_status;
|
||||
}
|
||||
|
||||
if (atomic_test_and_set_bit(flags, PENDING_DHKEY)) {
|
||||
status = BT_HCI_ERR_CMD_DISALLOWED;
|
||||
goto send_status;
|
||||
}
|
||||
|
||||
cmd = (void *)buf->data;
|
||||
/* Convert X and Y coordinates from little-endian HCI to
|
||||
* big-endian (expected by the crypto API).
|
||||
*/
|
||||
sys_memcpy_swap(ecc.pk, cmd->key, 32);
|
||||
sys_memcpy_swap(&ecc.pk[32], &cmd->key[32], 32);
|
||||
k_sem_give(&cmd_sem);
|
||||
status = BT_HCI_ERR_SUCCESS;
|
||||
|
||||
send_status:
|
||||
net_buf_unref(buf);
|
||||
send_cmd_status(BT_HCI_OP_LE_GENERATE_DHKEY, status);
|
||||
}
|
||||
|
||||
static void le_p256_pub_key(struct net_buf *buf)
|
||||
{
|
||||
u8_t status;
|
||||
|
||||
net_buf_unref(buf);
|
||||
|
||||
if (atomic_test_bit(flags, PENDING_DHKEY)) {
|
||||
status = BT_HCI_ERR_CMD_DISALLOWED;
|
||||
} else if (atomic_test_and_set_bit(flags, PENDING_PUB_KEY)) {
|
||||
status = BT_HCI_ERR_CMD_DISALLOWED;
|
||||
} else {
|
||||
k_sem_give(&cmd_sem);
|
||||
status = BT_HCI_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
send_cmd_status(BT_HCI_OP_LE_P256_PUBLIC_KEY, status);
|
||||
}
|
||||
|
||||
int bt_hci_ecc_send(struct net_buf *buf)
|
||||
{
|
||||
if (bt_buf_get_type(buf) == BT_BUF_CMD) {
|
||||
struct bt_hci_cmd_hdr *chdr = (void *)buf->data;
|
||||
|
||||
switch (sys_le16_to_cpu(chdr->opcode)) {
|
||||
case BT_HCI_OP_LE_P256_PUBLIC_KEY:
|
||||
net_buf_pull(buf, sizeof(*chdr));
|
||||
le_p256_pub_key(buf);
|
||||
return 0;
|
||||
case BT_HCI_OP_LE_GENERATE_DHKEY:
|
||||
net_buf_pull(buf, sizeof(*chdr));
|
||||
le_gen_dhkey(buf);
|
||||
return 0;
|
||||
case BT_HCI_OP_LE_SET_EVENT_MASK:
|
||||
clear_ecc_events(buf);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bt_dev.drv->send(buf);
|
||||
}
|
||||
|
||||
int default_CSPRNG(u8_t *dst, unsigned int len)
|
||||
{
|
||||
return !bt_rand(dst, len);
|
||||
}
|
||||
|
||||
void bt_hci_ecc_init(void)
|
||||
{
|
||||
#if defined(BFLB_BLE)
|
||||
k_sem_init(&cmd_sem, 0, 1);
|
||||
k_thread_create(&ecc_thread_data, "ecc_thread",
|
||||
CONFIG_BT_HCI_ECC_STACK_SIZE, ecc_thread,
|
||||
CONFIG_BT_WORK_QUEUE_PRIO);
|
||||
#else
|
||||
k_thread_create(&ecc_thread_data, ecc_thread_stack,
|
||||
K_THREAD_STACK_SIZEOF(ecc_thread_stack), ecc_thread,
|
||||
NULL, NULL, NULL, K_PRIO_PREEMPT(10), 0, K_NO_WAIT);
|
||||
k_thread_name_set(&ecc_thread_data, "BT ECC");
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/* hci_ecc.h - HCI ECC emulation */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
void bt_hci_ecc_init(void);
|
||||
int bt_hci_ecc_send(struct net_buf *buf);
|
||||
@@ -0,0 +1,887 @@
|
||||
/* hfp_hf.c - Hands free Profile - Handsfree side handling */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <zephyr.h>
|
||||
#include <errno.h>
|
||||
#include <atomic.h>
|
||||
#include <byteorder.h>
|
||||
#include <util.h>
|
||||
#include <printk.h>
|
||||
|
||||
#include <conn.h>
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HFP_HF)
|
||||
#define LOG_MODULE_NAME bt_hfp_hf
|
||||
#include "log.h"
|
||||
|
||||
#include <rfcomm.h>
|
||||
#include <hfp_hf.h>
|
||||
#include <sdp.h>
|
||||
|
||||
#include "hci_core.h"
|
||||
#include "conn_internal.h"
|
||||
#include "l2cap_internal.h"
|
||||
#include "rfcomm_internal.h"
|
||||
#include "at.h"
|
||||
#include "hfp_internal.h"
|
||||
|
||||
#define MAX_IND_STR_LEN 17
|
||||
|
||||
struct bt_hfp_hf_cb *bt_hf;
|
||||
bool hfp_codec_msbc = 0;
|
||||
|
||||
#if !defined(BFLB_DYNAMIC_ALLOC_MEM)
|
||||
NET_BUF_POOL_FIXED_DEFINE(hf_pool, CONFIG_BT_MAX_CONN + 1,
|
||||
BT_RFCOMM_BUF_SIZE(BT_HF_CLIENT_MAX_PDU), NULL);
|
||||
#else
|
||||
struct net_buf_pool hf_pool;
|
||||
#endif
|
||||
|
||||
static struct bt_hfp_hf bt_hfp_hf_pool[CONFIG_BT_MAX_CONN];
|
||||
|
||||
static struct bt_sdp_attribute hfp_attrs[] = {
|
||||
BT_SDP_NEW_SERVICE,
|
||||
BT_SDP_LIST(
|
||||
BT_SDP_ATTR_SVCLASS_ID_LIST,
|
||||
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 10),
|
||||
BT_SDP_DATA_ELEM_LIST(
|
||||
{ BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
|
||||
BT_SDP_DATA_ELEM_LIST(
|
||||
{ BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
|
||||
BT_SDP_ARRAY_16(BT_SDP_HANDSFREE_SVCLASS) }, ) },
|
||||
{ BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
|
||||
BT_SDP_DATA_ELEM_LIST(
|
||||
{ BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
|
||||
BT_SDP_ARRAY_16(BT_SDP_GENERIC_AUDIO_SVCLASS) }, ) }, )),
|
||||
BT_SDP_LIST(
|
||||
BT_SDP_ATTR_PROTO_DESC_LIST,
|
||||
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 12),
|
||||
BT_SDP_DATA_ELEM_LIST(
|
||||
{ BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
|
||||
BT_SDP_DATA_ELEM_LIST(
|
||||
{ BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
|
||||
BT_SDP_ARRAY_16(BT_SDP_PROTO_L2CAP) }, ) },
|
||||
{ BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 5),
|
||||
BT_SDP_DATA_ELEM_LIST(
|
||||
{ BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
|
||||
BT_SDP_ARRAY_16(BT_SDP_PROTO_RFCOMM) },
|
||||
{ BT_SDP_TYPE_SIZE(BT_SDP_UINT8),
|
||||
BT_SDP_ARRAY_16(BT_RFCOMM_CHAN_HFP_HF) }) }, )),
|
||||
BT_SDP_LIST(
|
||||
BT_SDP_ATTR_PROFILE_DESC_LIST,
|
||||
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 8),
|
||||
BT_SDP_DATA_ELEM_LIST(
|
||||
{ BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
|
||||
BT_SDP_DATA_ELEM_LIST(
|
||||
{ BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
|
||||
BT_SDP_ARRAY_16(BT_SDP_HANDSFREE_SVCLASS) },
|
||||
{ BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
|
||||
BT_SDP_ARRAY_16(0x0107) }, ) }, )),
|
||||
BT_SDP_SERVICE_NAME("hands-free"),
|
||||
/*
|
||||
"SupportedFeatures" attribute bit mapping for the HF
|
||||
bit 0: EC and/or NR function
|
||||
bit 1: Call waiting or three-way calling
|
||||
bit 2: CLI presentation capability
|
||||
bit 3: Voice recognition activation
|
||||
bit 4: Remote volume control
|
||||
bit 5: Wide band speech
|
||||
bit 6: Enhanced Voice Recognition Status
|
||||
bit 7: Voice Recognition Text
|
||||
*/
|
||||
BT_SDP_SUPPORTED_FEATURES(0x0035),
|
||||
};
|
||||
|
||||
static struct bt_sdp_record hfp_rec = BT_SDP_RECORD(hfp_attrs);
|
||||
|
||||
/* The order should follow the enum hfp_hf_ag_indicators */
|
||||
static const struct {
|
||||
char *name;
|
||||
uint32_t min;
|
||||
uint32_t max;
|
||||
} ag_ind[] = {
|
||||
{ "service", 0, 1 }, /* HF_SERVICE_IND */
|
||||
{ "call", 0, 1 }, /* HF_CALL_IND */
|
||||
{ "callsetup", 0, 3 }, /* HF_CALL_SETUP_IND */
|
||||
{ "callheld", 0, 2 }, /* HF_CALL_HELD_IND */
|
||||
{ "signal", 0, 5 }, /* HF_SINGNAL_IND */
|
||||
{ "roam", 0, 1 }, /* HF_ROAM_IND */
|
||||
{ "battchg", 0, 5 } /* HF_BATTERY_IND */
|
||||
};
|
||||
|
||||
static void connected(struct bt_conn *conn)
|
||||
{
|
||||
BT_DBG("HFP HF Connected!");
|
||||
}
|
||||
|
||||
static void disconnected(struct bt_conn *conn)
|
||||
{
|
||||
BT_DBG("HFP HF Disconnected!");
|
||||
}
|
||||
|
||||
static void service(struct bt_conn *conn, uint32_t value)
|
||||
{
|
||||
BT_DBG("Service indicator value: %u", value);
|
||||
}
|
||||
|
||||
static void call(struct bt_conn *conn, uint32_t value)
|
||||
{
|
||||
BT_DBG("Call indicator value: %u", value);
|
||||
}
|
||||
|
||||
static void call_setup(struct bt_conn *conn, uint32_t value)
|
||||
{
|
||||
BT_DBG("Call Setup indicator value: %u", value);
|
||||
}
|
||||
|
||||
static void call_held(struct bt_conn *conn, uint32_t value)
|
||||
{
|
||||
BT_DBG("Call Held indicator value: %u", value);
|
||||
}
|
||||
|
||||
static void signal(struct bt_conn *conn, uint32_t value)
|
||||
{
|
||||
BT_DBG("Signal indicator value: %u", value);
|
||||
}
|
||||
|
||||
static void roam(struct bt_conn *conn, uint32_t value)
|
||||
{
|
||||
BT_DBG("Roaming indicator value: %u", value);
|
||||
}
|
||||
|
||||
static void battery(struct bt_conn *conn, uint32_t value)
|
||||
{
|
||||
BT_DBG("Battery indicator value: %u", value);
|
||||
}
|
||||
|
||||
static void ring_cb(struct bt_conn *conn)
|
||||
{
|
||||
BT_DBG("Incoming Call...");
|
||||
}
|
||||
|
||||
static struct bt_hfp_hf_cb hf_cb = {
|
||||
.connected = connected,
|
||||
.disconnected = disconnected,
|
||||
.service = service,
|
||||
.call = call,
|
||||
.call_setup = call_setup,
|
||||
.call_held = call_held,
|
||||
.signal = signal,
|
||||
.roam = roam,
|
||||
.battery = battery,
|
||||
.ring_indication = ring_cb,
|
||||
};
|
||||
|
||||
void hf_slc_error(struct at_client *hf_at)
|
||||
{
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
|
||||
int err;
|
||||
|
||||
BT_ERR("SLC error: disconnecting");
|
||||
err = bt_rfcomm_dlc_disconnect(&hf->rfcomm_dlc);
|
||||
if (err) {
|
||||
BT_ERR("Rfcomm: Unable to disconnect :%d", -err);
|
||||
}
|
||||
}
|
||||
|
||||
int hfp_hf_send_cmd(struct bt_hfp_hf *hf, at_resp_cb_t resp,
|
||||
at_finish_cb_t finish, const char *format, ...)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
va_list vargs;
|
||||
int ret;
|
||||
|
||||
/* register the callbacks */
|
||||
at_register(&hf->at, resp, finish);
|
||||
|
||||
buf = bt_rfcomm_create_pdu(&hf_pool);
|
||||
if (!buf) {
|
||||
BT_ERR("No Buffers!");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
va_start(vargs, format);
|
||||
ret = vsnprintf((char *)buf->data, (net_buf_tailroom(buf) - 1), format, vargs);
|
||||
if (ret < 0) {
|
||||
BT_ERR("Unable to format variable arguments");
|
||||
return ret;
|
||||
}
|
||||
va_end(vargs);
|
||||
|
||||
net_buf_add(buf, ret);
|
||||
net_buf_add_u8(buf, '\r');
|
||||
|
||||
ret = bt_rfcomm_dlc_send(&hf->rfcomm_dlc, buf);
|
||||
if (ret < 0) {
|
||||
BT_ERR("Rfcomm send error :(%d)", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int brsf_handle(struct at_client *hf_at)
|
||||
{
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
|
||||
uint32_t val;
|
||||
int ret;
|
||||
|
||||
ret = at_get_number(hf_at, &val);
|
||||
if (ret < 0) {
|
||||
BT_ERR("Error getting value");
|
||||
return ret;
|
||||
}
|
||||
|
||||
hf->ag_features = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int brsf_resp(struct at_client *hf_at, struct net_buf *buf)
|
||||
{
|
||||
int err;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
err = at_parse_cmd_input(hf_at, buf, "BRSF", brsf_handle,
|
||||
AT_CMD_TYPE_NORMAL);
|
||||
if (err < 0) {
|
||||
/* Returning negative value is avoided before SLC connection
|
||||
* established.
|
||||
*/
|
||||
BT_ERR("Error parsing CMD input");
|
||||
hf_slc_error(hf_at);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cind_handle_values(struct at_client *hf_at, uint32_t index,
|
||||
char *name, uint32_t min, uint32_t max)
|
||||
{
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
|
||||
int i;
|
||||
|
||||
BT_DBG("index: %u, name: %s, min: %u, max:%u", index, name, min, max);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ag_ind); i++) {
|
||||
if (strcmp(name, ag_ind[i].name) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (min != ag_ind[i].min || max != ag_ind[i].max) {
|
||||
BT_ERR("%s indicator min/max value not matching", name);
|
||||
}
|
||||
|
||||
hf->ind_table[index] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int cind_handle(struct at_client *hf_at)
|
||||
{
|
||||
uint32_t index = 0U;
|
||||
|
||||
/* Parsing Example: CIND: ("call",(0,1)) etc.. */
|
||||
while (at_has_next_list(hf_at)) {
|
||||
char name[MAX_IND_STR_LEN];
|
||||
uint32_t min, max;
|
||||
|
||||
if (at_open_list(hf_at) < 0) {
|
||||
BT_ERR("Could not get open list");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (at_list_get_string(hf_at, name, sizeof(name)) < 0) {
|
||||
BT_ERR("Could not get string");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (at_open_list(hf_at) < 0) {
|
||||
BT_ERR("Could not get open list");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (at_list_get_range(hf_at, &min, &max) < 0) {
|
||||
BT_ERR("Could not get range");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (at_close_list(hf_at) < 0) {
|
||||
BT_ERR("Could not get close list");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (at_close_list(hf_at) < 0) {
|
||||
BT_ERR("Could not get close list");
|
||||
goto error;
|
||||
}
|
||||
|
||||
cind_handle_values(hf_at, index, name, min, max);
|
||||
index++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
error:
|
||||
BT_ERR("Error on CIND response");
|
||||
hf_slc_error(hf_at);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int cind_resp(struct at_client *hf_at, struct net_buf *buf)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = at_parse_cmd_input(hf_at, buf, "CIND", cind_handle,
|
||||
AT_CMD_TYPE_NORMAL);
|
||||
if (err < 0) {
|
||||
BT_ERR("Error parsing CMD input");
|
||||
hf_slc_error(hf_at);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ag_indicator_handle_values(struct at_client *hf_at, uint32_t index,
|
||||
uint32_t value)
|
||||
{
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
|
||||
struct bt_conn *conn = hf->rfcomm_dlc.session->br_chan.chan.conn;
|
||||
|
||||
BT_DBG("Index :%u, Value :%u", index, value);
|
||||
|
||||
if (index >= ARRAY_SIZE(ag_ind)) {
|
||||
BT_ERR("Max only %lu indicators are supported",
|
||||
ARRAY_SIZE(ag_ind));
|
||||
return;
|
||||
}
|
||||
|
||||
if (value > ag_ind[hf->ind_table[index]].max ||
|
||||
value < ag_ind[hf->ind_table[index]].min) {
|
||||
BT_ERR("Indicators out of range - value: %u", value);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (hf->ind_table[index]) {
|
||||
case HF_SERVICE_IND:
|
||||
if (bt_hf->service) {
|
||||
bt_hf->service(conn, value);
|
||||
}
|
||||
break;
|
||||
case HF_CALL_IND:
|
||||
if (bt_hf->call) {
|
||||
bt_hf->call(conn, value);
|
||||
}
|
||||
break;
|
||||
case HF_CALL_SETUP_IND:
|
||||
if (bt_hf->call_setup) {
|
||||
bt_hf->call_setup(conn, value);
|
||||
}
|
||||
break;
|
||||
case HF_CALL_HELD_IND:
|
||||
if (bt_hf->call_held) {
|
||||
bt_hf->call_held(conn, value);
|
||||
}
|
||||
break;
|
||||
case HF_SINGNAL_IND:
|
||||
if (bt_hf->signal) {
|
||||
bt_hf->signal(conn, value);
|
||||
}
|
||||
break;
|
||||
case HF_ROAM_IND:
|
||||
if (bt_hf->roam) {
|
||||
bt_hf->roam(conn, value);
|
||||
}
|
||||
break;
|
||||
case HF_BATTERY_IND:
|
||||
if (bt_hf->battery) {
|
||||
bt_hf->battery(conn, value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BT_ERR("Unknown AG indicator");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int cind_status_handle(struct at_client *hf_at)
|
||||
{
|
||||
uint32_t index = 0U;
|
||||
|
||||
while (at_has_next_list(hf_at)) {
|
||||
uint32_t value;
|
||||
int ret;
|
||||
|
||||
ret = at_get_number(hf_at, &value);
|
||||
if (ret < 0) {
|
||||
BT_ERR("could not get the value");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ag_indicator_handle_values(hf_at, index, value);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cind_status_resp(struct at_client *hf_at, struct net_buf *buf)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = at_parse_cmd_input(hf_at, buf, "CIND", cind_status_handle,
|
||||
AT_CMD_TYPE_NORMAL);
|
||||
if (err < 0) {
|
||||
BT_ERR("Error parsing CMD input");
|
||||
hf_slc_error(hf_at);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ciev_handle(struct at_client *hf_at)
|
||||
{
|
||||
uint32_t index, value;
|
||||
int ret;
|
||||
|
||||
ret = at_get_number(hf_at, &index);
|
||||
if (ret < 0) {
|
||||
BT_ERR("could not get the Index");
|
||||
return ret;
|
||||
}
|
||||
/* The first element of the list shall have 1 */
|
||||
if (!index) {
|
||||
BT_ERR("Invalid index value '0'");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = at_get_number(hf_at, &value);
|
||||
if (ret < 0) {
|
||||
BT_ERR("could not get the value");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ag_indicator_handle_values(hf_at, (index - 1), value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ring_handle(struct at_client *hf_at)
|
||||
{
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
|
||||
struct bt_conn *conn = hf->rfcomm_dlc.session->br_chan.chan.conn;
|
||||
|
||||
if (bt_hf->ring_indication) {
|
||||
bt_hf->ring_indication(conn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bcs_handle(struct at_client *hf_at)
|
||||
{
|
||||
uint32_t value;
|
||||
int ret;
|
||||
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
|
||||
|
||||
ret = at_get_number(hf_at, &value);
|
||||
if (ret < 0) {
|
||||
BT_ERR("could not get the value");
|
||||
return ret;
|
||||
}
|
||||
if (value == 1) {
|
||||
if (hfp_hf_send_cmd(hf, NULL, NULL, "AT+BCS=1") < 0) {
|
||||
BT_ERR("Error Sending AT+BCS=1");
|
||||
}
|
||||
} else if (value == 2) {
|
||||
if (hfp_hf_send_cmd(hf, NULL, NULL, "AT+BCS=2") < 0) {
|
||||
BT_ERR("Error Sending AT+BCS=2");
|
||||
} else {
|
||||
hfp_codec_msbc = 1;
|
||||
}
|
||||
} else {
|
||||
BT_WARN("Invail BCS value !");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct unsolicited {
|
||||
const char *cmd;
|
||||
enum at_cmd_type type;
|
||||
int (*func)(struct at_client *hf_at);
|
||||
} handlers[] = {
|
||||
{ "CIEV", AT_CMD_TYPE_UNSOLICITED, ciev_handle },
|
||||
{ "RING", AT_CMD_TYPE_OTHER, ring_handle },
|
||||
{ "BCS", AT_CMD_TYPE_UNSOLICITED, bcs_handle }
|
||||
};
|
||||
|
||||
static const struct unsolicited *hfp_hf_unsol_lookup(struct at_client *hf_at)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(handlers); i++) {
|
||||
if (!strncmp(hf_at->buf, handlers[i].cmd,
|
||||
strlen(handlers[i].cmd))) {
|
||||
return &handlers[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int unsolicited_cb(struct at_client *hf_at, struct net_buf *buf)
|
||||
{
|
||||
const struct unsolicited *handler;
|
||||
|
||||
handler = hfp_hf_unsol_lookup(hf_at);
|
||||
if (!handler) {
|
||||
BT_ERR("Unhandled unsolicited response");
|
||||
return -ENOMSG;
|
||||
}
|
||||
|
||||
if (!at_parse_cmd_input(hf_at, buf, handler->cmd, handler->func,
|
||||
handler->type)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMSG;
|
||||
}
|
||||
|
||||
int cmd_complete(struct at_client *hf_at, enum at_result result,
|
||||
enum at_cme cme_err)
|
||||
{
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
|
||||
struct bt_conn *conn = hf->rfcomm_dlc.session->br_chan.chan.conn;
|
||||
struct bt_hfp_hf_cmd_complete cmd = { 0 };
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
switch (result) {
|
||||
case AT_RESULT_OK:
|
||||
cmd.type = HFP_HF_CMD_OK;
|
||||
break;
|
||||
case AT_RESULT_ERROR:
|
||||
cmd.type = HFP_HF_CMD_ERROR;
|
||||
break;
|
||||
case AT_RESULT_CME_ERROR:
|
||||
cmd.type = HFP_HF_CMD_CME_ERROR;
|
||||
cmd.cme = cme_err;
|
||||
break;
|
||||
default:
|
||||
BT_ERR("Unknown error code");
|
||||
cmd.type = HFP_HF_CMD_UNKNOWN_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bt_hf->cmd_complete_cb) {
|
||||
bt_hf->cmd_complete_cb(conn, &cmd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmee_finish(struct at_client *hf_at, enum at_result result,
|
||||
enum at_cme cme_err)
|
||||
{
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
|
||||
|
||||
if (result != AT_RESULT_OK) {
|
||||
BT_ERR("SLC Connection ERROR in response");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hfp_hf_send_cmd(hf, NULL, NULL, "AT+NREC=0") < 0) {
|
||||
BT_ERR("Error Sending AT+NREC");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void slc_completed(struct at_client *hf_at)
|
||||
{
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
|
||||
struct bt_conn *conn = hf->rfcomm_dlc.session->br_chan.chan.conn;
|
||||
|
||||
if (bt_hf->connected) {
|
||||
bt_hf->connected(conn);
|
||||
}
|
||||
|
||||
if (hfp_hf_send_cmd(hf, NULL, cmee_finish, "AT+CMEE=1") < 0) {
|
||||
BT_ERR("Error Sending AT+CMEE");
|
||||
}
|
||||
}
|
||||
|
||||
int cmer_finish(struct at_client *hf_at, enum at_result result,
|
||||
enum at_cme cme_err)
|
||||
{
|
||||
if (result != AT_RESULT_OK) {
|
||||
BT_ERR("SLC Connection ERROR in response");
|
||||
hf_slc_error(hf_at);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
slc_completed(hf_at);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cind_status_finish(struct at_client *hf_at, enum at_result result,
|
||||
enum at_cme cme_err)
|
||||
{
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
|
||||
int err;
|
||||
|
||||
if (result != AT_RESULT_OK) {
|
||||
BT_ERR("SLC Connection ERROR in response");
|
||||
hf_slc_error(hf_at);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
at_register_unsolicited(hf_at, unsolicited_cb);
|
||||
err = hfp_hf_send_cmd(hf, NULL, cmer_finish, "AT+CMER=3,0,0,1");
|
||||
if (err < 0) {
|
||||
hf_slc_error(hf_at);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cind_finish(struct at_client *hf_at, enum at_result result,
|
||||
enum at_cme cme_err)
|
||||
{
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
|
||||
int err;
|
||||
|
||||
if (result != AT_RESULT_OK) {
|
||||
BT_ERR("SLC Connection ERROR in response");
|
||||
hf_slc_error(hf_at);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = hfp_hf_send_cmd(hf, cind_status_resp, cind_status_finish,
|
||||
"AT+CIND?");
|
||||
if (err < 0) {
|
||||
hf_slc_error(hf_at);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bac_finish(struct at_client *hf_at, enum at_result result,
|
||||
enum at_cme cme_err)
|
||||
{
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
|
||||
int err;
|
||||
|
||||
if (result != AT_RESULT_OK) {
|
||||
BT_ERR("SLC Connection ERROR in response");
|
||||
hf_slc_error(hf_at);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = hfp_hf_send_cmd(hf, cind_resp, cind_finish, "AT+CIND=?");
|
||||
if (err < 0) {
|
||||
hf_slc_error(hf_at);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int brsf_finish(struct at_client *hf_at, enum at_result result,
|
||||
enum at_cme cme_err)
|
||||
{
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
|
||||
int err;
|
||||
|
||||
if (result != AT_RESULT_OK) {
|
||||
BT_ERR("SLC Connection ERROR in response");
|
||||
hf_slc_error(hf_at);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = hfp_hf_send_cmd(hf, NULL, bac_finish, "AT+BAC=1,2");
|
||||
if (err < 0) {
|
||||
hf_slc_error(hf_at);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hf_slc_establish(struct bt_hfp_hf *hf)
|
||||
{
|
||||
int err;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
err = hfp_hf_send_cmd(hf, brsf_resp, brsf_finish, "AT+BRSF=%u",
|
||||
hf->hf_features);
|
||||
if (err < 0) {
|
||||
hf_slc_error(&hf->at);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bt_hfp_hf *bt_hfp_hf_lookup_bt_conn(struct bt_conn *conn)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bt_hfp_hf_pool); i++) {
|
||||
struct bt_hfp_hf *hf = &bt_hfp_hf_pool[i];
|
||||
|
||||
if (hf->rfcomm_dlc.session->br_chan.chan.conn == conn) {
|
||||
return hf;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int bt_hfp_hf_send_cmd(struct bt_conn *conn, enum bt_hfp_hf_at_cmd cmd)
|
||||
{
|
||||
struct bt_hfp_hf *hf;
|
||||
int err;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
if (!conn) {
|
||||
BT_ERR("Invalid connection");
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
hf = bt_hfp_hf_lookup_bt_conn(conn);
|
||||
if (!hf) {
|
||||
BT_ERR("No HF connection found");
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case BT_HFP_HF_ATA:
|
||||
err = hfp_hf_send_cmd(hf, NULL, cmd_complete, "ATA");
|
||||
if (err < 0) {
|
||||
BT_ERR("Failed ATA");
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
case BT_HFP_HF_AT_CHUP:
|
||||
err = hfp_hf_send_cmd(hf, NULL, cmd_complete, "AT+CHUP");
|
||||
if (err < 0) {
|
||||
BT_ERR("Failed AT+CHUP");
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BT_ERR("Invalid AT Command");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hfp_hf_connected(struct bt_rfcomm_dlc *dlc)
|
||||
{
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(dlc, struct bt_hfp_hf, rfcomm_dlc);
|
||||
|
||||
BT_DBG("hf connected");
|
||||
|
||||
BT_ASSERT(hf);
|
||||
hf_slc_establish(hf);
|
||||
}
|
||||
|
||||
static void hfp_hf_disconnected(struct bt_rfcomm_dlc *dlc)
|
||||
{
|
||||
struct bt_conn *conn = dlc->session->br_chan.chan.conn;
|
||||
|
||||
BT_DBG("hf disconnected!");
|
||||
if (bt_hf->disconnected) {
|
||||
bt_hf->disconnected(conn);
|
||||
}
|
||||
}
|
||||
|
||||
static void hfp_hf_recv(struct bt_rfcomm_dlc *dlc, struct net_buf *buf)
|
||||
{
|
||||
struct bt_hfp_hf *hf = CONTAINER_OF(dlc, struct bt_hfp_hf, rfcomm_dlc);
|
||||
|
||||
if (at_parse_input(&hf->at, buf) < 0) {
|
||||
BT_ERR("Parsing failed");
|
||||
}
|
||||
}
|
||||
|
||||
static int bt_hfp_hf_accept(struct bt_conn *conn, struct bt_rfcomm_dlc **dlc)
|
||||
{
|
||||
int i;
|
||||
static struct bt_rfcomm_dlc_ops ops = {
|
||||
.connected = hfp_hf_connected,
|
||||
.disconnected = hfp_hf_disconnected,
|
||||
.recv = hfp_hf_recv,
|
||||
};
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bt_hfp_hf_pool); i++) {
|
||||
struct bt_hfp_hf *hf = &bt_hfp_hf_pool[i];
|
||||
int j;
|
||||
|
||||
if (hf->rfcomm_dlc.session) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hf->at.buf = hf->hf_buffer;
|
||||
hf->at.buf_max_len = HF_MAX_BUF_LEN;
|
||||
|
||||
hf->rfcomm_dlc.ops = &ops;
|
||||
hf->rfcomm_dlc.mtu = BT_HFP_MAX_MTU;
|
||||
|
||||
*dlc = &hf->rfcomm_dlc;
|
||||
|
||||
/* Set the supported features*/
|
||||
hf->hf_features = BT_HFP_HF_SUPPORTED_FEATURES;
|
||||
|
||||
for (j = 0; j < HF_MAX_AG_INDICATORS; j++) {
|
||||
hf->ind_table[j] = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_ERR("Unable to establish HF connection (%p)", conn);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int bt_hfp_hf_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
#if defined(BFLB_DYNAMIC_ALLOC_MEM)
|
||||
net_buf_init(&hf_pool, CONFIG_BT_MAX_CONN + 1, BT_RFCOMM_BUF_SIZE(BT_HF_CLIENT_MAX_PDU), NULL);
|
||||
#endif
|
||||
|
||||
bt_hf = &hf_cb;
|
||||
|
||||
static struct bt_rfcomm_server chan = {
|
||||
.channel = BT_RFCOMM_CHAN_HFP_HF,
|
||||
.accept = bt_hfp_hf_accept,
|
||||
};
|
||||
|
||||
bt_rfcomm_server_register(&chan);
|
||||
|
||||
/* Register SDP record */
|
||||
err = bt_sdp_register_service(&hfp_rec);
|
||||
if (err < 0) {
|
||||
BT_ERR("HFP regist sdp record failed");
|
||||
}
|
||||
BT_DBG("HFP initialized successfully.");
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/** @file
|
||||
* @brief Internal APIs for Bluetooth Handsfree profile handling.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define BT_HFP_MAX_MTU 140
|
||||
#define BT_HF_CLIENT_MAX_PDU BT_HFP_MAX_MTU
|
||||
|
||||
/* HFP AG Features */
|
||||
#define BT_HFP_AG_FEATURE_3WAY_CALL 0x00000001 /* Three-way calling */
|
||||
#define BT_HFP_AG_FEATURE_ECNR 0x00000002 /* EC and/or NR function */
|
||||
#define BT_HFP_AG_FEATURE_VOICE_RECG 0x00000004 /* Voice recognition */
|
||||
#define BT_HFP_AG_INBAND_RING_TONE 0x00000008 /* In-band ring capability */
|
||||
#define BT_HFP_AG_VOICE_TAG 0x00000010 /* Attach no. to voice tag */
|
||||
#define BT_HFP_AG_FEATURE_REJECT_CALL 0x00000020 /* Ability to reject call */
|
||||
#define BT_HFP_AG_FEATURE_ECS 0x00000040 /* Enhanced call status */
|
||||
#define BT_HFP_AG_FEATURE_ECC 0x00000080 /* Enhanced call control */
|
||||
#define BT_HFP_AG_FEATURE_EXT_ERR 0x00000100 /* Extented error codes */
|
||||
#define BT_HFP_AG_FEATURE_CODEC_NEG 0x00000200 /* Codec negotiation */
|
||||
#define BT_HFP_AG_FEATURE_HF_IND 0x00000400 /* HF Indicators */
|
||||
#define BT_HFP_AG_FEARTURE_ESCO_S4 0x00000800 /* eSCO S4 Settings */
|
||||
|
||||
/* HFP HF Features */
|
||||
#define BT_HFP_HF_FEATURE_ECNR 0x00000001 /* EC and/or NR */
|
||||
#define BT_HFP_HF_FEATURE_3WAY_CALL 0x00000002 /* Three-way calling */
|
||||
#define BT_HFP_HF_FEATURE_CLI 0x00000004 /* CLI presentation */
|
||||
#define BT_HFP_HF_FEATURE_VOICE_RECG 0x00000008 /* Voice recognition */
|
||||
#define BT_HFP_HF_FEATURE_VOLUME 0x00000010 /* Remote volume control */
|
||||
#define BT_HFP_HF_FEATURE_ECS 0x00000020 /* Enhanced call status */
|
||||
#define BT_HFP_HF_FEATURE_ECC 0x00000040 /* Enhanced call control */
|
||||
#define BT_HFP_HF_FEATURE_CODEC_NEG 0x00000080 /* CODEC Negotiation */
|
||||
#define BT_HFP_HF_FEATURE_HF_IND 0x00000100 /* HF Indicators */
|
||||
#define BT_HFP_HF_FEATURE_ESCO_S4 0x00000200 /* eSCO S4 Settings */
|
||||
|
||||
/* HFP HF Supported features */
|
||||
#define BT_HFP_HF_SUPPORTED_FEATURES (BT_HFP_HF_FEATURE_ECNR | \
|
||||
BT_HFP_HF_FEATURE_CLI | \
|
||||
BT_HFP_HF_FEATURE_VOLUME | \
|
||||
BT_HFP_HF_FEATURE_CODEC_NEG)
|
||||
|
||||
#define HF_MAX_BUF_LEN BT_HF_CLIENT_MAX_PDU
|
||||
#define HF_MAX_AG_INDICATORS 20
|
||||
|
||||
struct bt_hfp_hf {
|
||||
struct bt_rfcomm_dlc rfcomm_dlc;
|
||||
char hf_buffer[HF_MAX_BUF_LEN];
|
||||
struct at_client at;
|
||||
uint32_t hf_features;
|
||||
uint32_t ag_features;
|
||||
int8_t ind_table[HF_MAX_AG_INDICATORS];
|
||||
};
|
||||
|
||||
enum hfp_hf_ag_indicators {
|
||||
HF_SERVICE_IND,
|
||||
HF_CALL_IND,
|
||||
HF_CALL_SETUP_IND,
|
||||
HF_CALL_HELD_IND,
|
||||
HF_SINGNAL_IND,
|
||||
HF_ROAM_IND,
|
||||
HF_BATTERY_IND
|
||||
};
|
||||
@@ -0,0 +1,110 @@
|
||||
/** @file
|
||||
* @brief Internal APIs for Bluetooth ISO handling.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <iso.h>
|
||||
|
||||
#define BT_ISO_DATA_PATH_DISABLED 0xFF
|
||||
|
||||
struct iso_data {
|
||||
/** BT_BUF_ISO_IN */
|
||||
uint8_t type;
|
||||
|
||||
/* Index into the bt_conn storage array */
|
||||
uint8_t index;
|
||||
|
||||
/** ISO connection handle */
|
||||
uint16_t handle;
|
||||
|
||||
/** ISO timestamp */
|
||||
uint32_t ts;
|
||||
};
|
||||
|
||||
#define iso(buf) ((struct iso_data *)net_buf_user_data(buf))
|
||||
|
||||
#if defined(CONFIG_BT_MAX_ISO_CONN)
|
||||
extern struct bt_conn iso_conns[CONFIG_BT_MAX_ISO_CONN];
|
||||
#endif
|
||||
|
||||
/* Process ISO buffer */
|
||||
void hci_iso(struct net_buf *buf);
|
||||
|
||||
/* Allocates RX buffer */
|
||||
struct net_buf *bt_iso_get_rx(uint32_t timeout);
|
||||
|
||||
/* Create new ISO connecting */
|
||||
struct bt_conn *iso_new(void);
|
||||
|
||||
/* Process CIS Estabilished event */
|
||||
void hci_le_cis_estabilished(struct net_buf *buf);
|
||||
|
||||
/* Process CIS Request event */
|
||||
void hci_le_cis_req(struct net_buf *buf);
|
||||
|
||||
/* Notify ISO channels of a new connection */
|
||||
int bt_iso_accept(struct bt_conn *conn);
|
||||
|
||||
/* Notify ISO channels of a new connection */
|
||||
void bt_iso_connected(struct bt_conn *conn);
|
||||
|
||||
/* Notify ISO channels of a disconnect event */
|
||||
void bt_iso_disconnected(struct bt_conn *conn);
|
||||
|
||||
/* Allocate ISO PDU */
|
||||
#if defined(CONFIG_NET_BUF_LOG)
|
||||
struct net_buf *bt_iso_create_pdu_timeout_debug(struct net_buf_pool *pool,
|
||||
size_t reserve,
|
||||
k_timeout_t timeout,
|
||||
const char *func, int line);
|
||||
#define bt_iso_create_pdu_timeout(_pool, _reserve, _timeout) \
|
||||
bt_iso_create_pdu_timeout_debug(_pool, _reserve, _timeout, \
|
||||
__func__, __LINE__)
|
||||
|
||||
#define bt_iso_create_pdu(_pool, _reserve) \
|
||||
bt_iso_create_pdu_timeout_debug(_pool, _reserve, K_FOREVER, \
|
||||
__func__, __line__)
|
||||
#else
|
||||
struct net_buf *bt_iso_create_pdu_timeout(struct net_buf_pool *pool,
|
||||
size_t reserve, uint32_t timeout);
|
||||
|
||||
#define bt_iso_create_pdu(_pool, _reserve) \
|
||||
bt_iso_create_pdu_timeout(_pool, _reserve, K_FOREVER)
|
||||
#endif
|
||||
|
||||
/* Allocate ISO Fragment */
|
||||
#if defined(CONFIG_NET_BUF_LOG)
|
||||
struct net_buf *bt_iso_create_frag_timeout_debug(size_t reserve,
|
||||
k_timeout_t timeout,
|
||||
const char *func, int line);
|
||||
|
||||
#define bt_iso_create_frag_timeout(_reserve, _timeout) \
|
||||
bt_iso_create_frag_timeout_debug(_reserve, _timeout, \
|
||||
__func__, __LINE__)
|
||||
|
||||
#define bt_iso_create_frag(_reserve) \
|
||||
bt_iso_create_frag_timeout_debug(_reserve, K_FOREVER, \
|
||||
__func__, __LINE__)
|
||||
#else
|
||||
struct net_buf *bt_iso_create_frag_timeout(size_t reserve, uint32_t timeout);
|
||||
|
||||
#define bt_iso_create_frag(_reserve) \
|
||||
bt_iso_create_frag_timeout(_reserve, K_FOREVER)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_AUDIO_DEBUG_ISO)
|
||||
void bt_iso_chan_set_state_debug(struct bt_iso_chan *chan, uint8_t state,
|
||||
const char *func, int line);
|
||||
#define bt_iso_chan_set_state(_chan, _state) \
|
||||
bt_iso_chan_set_state_debug(_chan, _state, __func__, __LINE__)
|
||||
#else
|
||||
void bt_iso_chan_set_state(struct bt_iso_chan *chan, uint8_t state);
|
||||
#endif /* CONFIG_BT_AUDIO_DEBUG_ISO */
|
||||
|
||||
/* Process incoming data for a connection */
|
||||
void bt_iso_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags);
|
||||
@@ -0,0 +1,506 @@
|
||||
/* keys.c - Bluetooth key handling */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <atomic.h>
|
||||
#include <misc/util.h>
|
||||
|
||||
#include <bluetooth.h>
|
||||
#include <conn.h>
|
||||
#include <hci_host.h>
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_KEYS)
|
||||
#include "log.h"
|
||||
|
||||
#include "rpa.h"
|
||||
#include "gatt_internal.h"
|
||||
#include "hci_core.h"
|
||||
#include "smp.h"
|
||||
#include "settings.h"
|
||||
#include "keys.h"
|
||||
#if defined(BFLB_BLE)
|
||||
#if defined(CONFIG_BT_SETTINGS)
|
||||
#include "easyflash.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static struct bt_keys key_pool[CONFIG_BT_MAX_PAIRED];
|
||||
|
||||
#define BT_KEYS_STORAGE_LEN_COMPAT (BT_KEYS_STORAGE_LEN - sizeof(uint32_t))
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
static u32_t aging_counter_val;
|
||||
static struct bt_keys *last_keys_updated;
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
|
||||
struct bt_keys *bt_keys_get_addr(u8_t id, const bt_addr_le_t *addr)
|
||||
{
|
||||
struct bt_keys *keys;
|
||||
int i;
|
||||
size_t first_free_slot = ARRAY_SIZE(key_pool);
|
||||
|
||||
BT_DBG("%s", bt_addr_le_str(addr));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
|
||||
keys = &key_pool[i];
|
||||
|
||||
if (keys->id == id && !bt_addr_le_cmp(&keys->addr, addr)) {
|
||||
return keys;
|
||||
}
|
||||
|
||||
if (first_free_slot == ARRAY_SIZE(key_pool) &&
|
||||
(!bt_addr_le_cmp(&keys->addr, BT_ADDR_LE_ANY) ||
|
||||
!keys->enc_size)) {
|
||||
first_free_slot = i;
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
if (first_free_slot == ARRAY_SIZE(key_pool)) {
|
||||
struct bt_keys *oldest = &key_pool[0];
|
||||
|
||||
for (i = 1; i < ARRAY_SIZE(key_pool); i++) {
|
||||
struct bt_keys *current = &key_pool[i];
|
||||
|
||||
if (current->aging_counter < oldest->aging_counter) {
|
||||
oldest = current;
|
||||
}
|
||||
}
|
||||
|
||||
bt_unpair(oldest->id, &oldest->addr);
|
||||
if (!bt_addr_le_cmp(&oldest->addr, BT_ADDR_LE_ANY)) {
|
||||
first_free_slot = oldest - &key_pool[0];
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
if (first_free_slot < ARRAY_SIZE(key_pool)) {
|
||||
keys = &key_pool[first_free_slot];
|
||||
keys->id = id;
|
||||
bt_addr_le_copy(&keys->addr, addr);
|
||||
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
keys->aging_counter = ++aging_counter_val;
|
||||
last_keys_updated = keys;
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
BT_DBG("created %p for %s", keys, bt_addr_le_str(addr));
|
||||
return keys;
|
||||
}
|
||||
|
||||
BT_DBG("unable to create keys for %s", bt_addr_le_str(addr));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bt_foreach_bond(u8_t id, void (*func)(const struct bt_bond_info *info, void *user_data),
|
||||
void *user_data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
|
||||
struct bt_keys *keys = &key_pool[i];
|
||||
|
||||
if (keys->keys && keys->id == id) {
|
||||
struct bt_bond_info info;
|
||||
|
||||
bt_addr_le_copy(&info.addr, &keys->addr);
|
||||
func(&info, user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bt_keys_foreach(int type, void (*func)(struct bt_keys *keys, void *data),
|
||||
void *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
|
||||
if ((key_pool[i].keys & type)) {
|
||||
func(&key_pool[i], data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct bt_keys *bt_keys_find(int type, u8_t id, const bt_addr_le_t *addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
BT_DBG("type %d %s", type, bt_addr_le_str(addr));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
|
||||
if ((key_pool[i].keys & type) && key_pool[i].id == id &&
|
||||
!bt_addr_le_cmp(&key_pool[i].addr, addr)) {
|
||||
return &key_pool[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct bt_keys *bt_keys_get_type(int type, u8_t id, const bt_addr_le_t *addr)
|
||||
{
|
||||
struct bt_keys *keys;
|
||||
|
||||
BT_DBG("type %d %s", type, bt_addr_le_str(addr));
|
||||
|
||||
keys = bt_keys_find(type, id, addr);
|
||||
if (keys) {
|
||||
return keys;
|
||||
}
|
||||
|
||||
keys = bt_keys_get_addr(id, addr);
|
||||
if (!keys) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bt_keys_add_type(keys, type);
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
struct bt_keys *bt_keys_find_irk(u8_t id, const bt_addr_le_t *addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
BT_DBG("%s", bt_addr_le_str(addr));
|
||||
|
||||
if (!bt_addr_le_is_rpa(addr)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
|
||||
if (!(key_pool[i].keys & BT_KEYS_IRK)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key_pool[i].id == id &&
|
||||
!bt_addr_cmp(&addr->a, &key_pool[i].irk.rpa)) {
|
||||
BT_DBG("cached RPA %s for %s",
|
||||
bt_addr_str(&key_pool[i].irk.rpa),
|
||||
bt_addr_le_str(&key_pool[i].addr));
|
||||
return &key_pool[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
|
||||
if (!(key_pool[i].keys & BT_KEYS_IRK)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key_pool[i].id != id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bt_rpa_irk_matches(key_pool[i].irk.val, &addr->a)) {
|
||||
BT_DBG("RPA %s matches %s",
|
||||
bt_addr_str(&key_pool[i].irk.rpa),
|
||||
bt_addr_le_str(&key_pool[i].addr));
|
||||
|
||||
bt_addr_copy(&key_pool[i].irk.rpa, &addr->a);
|
||||
|
||||
return &key_pool[i];
|
||||
}
|
||||
}
|
||||
|
||||
BT_DBG("No IRK for %s", bt_addr_le_str(addr));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct bt_keys *bt_keys_find_addr(u8_t id, const bt_addr_le_t *addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
BT_DBG("%s", bt_addr_le_str(addr));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
|
||||
if (key_pool[i].id == id &&
|
||||
!bt_addr_le_cmp(&key_pool[i].addr, addr)) {
|
||||
return &key_pool[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BLE_AT_CMD)
|
||||
bt_addr_le_t *bt_get_keys_address(u8_t id)
|
||||
{
|
||||
bt_addr_le_t addr;
|
||||
|
||||
memset(&addr, 0, sizeof(bt_addr_le_t));
|
||||
if (id < ARRAY_SIZE(key_pool)) {
|
||||
if (bt_addr_le_cmp(&key_pool[id].addr, &addr)) {
|
||||
return &key_pool[id].addr;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
void bt_keys_add_type(struct bt_keys *keys, int type)
|
||||
{
|
||||
keys->keys |= type;
|
||||
}
|
||||
|
||||
void bt_keys_clear(struct bt_keys *keys)
|
||||
{
|
||||
#if defined(BFLB_BLE)
|
||||
if (keys->keys & BT_KEYS_IRK) {
|
||||
bt_id_del(keys);
|
||||
}
|
||||
|
||||
memset(keys, 0, sizeof(*keys));
|
||||
|
||||
#if defined(CONFIG_BT_SETTINGS)
|
||||
ef_del_env(NV_KEY_POOL);
|
||||
#endif
|
||||
#else
|
||||
BT_DBG("%s (keys 0x%04x)", bt_addr_le_str(&keys->addr), keys->keys);
|
||||
|
||||
if (keys->keys & BT_KEYS_IRK) {
|
||||
bt_id_del(keys);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
char key[BT_SETTINGS_KEY_MAX];
|
||||
|
||||
/* Delete stored keys from flash */
|
||||
if (keys->id) {
|
||||
char id[4];
|
||||
|
||||
u8_to_dec(id, sizeof(id), keys->id);
|
||||
bt_settings_encode_key(key, sizeof(key), "keys",
|
||||
&keys->addr, id);
|
||||
} else {
|
||||
bt_settings_encode_key(key, sizeof(key), "keys",
|
||||
&keys->addr, NULL);
|
||||
}
|
||||
|
||||
BT_DBG("Deleting key %s", log_strdup(key));
|
||||
settings_delete(key);
|
||||
}
|
||||
|
||||
(void)memset(keys, 0, sizeof(*keys));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void keys_clear_id(struct bt_keys *keys, void *data)
|
||||
{
|
||||
u8_t *id = data;
|
||||
|
||||
if (*id == keys->id) {
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_gatt_clear(*id, &keys->addr);
|
||||
}
|
||||
|
||||
bt_keys_clear(keys);
|
||||
}
|
||||
}
|
||||
|
||||
void bt_keys_clear_all(u8_t id)
|
||||
{
|
||||
bt_keys_foreach(BT_KEYS_ALL, keys_clear_id, &id);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_SETTINGS)
|
||||
int bt_keys_store(struct bt_keys *keys)
|
||||
{
|
||||
#if defined(BFLB_BLE)
|
||||
int err;
|
||||
err = bt_settings_set_bin(NV_KEY_POOL, (const u8_t *)&key_pool[0], sizeof(key_pool));
|
||||
return err;
|
||||
#else
|
||||
char val[BT_SETTINGS_SIZE(BT_KEYS_STORAGE_LEN)];
|
||||
char key[BT_SETTINGS_KEY_MAX];
|
||||
char *str;
|
||||
int err;
|
||||
|
||||
str = settings_str_from_bytes(keys->storage_start, BT_KEYS_STORAGE_LEN,
|
||||
val, sizeof(val));
|
||||
if (!str) {
|
||||
BT_ERR("Unable to encode bt_keys as value");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (keys->id) {
|
||||
char id[4];
|
||||
|
||||
u8_to_dec(id, sizeof(id), keys->id);
|
||||
bt_settings_encode_key(key, sizeof(key), "keys", &keys->addr,
|
||||
id);
|
||||
} else {
|
||||
bt_settings_encode_key(key, sizeof(key), "keys", &keys->addr,
|
||||
NULL);
|
||||
}
|
||||
|
||||
err = settings_save_one(key, keys->storage_start, BT_KEYS_STORAGE_LEN);
|
||||
if (err) {
|
||||
BT_ERR("Failed to save keys (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_DBG("Stored keys for %s (%s)", bt_addr_le_str(&keys->addr),
|
||||
log_strdup(key));
|
||||
|
||||
return 0;
|
||||
#endif //BFLB_BLE
|
||||
}
|
||||
|
||||
#if !defined(BFLB_BLE)
|
||||
static int keys_set(const char *name, size_t len_rd, settings_read_cb read_cb,
|
||||
void *cb_arg)
|
||||
{
|
||||
struct bt_keys *keys;
|
||||
bt_addr_le_t addr;
|
||||
u8_t id;
|
||||
size_t len;
|
||||
int err;
|
||||
char val[BT_KEYS_STORAGE_LEN];
|
||||
const char *next;
|
||||
|
||||
if (!name) {
|
||||
BT_ERR("Insufficient number of arguments");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len = read_cb(cb_arg, val, sizeof(val));
|
||||
if (len < 0) {
|
||||
BT_ERR("Failed to read value (err %zu)", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
BT_DBG("name %s val %s", log_strdup(name),
|
||||
(len) ? bt_hex(val, sizeof(val)) : "(null)");
|
||||
|
||||
err = bt_settings_decode_key(name, &addr);
|
||||
if (err) {
|
||||
BT_ERR("Unable to decode address %s", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
settings_name_next(name, &next);
|
||||
|
||||
if (!next) {
|
||||
id = BT_ID_DEFAULT;
|
||||
} else {
|
||||
id = strtol(next, NULL, 10);
|
||||
}
|
||||
|
||||
if (!len) {
|
||||
keys = bt_keys_find(BT_KEYS_ALL, id, &addr);
|
||||
if (keys) {
|
||||
(void)memset(keys, 0, sizeof(*keys));
|
||||
BT_DBG("Cleared keys for %s", bt_addr_le_str(&addr));
|
||||
} else {
|
||||
BT_WARN("Unable to find deleted keys for %s",
|
||||
bt_addr_le_str(&addr));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
keys = bt_keys_get_addr(id, &addr);
|
||||
if (!keys) {
|
||||
BT_ERR("Failed to allocate keys for %s", bt_addr_le_str(&addr));
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (len != BT_KEYS_STORAGE_LEN) {
|
||||
do {
|
||||
/* Load shorter structure for compatibility with old
|
||||
* records format with no counter.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST) &&
|
||||
len == BT_KEYS_STORAGE_LEN_COMPAT) {
|
||||
BT_WARN("Keys for %s have no aging counter",
|
||||
bt_addr_le_str(&addr));
|
||||
memcpy(keys->storage_start, val, len);
|
||||
continue;
|
||||
}
|
||||
|
||||
BT_ERR("Invalid key length %zu != %zu", len,
|
||||
BT_KEYS_STORAGE_LEN);
|
||||
bt_keys_clear(keys);
|
||||
|
||||
return -EINVAL;
|
||||
} while (0);
|
||||
} else {
|
||||
memcpy(keys->storage_start, val, len);
|
||||
}
|
||||
|
||||
BT_DBG("Successfully restored keys for %s", bt_addr_le_str(&addr));
|
||||
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
if (aging_counter_val < keys->aging_counter) {
|
||||
aging_counter_val = keys->aging_counter;
|
||||
}
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
return 0;
|
||||
}
|
||||
#endif //!(BFLB_BLE)
|
||||
|
||||
static void id_add(struct bt_keys *keys, void *user_data)
|
||||
{
|
||||
bt_id_add(keys);
|
||||
}
|
||||
|
||||
#if defined(BFLB_BLE)
|
||||
int keys_commit(void)
|
||||
#else
|
||||
static int keys_commit(void)
|
||||
#endif
|
||||
{
|
||||
BT_DBG("");
|
||||
|
||||
/* We do this in commit() rather than add() since add() may get
|
||||
* called multiple times for the same address, especially if
|
||||
* the keys were already removed.
|
||||
*/
|
||||
bt_keys_foreach(BT_KEYS_IRK, id_add, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//SETTINGS_STATIC_HANDLER_DEFINE(bt_keys, "bt/keys", NULL, keys_set, keys_commit,
|
||||
// NULL);
|
||||
|
||||
#if defined(BFLB_BLE)
|
||||
int bt_keys_load(void)
|
||||
{
|
||||
return bt_settings_get_bin(NV_KEY_POOL, (u8_t *)&key_pool[0], sizeof(key_pool), NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_BT_SETTINGS */
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
void bt_keys_update_usage(u8_t id, const bt_addr_le_t *addr)
|
||||
{
|
||||
struct bt_keys *keys = bt_keys_find_addr(id, addr);
|
||||
|
||||
if (!keys) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_keys_updated == keys) {
|
||||
return;
|
||||
}
|
||||
|
||||
keys->aging_counter = ++aging_counter_val;
|
||||
last_keys_updated = keys;
|
||||
|
||||
BT_DBG("Aging counter for %s is set to %u", bt_addr_le_str(addr),
|
||||
keys->aging_counter);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_KEYS_SAVE_AGING_COUNTER_ON_PAIRING)) {
|
||||
bt_keys_store(keys);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
@@ -0,0 +1,123 @@
|
||||
/* keys.h - Bluetooth key handling */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
enum {
|
||||
BT_KEYS_SLAVE_LTK = BIT(0),
|
||||
BT_KEYS_IRK = BIT(1),
|
||||
BT_KEYS_LTK = BIT(2),
|
||||
BT_KEYS_LOCAL_CSRK = BIT(3),
|
||||
BT_KEYS_REMOTE_CSRK = BIT(4),
|
||||
BT_KEYS_LTK_P256 = BIT(5),
|
||||
|
||||
BT_KEYS_ALL = (BT_KEYS_SLAVE_LTK | BT_KEYS_IRK |
|
||||
BT_KEYS_LTK | BT_KEYS_LOCAL_CSRK |
|
||||
BT_KEYS_REMOTE_CSRK | BT_KEYS_LTK_P256),
|
||||
};
|
||||
|
||||
enum {
|
||||
BT_KEYS_AUTHENTICATED = BIT(0),
|
||||
BT_KEYS_DEBUG = BIT(1),
|
||||
BT_KEYS_ID_PENDING_ADD = BIT(2),
|
||||
BT_KEYS_ID_PENDING_DEL = BIT(3),
|
||||
BT_KEYS_SC = BIT(4),
|
||||
};
|
||||
|
||||
struct bt_ltk {
|
||||
u8_t rand[8];
|
||||
u8_t ediv[2];
|
||||
u8_t val[16];
|
||||
};
|
||||
|
||||
struct bt_irk {
|
||||
u8_t val[16];
|
||||
bt_addr_t rpa;
|
||||
};
|
||||
|
||||
struct bt_csrk {
|
||||
u8_t val[16];
|
||||
u32_t cnt;
|
||||
};
|
||||
|
||||
struct bt_keys {
|
||||
u8_t id;
|
||||
bt_addr_le_t addr;
|
||||
#if !defined(BFLB_BLE)
|
||||
u8_t storage_start[0];
|
||||
#endif
|
||||
u8_t enc_size;
|
||||
u8_t flags;
|
||||
u16_t keys;
|
||||
struct bt_ltk ltk;
|
||||
struct bt_irk irk;
|
||||
#if defined(CONFIG_BT_SIGNING)
|
||||
struct bt_csrk local_csrk;
|
||||
struct bt_csrk remote_csrk;
|
||||
#endif /* BT_SIGNING */
|
||||
#if !defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
|
||||
struct bt_ltk slave_ltk;
|
||||
#endif /* CONFIG_BT_SMP_SC_PAIR_ONLY */
|
||||
#if (defined(CONFIG_BT_KEYS_OVERWRITE_OLDEST))
|
||||
u32_t aging_counter;
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
};
|
||||
|
||||
#if !defined(BFLB_BLE)
|
||||
#define BT_KEYS_STORAGE_LEN (sizeof(struct bt_keys) - \
|
||||
offsetof(struct bt_keys, storage_start))
|
||||
#endif
|
||||
|
||||
void bt_keys_foreach(int type, void (*func)(struct bt_keys *keys, void *data),
|
||||
void *data);
|
||||
|
||||
struct bt_keys *bt_keys_get_addr(u8_t id, const bt_addr_le_t *addr);
|
||||
struct bt_keys *bt_keys_get_type(int type, u8_t id, const bt_addr_le_t *addr);
|
||||
struct bt_keys *bt_keys_find(int type, u8_t id, const bt_addr_le_t *addr);
|
||||
struct bt_keys *bt_keys_find_irk(u8_t id, const bt_addr_le_t *addr);
|
||||
struct bt_keys *bt_keys_find_addr(u8_t id, const bt_addr_le_t *addr);
|
||||
#if defined(CONFIG_BLE_AT_CMD)
|
||||
bt_addr_le_t *bt_get_keys_address(u8_t id);
|
||||
#endif
|
||||
|
||||
void bt_keys_add_type(struct bt_keys *keys, int type);
|
||||
void bt_keys_clear(struct bt_keys *keys);
|
||||
void bt_keys_clear_all(u8_t id);
|
||||
#if defined(BFLB_BLE)
|
||||
int keys_commit(void);
|
||||
int bt_keys_load(void);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_SETTINGS)
|
||||
int bt_keys_store(struct bt_keys *keys);
|
||||
#else
|
||||
static inline int bt_keys_store(struct bt_keys *keys)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
enum {
|
||||
BT_LINK_KEY_AUTHENTICATED = BIT(0),
|
||||
BT_LINK_KEY_DEBUG = BIT(1),
|
||||
BT_LINK_KEY_SC = BIT(2),
|
||||
};
|
||||
|
||||
struct bt_keys_link_key {
|
||||
bt_addr_t addr;
|
||||
u8_t flags;
|
||||
u8_t val[16];
|
||||
};
|
||||
|
||||
struct bt_keys_link_key *bt_keys_get_link_key(const bt_addr_t *addr);
|
||||
struct bt_keys_link_key *bt_keys_find_link_key(const bt_addr_t *addr);
|
||||
void bt_keys_link_key_clear(struct bt_keys_link_key *link_key);
|
||||
void bt_keys_link_key_clear_addr(const bt_addr_t *addr);
|
||||
|
||||
/* This function is used to signal that the key has been used for paring */
|
||||
/* It updates the aging counter and saves it to flash if configuration option */
|
||||
/* BT_KEYS_SAVE_AGING_COUNTER_ON_PAIRING is enabled */
|
||||
void bt_keys_update_usage(u8_t id, const bt_addr_le_t *addr);
|
||||
@@ -0,0 +1,241 @@
|
||||
/* keys_br.c - Bluetooth BR/EDR key handling */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <string.h>
|
||||
#include <atomic.h>
|
||||
#include <util.h>
|
||||
|
||||
#include <bluetooth.h>
|
||||
#include <conn.h>
|
||||
#include <hci_host.h>
|
||||
#include <settings.h>
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_KEYS)
|
||||
#define LOG_MODULE_NAME bt_keys_br
|
||||
#include "log.h"
|
||||
|
||||
#include "hci_core.h"
|
||||
#include "settings.h"
|
||||
#include "keys.h"
|
||||
|
||||
static struct bt_keys_link_key key_pool[CONFIG_BT_MAX_PAIRED];
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
static uint32_t aging_counter_val;
|
||||
static struct bt_keys_link_key *last_keys_updated;
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
|
||||
struct bt_keys_link_key *bt_keys_find_link_key(const bt_addr_t *addr)
|
||||
{
|
||||
struct bt_keys_link_key *key;
|
||||
int i;
|
||||
|
||||
BT_DBG("%s", bt_addr_str(addr));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
|
||||
key = &key_pool[i];
|
||||
|
||||
if (!bt_addr_cmp(&key->addr, addr)) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct bt_keys_link_key *bt_keys_get_link_key(const bt_addr_t *addr)
|
||||
{
|
||||
struct bt_keys_link_key *key;
|
||||
|
||||
key = bt_keys_find_link_key(addr);
|
||||
if (key) {
|
||||
return key;
|
||||
}
|
||||
|
||||
key = bt_keys_find_link_key(BT_ADDR_ANY);
|
||||
#if 0 //IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST) //MBHJ
|
||||
if (!key) {
|
||||
int i;
|
||||
|
||||
key = &key_pool[0];
|
||||
for (i = 1; i < ARRAY_SIZE(key_pool); i++) {
|
||||
struct bt_keys_link_key *current = &key_pool[i];
|
||||
|
||||
if (current->aging_counter < key->aging_counter) {
|
||||
key = current;
|
||||
}
|
||||
}
|
||||
|
||||
if (key) {
|
||||
bt_keys_link_key_clear(key);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (key) {
|
||||
bt_addr_copy(&key->addr, addr);
|
||||
#if 0 //IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST) //MBHJ
|
||||
key->aging_counter = ++aging_counter_val;
|
||||
last_keys_updated = key;
|
||||
#endif
|
||||
BT_DBG("created %p for %s", key, bt_addr_str(addr));
|
||||
return key;
|
||||
}
|
||||
|
||||
BT_DBG("unable to create keys for %s", bt_addr_str(addr));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bt_keys_link_key_clear(struct bt_keys_link_key *link_key)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
char key[BT_SETTINGS_KEY_MAX];
|
||||
bt_addr_le_t le_addr;
|
||||
|
||||
le_addr.type = BT_ADDR_LE_PUBLIC;
|
||||
bt_addr_copy(&le_addr.a, &link_key->addr);
|
||||
bt_settings_encode_key(key, sizeof(key), "link_key",
|
||||
&le_addr, NULL);
|
||||
settings_delete(key);
|
||||
}
|
||||
|
||||
BT_DBG("%s", bt_addr_str(&link_key->addr));
|
||||
(void)memset(link_key, 0, sizeof(*link_key));
|
||||
}
|
||||
|
||||
void bt_keys_link_key_clear_addr(const bt_addr_t *addr)
|
||||
{
|
||||
int i;
|
||||
struct bt_keys_link_key *key;
|
||||
|
||||
if (!addr) {
|
||||
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
|
||||
key = &key_pool[i];
|
||||
bt_keys_link_key_clear(key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
key = bt_keys_find_link_key(addr);
|
||||
if (key) {
|
||||
bt_keys_link_key_clear(key);
|
||||
}
|
||||
}
|
||||
|
||||
void bt_keys_link_key_store(struct bt_keys_link_key *link_key)
|
||||
{
|
||||
#if 0 //MBHJ
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
int err;
|
||||
char key[BT_SETTINGS_KEY_MAX];
|
||||
bt_addr_le_t le_addr;
|
||||
|
||||
le_addr.type = BT_ADDR_LE_PUBLIC;
|
||||
bt_addr_copy(&le_addr.a, &link_key->addr);
|
||||
bt_settings_encode_key(key, sizeof(key), "link_key",
|
||||
&le_addr, NULL);
|
||||
|
||||
err = settings_save_one(key, link_key->storage_start,
|
||||
BT_KEYS_LINK_KEY_STORAGE_LEN);
|
||||
if (err) {
|
||||
BT_ERR("Failed to svae link key (err %d)", err);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_SETTINGS)
|
||||
|
||||
static int link_key_set(const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
int err;
|
||||
ssize_t len;
|
||||
bt_addr_le_t le_addr;
|
||||
struct bt_keys_link_key *link_key;
|
||||
char val[BT_KEYS_LINK_KEY_STORAGE_LEN];
|
||||
|
||||
if (!name) {
|
||||
BT_ERR("Insufficient number of arguments");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len = read_cb(cb_arg, val, sizeof(val));
|
||||
if (len < 0) {
|
||||
BT_ERR("Failed to read value (err %zu)", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
BT_DBG("name %s val %s", log_strdup(name),
|
||||
len ? bt_hex(val, sizeof(val)) : "(null)");
|
||||
|
||||
err = bt_settings_decode_key(name, &le_addr);
|
||||
if (err) {
|
||||
BT_ERR("Unable to decode address %s", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
link_key = bt_keys_get_link_key(&le_addr.a);
|
||||
if (len != BT_KEYS_LINK_KEY_STORAGE_LEN) {
|
||||
if (link_key) {
|
||||
bt_keys_link_key_clear(link_key);
|
||||
BT_DBG("Clear keys for %s", bt_addr_le_str(&le_addr));
|
||||
} else {
|
||||
BT_WARN("Unable to find deleted keys for %s",
|
||||
bt_addr_le_str(&le_addr));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(link_key->storage_start, val, len);
|
||||
BT_DBG("Successfully restored link key for %s",
|
||||
bt_addr_le_str(&le_addr));
|
||||
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
if (aging_counter_val < link_key->aging_counter) {
|
||||
aging_counter_val = link_key->aging_counter;
|
||||
}
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_key_commit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SETTINGS_STATIC_HANDLER_DEFINE(bt_link_key, "bt/link_key", NULL, link_key_set,
|
||||
link_key_commit, NULL);
|
||||
|
||||
void bt_keys_link_key_update_usage(const bt_addr_t *addr)
|
||||
{
|
||||
struct bt_keys_link_key *link_key = bt_keys_find_link_key(addr);
|
||||
|
||||
if (!link_key) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_keys_updated == link_key) {
|
||||
return;
|
||||
}
|
||||
|
||||
link_key->aging_counter = ++aging_counter_val;
|
||||
last_keys_updated = link_key;
|
||||
|
||||
BT_DBG("Aging counter for %s is set to %u", bt_addr_str(addr),
|
||||
link_key->aging_counter);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_KEYS_SAVE_AGING_COUNTER_ON_PAIRING)) {
|
||||
bt_keys_link_key_store(link_key);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,340 @@
|
||||
/** @file
|
||||
* @brief Internal APIs for Bluetooth L2CAP handling.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <l2cap.h>
|
||||
|
||||
enum l2cap_conn_list_action {
|
||||
BT_L2CAP_CHAN_LOOKUP,
|
||||
BT_L2CAP_CHAN_DETACH,
|
||||
};
|
||||
|
||||
#define BT_L2CAP_CID_BR_SIG 0x0001
|
||||
#define BT_L2CAP_CID_ATT 0x0004
|
||||
#define BT_L2CAP_CID_LE_SIG 0x0005
|
||||
#define BT_L2CAP_CID_SMP 0x0006
|
||||
#define BT_L2CAP_CID_BR_SMP 0x0007
|
||||
|
||||
#define BT_L2CAP_PSM_RFCOMM 0x0003
|
||||
|
||||
struct bt_l2cap_hdr {
|
||||
u16_t len;
|
||||
u16_t cid;
|
||||
} __packed;
|
||||
|
||||
struct bt_l2cap_sig_hdr {
|
||||
u8_t code;
|
||||
u8_t ident;
|
||||
u16_t len;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_REJ_NOT_UNDERSTOOD 0x0000
|
||||
#define BT_L2CAP_REJ_MTU_EXCEEDED 0x0001
|
||||
#define BT_L2CAP_REJ_INVALID_CID 0x0002
|
||||
|
||||
#define BT_L2CAP_CMD_REJECT 0x01
|
||||
struct bt_l2cap_cmd_reject {
|
||||
u16_t reason;
|
||||
u8_t data[0];
|
||||
} __packed;
|
||||
|
||||
struct bt_l2cap_cmd_reject_cid_data {
|
||||
u16_t scid;
|
||||
u16_t dcid;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_CONN_REQ 0x02
|
||||
struct bt_l2cap_conn_req {
|
||||
u16_t psm;
|
||||
u16_t scid;
|
||||
} __packed;
|
||||
|
||||
/* command statuses in reposnse */
|
||||
#define BT_L2CAP_CS_NO_INFO 0x0000
|
||||
#define BT_L2CAP_CS_AUTHEN_PEND 0x0001
|
||||
|
||||
/* valid results in conn response on BR/EDR */
|
||||
#define BT_L2CAP_BR_SUCCESS 0x0000
|
||||
#define BT_L2CAP_BR_PENDING 0x0001
|
||||
#define BT_L2CAP_BR_ERR_PSM_NOT_SUPP 0x0002
|
||||
#define BT_L2CAP_BR_ERR_SEC_BLOCK 0x0003
|
||||
#define BT_L2CAP_BR_ERR_NO_RESOURCES 0x0004
|
||||
#define BT_L2CAP_BR_ERR_INVALID_SCID 0x0006
|
||||
#define BT_L2CAP_BR_ERR_SCID_IN_USE 0x0007
|
||||
|
||||
#define BT_L2CAP_CONN_RSP 0x03
|
||||
struct bt_l2cap_conn_rsp {
|
||||
u16_t dcid;
|
||||
u16_t scid;
|
||||
u16_t result;
|
||||
u16_t status;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_CONF_SUCCESS 0x0000
|
||||
#define BT_L2CAP_CONF_UNACCEPT 0x0001
|
||||
#define BT_L2CAP_CONF_REJECT 0x0002
|
||||
|
||||
#define BT_L2CAP_CONF_REQ 0x04
|
||||
struct bt_l2cap_conf_req {
|
||||
u16_t dcid;
|
||||
u16_t flags;
|
||||
u8_t data[0];
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_CONF_RSP 0x05
|
||||
struct bt_l2cap_conf_rsp {
|
||||
u16_t scid;
|
||||
u16_t flags;
|
||||
u16_t result;
|
||||
u8_t data[0];
|
||||
} __packed;
|
||||
|
||||
/* Option type used by MTU config request data */
|
||||
#define BT_L2CAP_CONF_OPT_MTU 0x01
|
||||
/* Options bits selecting most significant bit (hint) in type field */
|
||||
#define BT_L2CAP_CONF_HINT 0x80
|
||||
#define BT_L2CAP_CONF_MASK 0x7f
|
||||
|
||||
struct bt_l2cap_conf_opt {
|
||||
u8_t type;
|
||||
u8_t len;
|
||||
u8_t data[0];
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_DISCONN_REQ 0x06
|
||||
struct bt_l2cap_disconn_req {
|
||||
u16_t dcid;
|
||||
u16_t scid;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_DISCONN_RSP 0x07
|
||||
struct bt_l2cap_disconn_rsp {
|
||||
u16_t dcid;
|
||||
u16_t scid;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_INFO_FEAT_MASK 0x0002
|
||||
#define BT_L2CAP_INFO_FIXED_CHAN 0x0003
|
||||
|
||||
#define BT_L2CAP_INFO_REQ 0x0a
|
||||
struct bt_l2cap_info_req {
|
||||
u16_t type;
|
||||
} __packed;
|
||||
|
||||
/* info result */
|
||||
#define BT_L2CAP_INFO_SUCCESS 0x0000
|
||||
#define BT_L2CAP_INFO_NOTSUPP 0x0001
|
||||
|
||||
#define BT_L2CAP_INFO_RSP 0x0b
|
||||
struct bt_l2cap_info_rsp {
|
||||
u16_t type;
|
||||
u16_t result;
|
||||
u8_t data[0];
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_CONN_PARAM_REQ 0x12
|
||||
struct bt_l2cap_conn_param_req {
|
||||
u16_t min_interval;
|
||||
u16_t max_interval;
|
||||
u16_t latency;
|
||||
u16_t timeout;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_CONN_PARAM_ACCEPTED 0x0000
|
||||
#define BT_L2CAP_CONN_PARAM_REJECTED 0x0001
|
||||
|
||||
#define BT_L2CAP_CONN_PARAM_RSP 0x13
|
||||
struct bt_l2cap_conn_param_rsp {
|
||||
u16_t result;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_LE_CONN_REQ 0x14
|
||||
struct bt_l2cap_le_conn_req {
|
||||
u16_t psm;
|
||||
u16_t scid;
|
||||
u16_t mtu;
|
||||
u16_t mps;
|
||||
u16_t credits;
|
||||
} __packed;
|
||||
|
||||
/* valid results in conn response on LE */
|
||||
#define BT_L2CAP_LE_SUCCESS 0x0000
|
||||
#define BT_L2CAP_LE_ERR_PSM_NOT_SUPP 0x0002
|
||||
#define BT_L2CAP_LE_ERR_NO_RESOURCES 0x0004
|
||||
#define BT_L2CAP_LE_ERR_AUTHENTICATION 0x0005
|
||||
#define BT_L2CAP_LE_ERR_AUTHORIZATION 0x0006
|
||||
#define BT_L2CAP_LE_ERR_KEY_SIZE 0x0007
|
||||
#define BT_L2CAP_LE_ERR_ENCRYPTION 0x0008
|
||||
#define BT_L2CAP_LE_ERR_INVALID_SCID 0x0009
|
||||
#define BT_L2CAP_LE_ERR_SCID_IN_USE 0x000A
|
||||
#define BT_L2CAP_LE_ERR_UNACCEPT_PARAMS 0x000B
|
||||
|
||||
#define BT_L2CAP_LE_CONN_RSP 0x15
|
||||
struct bt_l2cap_le_conn_rsp {
|
||||
u16_t dcid;
|
||||
u16_t mtu;
|
||||
u16_t mps;
|
||||
u16_t credits;
|
||||
u16_t result;
|
||||
};
|
||||
|
||||
#define BT_L2CAP_LE_CREDITS 0x16
|
||||
struct bt_l2cap_le_credits {
|
||||
u16_t cid;
|
||||
u16_t credits;
|
||||
} __packed;
|
||||
|
||||
#define BT_L2CAP_SDU_HDR_LEN 2
|
||||
|
||||
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
|
||||
#define BT_L2CAP_RX_MTU CONFIG_BT_L2CAP_RX_MTU
|
||||
#else
|
||||
#define BT_L2CAP_RX_MTU (CONFIG_BT_RX_BUF_LEN - \
|
||||
BT_HCI_ACL_HDR_SIZE - BT_L2CAP_HDR_SIZE)
|
||||
#endif
|
||||
|
||||
struct bt_l2cap_fixed_chan {
|
||||
u16_t cid;
|
||||
int (*accept)(struct bt_conn *conn, struct bt_l2cap_chan **chan);
|
||||
sys_snode_t node;
|
||||
};
|
||||
|
||||
#define BT_L2CAP_CHANNEL_DEFINE(_name, _cid, _accept) \
|
||||
const Z_STRUCT_SECTION_ITERABLE(bt_l2cap_fixed_chan, _name) = { \
|
||||
.cid = _cid, \
|
||||
.accept = _accept, \
|
||||
}
|
||||
|
||||
/* Need a name different than bt_l2cap_fixed_chan for a different section */
|
||||
struct bt_l2cap_br_fixed_chan {
|
||||
u16_t cid;
|
||||
int (*accept)(struct bt_conn *conn, struct bt_l2cap_chan **chan);
|
||||
};
|
||||
|
||||
#define BT_L2CAP_BR_CHANNEL_DEFINE(_name, _cid, _accept) \
|
||||
const Z_STRUCT_SECTION_ITERABLE(bt_l2cap_br_fixed_chan, _name) = { \
|
||||
.cid = _cid, \
|
||||
.accept = _accept, \
|
||||
}
|
||||
|
||||
void l2cap_chan_sdu_sent(struct bt_conn *conn, void *user_data);
|
||||
/* Register a fixed L2CAP channel for L2CAP */
|
||||
void bt_l2cap_le_fixed_chan_register(struct bt_l2cap_fixed_chan *chan);
|
||||
|
||||
/* Notify L2CAP channels of a new connection */
|
||||
void bt_l2cap_connected(struct bt_conn *conn);
|
||||
|
||||
/* Notify L2CAP channels of a disconnect event */
|
||||
void bt_l2cap_disconnected(struct bt_conn *conn);
|
||||
|
||||
/* Add channel to the connection */
|
||||
void bt_l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan,
|
||||
bt_l2cap_chan_destroy_t destroy);
|
||||
|
||||
/* Remove channel from the connection */
|
||||
void bt_l2cap_chan_remove(struct bt_conn *conn, struct bt_l2cap_chan *chan);
|
||||
|
||||
/* Delete channel */
|
||||
void bt_l2cap_chan_del(struct bt_l2cap_chan *chan);
|
||||
|
||||
const char *bt_l2cap_chan_state_str(bt_l2cap_chan_state_t state);
|
||||
|
||||
#if defined(CONFIG_BT_DEBUG_L2CAP)
|
||||
void bt_l2cap_chan_set_state_debug(struct bt_l2cap_chan *chan,
|
||||
bt_l2cap_chan_state_t state,
|
||||
const char *func, int line);
|
||||
#define bt_l2cap_chan_set_state(_chan, _state) \
|
||||
bt_l2cap_chan_set_state_debug(_chan, _state, __func__, __LINE__)
|
||||
#else
|
||||
void bt_l2cap_chan_set_state(struct bt_l2cap_chan *chan,
|
||||
bt_l2cap_chan_state_t state);
|
||||
#endif /* CONFIG_BT_DEBUG_L2CAP */
|
||||
|
||||
/*
|
||||
* Notify L2CAP channels of a change in encryption state passing additionally
|
||||
* HCI status of performed security procedure.
|
||||
*/
|
||||
void bt_l2cap_encrypt_change(struct bt_conn *conn, u8_t hci_status);
|
||||
|
||||
/* Prepare an L2CAP PDU to be sent over a connection */
|
||||
struct net_buf *bt_l2cap_create_pdu_timeout(struct net_buf_pool *pool,
|
||||
size_t reserve, s32_t timeout);
|
||||
|
||||
#define bt_l2cap_create_pdu(_pool, _reserve) \
|
||||
bt_l2cap_create_pdu_timeout(_pool, _reserve, K_FOREVER)
|
||||
|
||||
/* Prepare a L2CAP Response PDU to be sent over a connection */
|
||||
struct net_buf *bt_l2cap_create_rsp(struct net_buf *buf, size_t reserve);
|
||||
|
||||
/* Send L2CAP PDU over a connection
|
||||
*
|
||||
* Buffer ownership is transferred to stack so either in case of success
|
||||
* or error the buffer will be unref internally.
|
||||
*
|
||||
* Calling this from RX thread is assumed to never fail so the return can be
|
||||
* ignored.
|
||||
*/
|
||||
int bt_l2cap_send_cb(struct bt_conn *conn, u16_t cid, struct net_buf *buf,
|
||||
bt_conn_tx_cb_t cb, void *user_data);
|
||||
|
||||
static inline void bt_l2cap_send(struct bt_conn *conn, u16_t cid,
|
||||
struct net_buf *buf)
|
||||
{
|
||||
bt_l2cap_send_cb(conn, cid, buf, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Receive a new L2CAP PDU from a connection */
|
||||
void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf);
|
||||
|
||||
/* Perform connection parameter update request */
|
||||
int bt_l2cap_update_conn_param(struct bt_conn *conn,
|
||||
const struct bt_le_conn_param *param);
|
||||
|
||||
/* Initialize L2CAP and supported channels */
|
||||
void bt_l2cap_init(void);
|
||||
|
||||
/* Lookup channel by Transmission CID */
|
||||
struct bt_l2cap_chan *bt_l2cap_le_lookup_tx_cid(struct bt_conn *conn,
|
||||
u16_t cid);
|
||||
|
||||
/* Lookup channel by Receiver CID */
|
||||
struct bt_l2cap_chan *bt_l2cap_le_lookup_rx_cid(struct bt_conn *conn,
|
||||
u16_t cid);
|
||||
|
||||
/* Initialize BR/EDR L2CAP signal layer */
|
||||
void bt_l2cap_br_init(void);
|
||||
|
||||
/* Register fixed channel */
|
||||
void bt_l2cap_br_fixed_chan_register(struct bt_l2cap_fixed_chan *chan);
|
||||
|
||||
/* Notify BR/EDR L2CAP channels about established new ACL connection */
|
||||
void bt_l2cap_br_connected(struct bt_conn *conn);
|
||||
|
||||
/* Lookup BR/EDR L2CAP channel by Receiver CID */
|
||||
struct bt_l2cap_chan *bt_l2cap_br_lookup_rx_cid(struct bt_conn *conn,
|
||||
u16_t cid);
|
||||
|
||||
/* Disconnects dynamic channel */
|
||||
int bt_l2cap_br_chan_disconnect(struct bt_l2cap_chan *chan);
|
||||
|
||||
/* Make connection to peer psm server */
|
||||
int bt_l2cap_br_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan,
|
||||
u16_t psm);
|
||||
|
||||
/* Send packet data to connected peer */
|
||||
int bt_l2cap_br_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf);
|
||||
|
||||
/*
|
||||
* Handle security level changed on link passing HCI status of performed
|
||||
* security procedure.
|
||||
*/
|
||||
void l2cap_br_encrypt_change(struct bt_conn *conn, u8_t hci_status);
|
||||
|
||||
/* Handle received data */
|
||||
void bt_l2cap_br_recv(struct bt_conn *conn, struct net_buf *buf);
|
||||
@@ -0,0 +1,28 @@
|
||||
/** @file
|
||||
* @brief Custom logging over UART
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#if defined(CONFIG_BT_DEBUG_MONITOR)
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <buf.h>
|
||||
#include "monitor.h"
|
||||
#include "log.h"
|
||||
|
||||
void bt_monitor_send(uint16_t opcode, const void *data, size_t len)
|
||||
{
|
||||
const uint8_t *buf = data;
|
||||
|
||||
BT_WARN("[Hci]:pkt_type:[0x%x],pkt_data:[%s]\r\n", opcode, bt_hex(buf, len));
|
||||
}
|
||||
|
||||
void bt_monitor_new_index(uint8_t type, uint8_t bus, bt_addr_t *addr,
|
||||
const char *name)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,102 @@
|
||||
/** @file
|
||||
* @brief Custom monitor protocol logging over UART
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BT_DEBUG_MONITOR)
|
||||
|
||||
#define BT_MONITOR_NEW_INDEX 0
|
||||
#define BT_MONITOR_DEL_INDEX 1
|
||||
#define BT_MONITOR_COMMAND_PKT 2
|
||||
#define BT_MONITOR_EVENT_PKT 3
|
||||
#define BT_MONITOR_ACL_TX_PKT 4
|
||||
#define BT_MONITOR_ACL_RX_PKT 5
|
||||
#define BT_MONITOR_SCO_TX_PKT 6
|
||||
#define BT_MONITOR_SCO_RX_PKT 7
|
||||
#define BT_MONITOR_OPEN_INDEX 8
|
||||
#define BT_MONITOR_CLOSE_INDEX 9
|
||||
#define BT_MONITOR_INDEX_INFO 10
|
||||
#define BT_MONITOR_VENDOR_DIAG 11
|
||||
#define BT_MONITOR_SYSTEM_NOTE 12
|
||||
#define BT_MONITOR_USER_LOGGING 13
|
||||
#define BT_MONITOR_NOP 255
|
||||
|
||||
#define BT_MONITOR_TYPE_PRIMARY 0
|
||||
#define BT_MONITOR_TYPE_AMP 1
|
||||
|
||||
/* Extended header types */
|
||||
#define BT_MONITOR_COMMAND_DROPS 1
|
||||
#define BT_MONITOR_EVENT_DROPS 2
|
||||
#define BT_MONITOR_ACL_RX_DROPS 3
|
||||
#define BT_MONITOR_ACL_TX_DROPS 4
|
||||
#define BT_MONITOR_SCO_RX_DROPS 5
|
||||
#define BT_MONITOR_SCO_TX_DROPS 6
|
||||
#define BT_MONITOR_OTHER_DROPS 7
|
||||
#define BT_MONITOR_TS32 8
|
||||
|
||||
#define BT_MONITOR_BASE_HDR_LEN 6
|
||||
|
||||
#if defined(CONFIG_BT_BREDR)
|
||||
#define BT_MONITOR_EXT_HDR_MAX 19
|
||||
#else
|
||||
#define BT_MONITOR_EXT_HDR_MAX 15
|
||||
#endif
|
||||
|
||||
struct bt_monitor_hdr {
|
||||
u16_t data_len;
|
||||
u16_t opcode;
|
||||
u8_t flags;
|
||||
u8_t hdr_len;
|
||||
|
||||
u8_t ext[BT_MONITOR_EXT_HDR_MAX];
|
||||
} __packed;
|
||||
|
||||
struct bt_monitor_ts32 {
|
||||
u8_t type;
|
||||
u32_t ts32;
|
||||
} __packed;
|
||||
|
||||
struct bt_monitor_new_index {
|
||||
u8_t type;
|
||||
u8_t bus;
|
||||
u8_t bdaddr[6];
|
||||
char name[8];
|
||||
} __packed;
|
||||
|
||||
struct bt_monitor_user_logging {
|
||||
u8_t priority;
|
||||
u8_t ident_len;
|
||||
} __packed;
|
||||
|
||||
static inline u8_t bt_monitor_opcode(struct net_buf *buf)
|
||||
{
|
||||
switch (bt_buf_get_type(buf)) {
|
||||
case BT_BUF_CMD:
|
||||
return BT_MONITOR_COMMAND_PKT;
|
||||
case BT_BUF_EVT:
|
||||
return BT_MONITOR_EVENT_PKT;
|
||||
case BT_BUF_ACL_OUT:
|
||||
return BT_MONITOR_ACL_TX_PKT;
|
||||
case BT_BUF_ACL_IN:
|
||||
return BT_MONITOR_ACL_RX_PKT;
|
||||
default:
|
||||
return BT_MONITOR_NOP;
|
||||
}
|
||||
}
|
||||
|
||||
void bt_monitor_send(u16_t opcode, const void *data, size_t len);
|
||||
|
||||
void bt_monitor_new_index(u8_t type, u8_t bus, bt_addr_t *addr,
|
||||
const char *name);
|
||||
|
||||
#else /* !CONFIG_BT_DEBUG_MONITOR */
|
||||
|
||||
#define bt_monitor_send(opcode, data, len)
|
||||
#define bt_monitor_new_index(type, bus, addr, name)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,514 @@
|
||||
/*
|
||||
* xx
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <util.h>
|
||||
|
||||
//#include <net/buf.h>
|
||||
#include <bluetooth.h>
|
||||
#include <hci_core.h>
|
||||
|
||||
#include "multi_adv.h"
|
||||
#include "work_q.h"
|
||||
|
||||
static struct multi_adv_instant g_multi_adv_list[MAX_MULTI_ADV_INSTANT];
|
||||
static struct multi_adv_scheduler g_multi_adv_scheduler;
|
||||
static struct k_delayed_work g_multi_adv_timer;
|
||||
|
||||
void multi_adv_schedule_timeslot(struct multi_adv_scheduler *adv_scheduler);
|
||||
int multi_adv_schedule_timer_stop(void);
|
||||
|
||||
int multi_adv_get_instant_num(void)
|
||||
{
|
||||
int i, num = 0;
|
||||
struct multi_adv_instant *inst = &(g_multi_adv_list[0]);
|
||||
|
||||
for (i = 0; i < MAX_MULTI_ADV_INSTANT; i++) {
|
||||
if (inst[i].inuse_flag)
|
||||
num++;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
struct multi_adv_instant *multi_adv_alloc_unused_instant(void)
|
||||
{
|
||||
int i;
|
||||
struct multi_adv_instant *inst = &(g_multi_adv_list[0]);
|
||||
|
||||
for (i = 0; i < MAX_MULTI_ADV_INSTANT; i++) {
|
||||
if (inst[i].inuse_flag == 0) {
|
||||
inst[i].inuse_flag = 1;
|
||||
inst[i].instant_id = i + 1;
|
||||
return &(inst[i]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int multi_adv_delete_instant_by_id(int instant_id)
|
||||
{
|
||||
int i;
|
||||
struct multi_adv_instant *inst = &(g_multi_adv_list[0]);
|
||||
|
||||
for (i = 0; i < MAX_MULTI_ADV_INSTANT; i++) {
|
||||
if ((inst[i].inuse_flag) && (instant_id == (inst[i].instant_id))) {
|
||||
inst[i].inuse_flag = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct multi_adv_instant *multi_adv_find_instant_by_id(int instant_id)
|
||||
{
|
||||
int i;
|
||||
struct multi_adv_instant *inst = &(g_multi_adv_list[0]);
|
||||
|
||||
for (i = 0; i < MAX_MULTI_ADV_INSTANT; i++) {
|
||||
if ((inst[i].inuse_flag) && (instant_id == (inst[i].instant_id))) {
|
||||
return &(inst[i]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct multi_adv_instant *multi_adv_find_instant_by_order(int order)
|
||||
{
|
||||
struct multi_adv_instant *inst = &(g_multi_adv_list[0]);
|
||||
|
||||
if (inst[order].inuse_flag) {
|
||||
return &(inst[order]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int multi_adv_set_ad_data(uint8_t *ad_data, const struct bt_data *ad, size_t ad_len)
|
||||
{
|
||||
int i, len;
|
||||
|
||||
memset(ad_data, 0, MAX_AD_DATA_LEN);
|
||||
len = 0;
|
||||
for (i = 0; i < ad_len; i++) {
|
||||
/* Check if ad fit in the remaining buffer */
|
||||
if (len + ad[i].data_len + 2 > MAX_AD_DATA_LEN) {
|
||||
break;
|
||||
}
|
||||
|
||||
ad_data[len++] = ad[i].data_len + 1;
|
||||
ad_data[len++] = ad[i].type;
|
||||
|
||||
memcpy(&ad_data[len], ad[i].data, ad[i].data_len);
|
||||
len += ad[i].data_len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int change_to_tick(int min_interval, int max_interval)
|
||||
{
|
||||
int tick;
|
||||
|
||||
if (max_interval / SLOT_PER_PERIOD != min_interval / SLOT_PER_PERIOD) {
|
||||
tick = min_interval / SLOT_PER_PERIOD;
|
||||
if (min_interval % SLOT_PER_PERIOD)
|
||||
tick++;
|
||||
} else {
|
||||
tick = min_interval / SLOT_PER_PERIOD;
|
||||
}
|
||||
if (tick <= 1)
|
||||
tick = 1;
|
||||
|
||||
return tick;
|
||||
}
|
||||
|
||||
int calculate_min_multi(int a, int b)
|
||||
{
|
||||
int x = a, y = b, z;
|
||||
|
||||
while (y != 0) {
|
||||
z = x % y;
|
||||
x = y;
|
||||
y = z;
|
||||
}
|
||||
|
||||
return a * b / x;
|
||||
}
|
||||
|
||||
void multi_adv_reorder(int inst_num, uint16_t inst_interval[], uint8_t inst_order[])
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < inst_num; i++) {
|
||||
int max = inst_interval[0];
|
||||
int max_idx = 0;
|
||||
int temp;
|
||||
|
||||
for (j = 1; j < inst_num - i; j++) {
|
||||
if (max < inst_interval[j]) {
|
||||
max = inst_interval[j];
|
||||
max_idx = j;
|
||||
}
|
||||
}
|
||||
|
||||
temp = inst_interval[inst_num - i - 1];
|
||||
inst_interval[inst_num - i - 1] = inst_interval[max_idx];
|
||||
inst_interval[max_idx] = temp;
|
||||
|
||||
temp = inst_order[inst_num - i - 1];
|
||||
inst_order[inst_num - i - 1] = inst_order[max_idx];
|
||||
inst_order[max_idx] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
int calculate_offset(uint16_t interval[], uint16_t offset[], int num, int duration)
|
||||
{
|
||||
int i, j, k, curr_offset = 0;
|
||||
int curr_max_instants, min_max_instants, instants;
|
||||
int offset_range;
|
||||
|
||||
offset_range = interval[num];
|
||||
if (offset_range > duration)
|
||||
offset_range = duration;
|
||||
|
||||
if (num == 0)
|
||||
return 0;
|
||||
|
||||
min_max_instants = 0x7fffffff;
|
||||
/* using 0-interval-1 as offset */
|
||||
for (i = 0; i < offset_range; i++) {
|
||||
curr_max_instants = 0;
|
||||
/* search slot form 0 - duration to get the max instants number */
|
||||
for (j = 0; j < duration; j++) {
|
||||
/* get instant number in each slot */
|
||||
instants = 0;
|
||||
for (k = 0; k < num; k++) {
|
||||
if (j % interval[k] == offset[k]) {
|
||||
instants++;
|
||||
}
|
||||
}
|
||||
if (j % interval[num] == i)
|
||||
instants++;
|
||||
if (curr_max_instants < instants) {
|
||||
curr_max_instants = instants;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if min max instants */
|
||||
if (min_max_instants > curr_max_instants) {
|
||||
min_max_instants = curr_max_instants;
|
||||
curr_offset = i;
|
||||
}
|
||||
}
|
||||
return curr_offset;
|
||||
}
|
||||
|
||||
void multi_adv_schedule_table(int inst_num, uint16_t inst_interval[], uint16_t inst_offset[])
|
||||
{
|
||||
int i, min_multi, last_min_multi;
|
||||
/* calculate min multi */
|
||||
last_min_multi = min_multi = inst_interval[0];
|
||||
for (i = 1; i < inst_num; i++) {
|
||||
min_multi = calculate_min_multi(min_multi, inst_interval[i]);
|
||||
if (min_multi > MAX_MIN_MULTI) {
|
||||
min_multi = last_min_multi;
|
||||
break;
|
||||
}
|
||||
last_min_multi = min_multi;
|
||||
}
|
||||
|
||||
/* offset calcute for schedule just for small interval range */
|
||||
for (i = 0; i < inst_num; i++) {
|
||||
inst_offset[i] = calculate_offset(inst_interval, inst_offset, i, min_multi);
|
||||
}
|
||||
}
|
||||
|
||||
int multi_adv_start_adv_instant(struct multi_adv_instant *adv_instant)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = bt_le_adv_start_instant(&adv_instant->param,
|
||||
adv_instant->ad, adv_instant->ad_len,
|
||||
adv_instant->sd, adv_instant->sd_len);
|
||||
if (ret) {
|
||||
BT_WARN("adv start instant failed: inst_id %d, err %d\r\n", adv_instant->instant_id, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void multi_adv_schedule_timer_handle(void)
|
||||
{
|
||||
struct multi_adv_scheduler *adv_scheduler = &g_multi_adv_scheduler;
|
||||
|
||||
multi_adv_schedule_timer_stop();
|
||||
if (adv_scheduler->schedule_state == SCHEDULE_STOP)
|
||||
return;
|
||||
|
||||
adv_scheduler->slot_clock = adv_scheduler->next_slot_clock;
|
||||
adv_scheduler->slot_offset = adv_scheduler->next_slot_offset;
|
||||
|
||||
multi_adv_schedule_timeslot(adv_scheduler);
|
||||
return;
|
||||
}
|
||||
|
||||
void multi_adv_schedule_timer_callback(struct k_work *timer)
|
||||
{
|
||||
multi_adv_schedule_timer_handle();
|
||||
return;
|
||||
}
|
||||
|
||||
int multi_adv_schedule_timer_start(int timeout)
|
||||
{
|
||||
struct multi_adv_scheduler *adv_scheduler = &g_multi_adv_scheduler;
|
||||
multi_adv_schedule_timer_stop();
|
||||
|
||||
k_delayed_work_submit(&g_multi_adv_timer, timeout);
|
||||
adv_scheduler->schedule_timer_active = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int multi_adv_schedule_timer_stop(void)
|
||||
{
|
||||
struct multi_adv_scheduler *adv_scheduler = &g_multi_adv_scheduler;
|
||||
|
||||
if (adv_scheduler->schedule_timer_active) {
|
||||
k_delayed_work_cancel(&g_multi_adv_timer);
|
||||
adv_scheduler->schedule_timer_active = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void multi_adv_schedule_timeslot(struct multi_adv_scheduler *adv_scheduler)
|
||||
{
|
||||
int i, inst_num;
|
||||
int inst_clk, inst_off, match, insts = 0, next_slot, min_next_slot;
|
||||
struct multi_adv_instant *adv_instant;
|
||||
uint16_t inst_interval[MAX_MULTI_ADV_INSTANT];
|
||||
uint16_t inst_offset[MAX_MULTI_ADV_INSTANT];
|
||||
uint8_t inst_order[MAX_MULTI_ADV_INSTANT];
|
||||
uint8_t match_order[MAX_MULTI_ADV_INSTANT];
|
||||
|
||||
inst_num = 0;
|
||||
for (i = 0; i < MAX_MULTI_ADV_INSTANT; i++) {
|
||||
adv_instant = multi_adv_find_instant_by_order(i);
|
||||
if (adv_instant) {
|
||||
inst_interval[inst_num] = adv_instant->instant_interval;
|
||||
inst_offset[inst_num] = adv_instant->instant_offset;
|
||||
inst_order[inst_num] = i;
|
||||
inst_num++;
|
||||
}
|
||||
}
|
||||
|
||||
inst_clk = adv_scheduler->slot_clock;
|
||||
inst_off = adv_scheduler->slot_offset;
|
||||
match = 0;
|
||||
for (i = 0; i < inst_num; i++) {
|
||||
if ((inst_clk % inst_interval[i]) == inst_offset[i]) {
|
||||
match_order[match] = i;
|
||||
match++;
|
||||
}
|
||||
}
|
||||
|
||||
// BT_DBG("multi_adv_schedule_timeslot, num = %d, match = %d", inst_num, match);
|
||||
if (match) {
|
||||
int offset_per_instant, diff;
|
||||
offset_per_instant = TIME_PRIOD_MS / match;
|
||||
diff = inst_off - (inst_off + offset_per_instant / 2) / offset_per_instant * offset_per_instant; //TODO may be error
|
||||
|
||||
/* means this is the time to start */
|
||||
if (diff <= 2) {
|
||||
insts = (inst_off + offset_per_instant / 2) / offset_per_instant;
|
||||
|
||||
/* start instant */
|
||||
adv_instant = multi_adv_find_instant_by_order(inst_order[match_order[insts]]);
|
||||
if (adv_instant)
|
||||
multi_adv_start_adv_instant(adv_instant);
|
||||
}
|
||||
|
||||
/* next instant in the same slot */
|
||||
if (match - insts > 1) {
|
||||
adv_scheduler->next_slot_offset = adv_scheduler->slot_offset + offset_per_instant;
|
||||
adv_scheduler->next_slot_clock = adv_scheduler->slot_clock;
|
||||
|
||||
if ((adv_scheduler->next_slot_offset >= (TIME_PRIOD_MS - 2)) && (adv_scheduler->slot_offset <= (TIME_PRIOD_MS + 2))) {
|
||||
adv_scheduler->next_slot_clock++;
|
||||
adv_scheduler->next_slot_offset = 0;
|
||||
}
|
||||
multi_adv_schedule_timer_start(offset_per_instant);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* next instant not in the same slot */
|
||||
min_next_slot = 0x7fffffff;
|
||||
for (i = 0; i < inst_num; i++) {
|
||||
if (inst_clk - inst_offset[i] < 0) {
|
||||
match = 0;
|
||||
} else {
|
||||
match = (inst_clk - inst_offset[i]) / inst_interval[i] + 1;
|
||||
}
|
||||
next_slot = match * inst_interval[i] + inst_offset[i];
|
||||
if (next_slot < min_next_slot) {
|
||||
min_next_slot = next_slot;
|
||||
}
|
||||
}
|
||||
adv_scheduler->next_slot_offset = 0;
|
||||
adv_scheduler->next_slot_clock = min_next_slot;
|
||||
|
||||
next_slot = (adv_scheduler->next_slot_clock - adv_scheduler->slot_clock) * TIME_PRIOD_MS + (adv_scheduler->next_slot_offset - adv_scheduler->slot_offset);
|
||||
multi_adv_schedule_timer_start(next_slot);
|
||||
return;
|
||||
}
|
||||
|
||||
void multi_adv_schedule_stop(void)
|
||||
{
|
||||
struct multi_adv_scheduler *adv_scheduler = &g_multi_adv_scheduler;
|
||||
|
||||
multi_adv_schedule_timer_stop();
|
||||
adv_scheduler->schedule_state = SCHEDULE_STOP;
|
||||
}
|
||||
|
||||
void multi_adv_schedule_start(void)
|
||||
{
|
||||
struct multi_adv_scheduler *adv_scheduler = &g_multi_adv_scheduler;
|
||||
|
||||
/* get all instant and calculate ticks and */
|
||||
if (adv_scheduler->schedule_state == SCHEDULE_START) {
|
||||
multi_adv_schedule_stop();
|
||||
}
|
||||
|
||||
/* reinit scheduler */
|
||||
adv_scheduler->slot_clock = 0;
|
||||
adv_scheduler->slot_offset = 0;
|
||||
adv_scheduler->schedule_state = SCHEDULE_START;
|
||||
multi_adv_schedule_timeslot(adv_scheduler);
|
||||
}
|
||||
|
||||
void multi_adv_new_schedule(void)
|
||||
{
|
||||
int i;
|
||||
struct multi_adv_instant *adv_instant, *high_duty_instant;
|
||||
struct multi_adv_scheduler *adv_scheduler = &g_multi_adv_scheduler;
|
||||
uint16_t inst_offset[MAX_MULTI_ADV_INSTANT];
|
||||
uint16_t inst_interval[MAX_MULTI_ADV_INSTANT];
|
||||
uint8_t inst_order[MAX_MULTI_ADV_INSTANT];
|
||||
int inst_num = 0;
|
||||
|
||||
if (adv_scheduler->schedule_state == SCHEDULE_START) {
|
||||
multi_adv_schedule_stop();
|
||||
}
|
||||
/* get all instant and calculate ticks and */
|
||||
high_duty_instant = 0;
|
||||
for (i = 0; i < MAX_MULTI_ADV_INSTANT; i++) {
|
||||
adv_instant = multi_adv_find_instant_by_order(i);
|
||||
if (adv_instant) {
|
||||
/* if high duty cycle adv found */
|
||||
if (adv_instant->param.interval_min < HIGH_DUTY_CYCLE_INTERVAL) {
|
||||
high_duty_instant = adv_instant;
|
||||
break;
|
||||
}
|
||||
|
||||
inst_interval[inst_num] = change_to_tick(adv_instant->param.interval_min, adv_instant->param.interval_max);
|
||||
inst_order[inst_num] = i;
|
||||
inst_num++;
|
||||
}
|
||||
}
|
||||
|
||||
if (high_duty_instant) {
|
||||
//BT_WARN("High Duty Cycle Instants, id = %d, interval = %d\n", adv_instant->instant_id, adv_instant->param.interval_min);
|
||||
multi_adv_start_adv_instant(adv_instant);
|
||||
return;
|
||||
}
|
||||
|
||||
/* instant number equal 0 and 1 */
|
||||
if (inst_num == 0) {
|
||||
bt_le_adv_stop();
|
||||
return;
|
||||
}
|
||||
if (inst_num == 1) {
|
||||
adv_instant = multi_adv_find_instant_by_order(inst_order[0]);
|
||||
if (!adv_instant)
|
||||
return;
|
||||
multi_adv_start_adv_instant(adv_instant);
|
||||
return;
|
||||
}
|
||||
|
||||
/* reorder by inst_interval */
|
||||
multi_adv_reorder(inst_num, inst_interval, inst_order);
|
||||
|
||||
/* calcuate schedule table */
|
||||
multi_adv_schedule_table(inst_num, inst_interval, inst_offset);
|
||||
|
||||
/* set interval and offset to instant */
|
||||
for (i = 0; i < inst_num; i++) {
|
||||
adv_instant = multi_adv_find_instant_by_order(inst_order[i]);
|
||||
if (!adv_instant) {
|
||||
continue;
|
||||
}
|
||||
adv_instant->instant_interval = inst_interval[i];
|
||||
adv_instant->instant_offset = inst_offset[i];
|
||||
|
||||
//BT_WARN("adv_instant id = %d, interval = %d, offset = %d\n", adv_instant->instant_id, adv_instant->instant_interval, adv_instant->instant_offset);
|
||||
}
|
||||
|
||||
multi_adv_schedule_start();
|
||||
}
|
||||
|
||||
int bt_le_multi_adv_thread_init(void)
|
||||
{
|
||||
/* timer and event init */
|
||||
k_delayed_work_init(&g_multi_adv_timer, multi_adv_schedule_timer_callback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_le_multi_adv_start(const struct bt_le_adv_param *param,
|
||||
const struct bt_data *ad, size_t ad_len,
|
||||
const struct bt_data *sd, size_t sd_len, int *instant_id)
|
||||
{
|
||||
int instant_num;
|
||||
struct multi_adv_instant *adv_instant;
|
||||
|
||||
instant_num = multi_adv_get_instant_num();
|
||||
if (instant_num >= MAX_MULTI_ADV_INSTANT)
|
||||
return -1;
|
||||
|
||||
adv_instant = multi_adv_alloc_unused_instant();
|
||||
if (adv_instant == 0)
|
||||
return -1;
|
||||
|
||||
memcpy(&(adv_instant->param), param, sizeof(struct bt_le_adv_param));
|
||||
|
||||
adv_instant->ad_len = multi_adv_set_ad_data(adv_instant->ad, ad, ad_len);
|
||||
adv_instant->sd_len = multi_adv_set_ad_data(adv_instant->sd, sd, sd_len);
|
||||
|
||||
multi_adv_new_schedule();
|
||||
|
||||
*instant_id = adv_instant->instant_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_le_multi_adv_stop(int instant_id)
|
||||
{
|
||||
if (multi_adv_find_instant_by_id(instant_id) == 0)
|
||||
return -1;
|
||||
|
||||
//BT_WARN("%s id[%d]\n", __func__, instant_id);
|
||||
multi_adv_delete_instant_by_id(instant_id);
|
||||
multi_adv_new_schedule();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool bt_le_multi_adv_id_is_vaild(int instant_id)
|
||||
{
|
||||
int i;
|
||||
struct multi_adv_instant *inst = &(g_multi_adv_list[0]);
|
||||
|
||||
for (i = 0; i < MAX_MULTI_ADV_INSTANT; i++) {
|
||||
if ((inst[i].inuse_flag) && (instant_id == (inst[i].instant_id))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* xx
|
||||
*/
|
||||
|
||||
#ifndef _MULTI_ADV_H_
|
||||
#define _MULTI_ADV_H_
|
||||
|
||||
#define MAX_MULTI_ADV_INSTANT 4
|
||||
#define MAX_AD_DATA_LEN 31
|
||||
|
||||
#define TIME_PRIOD_MS (10 * (MAX_MULTI_ADV_INSTANT - 2))
|
||||
#define SLOT_PER_PERIOD (TIME_PRIOD_MS * 8 / 5)
|
||||
|
||||
#define MAX_MIN_MULTI (30000 / TIME_PRIOD_MS)
|
||||
|
||||
#define HIGH_DUTY_CYCLE_INTERVAL (20 * 8 / 5)
|
||||
|
||||
struct multi_adv_instant {
|
||||
uint8_t inuse_flag;
|
||||
|
||||
/* for parameters */
|
||||
struct bt_le_adv_param param;
|
||||
uint8_t ad[MAX_AD_DATA_LEN];
|
||||
uint8_t ad_len;
|
||||
uint8_t sd[MAX_AD_DATA_LEN];
|
||||
uint8_t sd_len;
|
||||
|
||||
/* own address maybe used */
|
||||
bt_addr_t own_addr;
|
||||
uint8_t own_addr_valid;
|
||||
|
||||
/* for schedule */
|
||||
int instant_id;
|
||||
int instant_interval;
|
||||
int instant_offset;
|
||||
uint32_t clock;
|
||||
uint32_t clock_instant_offset;
|
||||
uint32_t clock_instant_total;
|
||||
uint32_t next_wakeup_time;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SCHEDULE_IDLE,
|
||||
SCHEDULE_READY,
|
||||
SCHEDULE_START,
|
||||
SCHEDULE_STOP,
|
||||
} SCHEDULE_STATE;
|
||||
|
||||
struct multi_adv_scheduler {
|
||||
SCHEDULE_STATE schedule_state;
|
||||
uint8_t schedule_timer_active;
|
||||
uint32_t slot_clock;
|
||||
uint16_t slot_offset;
|
||||
uint16_t next_slot_offset;
|
||||
uint32_t next_slot_clock;
|
||||
};
|
||||
|
||||
int bt_le_multi_adv_thread_init(void);
|
||||
int bt_le_multi_adv_start(const struct bt_le_adv_param *param,
|
||||
const struct bt_data *ad, size_t ad_len,
|
||||
const struct bt_data *sd, size_t sd_len, int *instant_id);
|
||||
int bt_le_multi_adv_stop(int instant_id);
|
||||
|
||||
bool bt_le_multi_adv_id_is_vaild(int instant_id);
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user