[feat] add ble component

This commit is contained in:
jzlv 2021-06-04 17:46:09 +08:00
parent 28f6fa8c50
commit 91a930f878
203 changed files with 82743 additions and 0 deletions

View file

@ -0,0 +1,385 @@
/** @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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -0,0 +1,739 @@
/*
* Audio Video Distribution Protocol
*
* SPDX-License-Identifier: Apache-2.0
*
*/
#include <zephyr.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <atomic.h>
#include <byteorder.h>
#include <util.h>
#include <hci_host.h>
#include <bluetooth.h>
#include <l2cap.h>
#include <a2dp.h>
#include <avdtp.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_AVDTP)
#define LOG_MODULE_NAME bt_avdtp
#include "log.h"
#include "hci_core.h"
#include "conn_internal.h"
#include "l2cap_internal.h"
#include "avdtp_internal.h"
#include "a2dp-codec.h"
#define AVDTP_MSG_POISTION 0x00
#define AVDTP_PKT_POSITION 0x02
#define AVDTP_TID_POSITION 0x04
#define AVDTP_SIGID_MASK 0x3f
#define AVDTP_GET_TR_ID(hdr) ((hdr & 0xf0) >> AVDTP_TID_POSITION)
#define AVDTP_GET_MSG_TYPE(hdr) (hdr & 0x03)
#define AVDTP_GET_PKT_TYPE(hdr) ((hdr & 0x0c) >> AVDTP_PKT_POSITION)
#define AVDTP_GET_SIG_ID(s) (s & AVDTP_SIGID_MASK)
static struct bt_avdtp_event_cb *event_cb;
static struct bt_avdtp_seid_lsep *lseps;
extern struct bt_a2dp_codec_sbc_params sbc_info;
#define AVDTP_CHAN(_ch) CONTAINER_OF(_ch, struct bt_avdtp, br_chan.chan)
#define AVDTP_KWORK(_work) CONTAINER_OF(_work, struct bt_avdtp_req,\
timeout_work)
#define AVDTP_TIMEOUT K_SECONDS(6)
static void handle_avdtp_discover_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type);
static void handle_avdtp_get_cap_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type);
static void handle_avdtp_set_conf_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type);
static void handle_avdtp_get_conf_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type);
static void handle_avdtp_reconf_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type);
static void handle_avdtp_open_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type);
static void handle_avdtp_start_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type);
static void handle_avdtp_close_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type);
static void handle_avdtp_suspend_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type);
static void handle_avdtp_abort_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type);
static void handle_avdtp_sec_ctrl_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type);
static void handle_avdtp_get_all_cap_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type);
static void handle_avdtp_dly_rpt_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type);
static const struct {
uint8_t sig_id;
void (*func)(struct bt_avdtp *session, struct net_buf *buf,
uint8_t msg_type);
} handler[] = {
{BT_AVDTP_DISCOVER, handle_avdtp_discover_cmd},
{BT_AVDTP_GET_CAPABILITIES, handle_avdtp_get_cap_cmd},
{BT_AVDTP_SET_CONFIGURATION, handle_avdtp_set_conf_cmd},
{BT_AVDTP_GET_CONFIGURATION, handle_avdtp_get_conf_cmd},
{BT_AVDTP_RECONFIGURE, handle_avdtp_reconf_cmd},
{BT_AVDTP_OPEN, handle_avdtp_open_cmd},
{BT_AVDTP_START, handle_avdtp_start_cmd},
{BT_AVDTP_CLOSE, handle_avdtp_close_cmd},
{BT_AVDTP_SUSPEND, handle_avdtp_suspend_cmd},
{BT_AVDTP_ABORT, handle_avdtp_abort_cmd},
{BT_AVDTP_SECURITY_CONTROL, handle_avdtp_sec_ctrl_cmd},
{BT_AVDTP_GET_ALL_CAPABILITIES, handle_avdtp_get_all_cap_cmd},
{BT_AVDTP_DELAYREPORT, handle_avdtp_dly_rpt_cmd},
};
static int avdtp_send(struct bt_avdtp *session,
struct net_buf *buf, struct bt_avdtp_req *req)
{
int result;
struct bt_avdtp_single_sig_hdr *hdr;
hdr = (struct bt_avdtp_single_sig_hdr *)buf->data;
result = bt_l2cap_chan_send(&session->br_chan.chan, buf);
if (result < 0) {
BT_ERR("Error:L2CAP send fail - result = %d", result);
return result;
}
/*Save the sent request*/
req->sig = AVDTP_GET_SIG_ID(hdr->signal_id);
req->tid = AVDTP_GET_TR_ID(hdr->hdr);
BT_DBG("sig 0x%02X, tid 0x%02X", req->sig, req->tid);
session->req = req;
/* Start timeout work */
k_delayed_work_submit(&session->req->timeout_work, AVDTP_TIMEOUT);
return result;
}
static struct net_buf *avdtp_create_pdu(uint8_t msg_type,
uint8_t pkt_type,
uint8_t sig_id)
{
struct net_buf *buf;
static uint8_t tid;
struct bt_avdtp_single_sig_hdr *hdr;
BT_DBG("");
buf = bt_l2cap_create_pdu(NULL, 0);
hdr = net_buf_add(buf, sizeof(*hdr));
hdr->hdr = (msg_type | pkt_type << AVDTP_PKT_POSITION |
tid++ << AVDTP_TID_POSITION);
tid %= 16; /* Loop for 16*/
hdr->signal_id = sig_id & AVDTP_SIGID_MASK;
BT_DBG("hdr = 0x%02X, Signal_ID = 0x%02X", hdr->hdr, hdr->signal_id);
return buf;
}
/* Timeout handler */
static void avdtp_timeout(struct k_work *work)
{
BT_DBG("Failed Signal_id = %d", (AVDTP_KWORK(work))->sig);
/* Gracefully Disconnect the Signalling and streaming L2cap chann*/
}
/**
* @brief avdtp_parsing_capability : parsing avdtp capability content
*/
static int avdtp_parsing_capability(struct net_buf *buf)
{
BT_DBG(" ");
while (buf->len)
{
uint8_t svc_cat = net_buf_pull_u8(buf);
uint8_t cat_len = net_buf_pull_u8(buf);;
switch (svc_cat)
{
case BT_AVDTP_SERVICE_CAT_MEDIA_TRANSPORT:
break;
case BT_AVDTP_SERVICE_CAT_REPORTING:
break;
case BT_AVDTP_SERVICE_CAT_RECOVERY:
break;
case BT_AVDTP_SERVICE_CAT_CONTENT_PROTECTION:
break;
case BT_AVDTP_SERVICE_CAT_HDR_COMPRESSION:
break;
case BT_AVDTP_SERVICE_CAT_MULTIPLEXING:
break;
case BT_AVDTP_SERVICE_CAT_MEDIA_CODEC:
break;
case BT_AVDTP_SERVICE_CAT_DELAYREPORTING:
break;
default:
break;
}
}
return 0;
}
static void handle_avdtp_discover_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type)
{
BT_DBG(" ");
if(!session)
{
BT_DBG("Error: Session not valid");
return;
}
struct net_buf *rsp_buf;
rsp_buf = avdtp_create_pdu(BT_AVDTP_ACCEPT, BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_DISCOVER);
if (!rsp_buf) {
BT_ERR("Error: No Buff available");
return;
}
struct bt_avdtp_seid_lsep *disc_sep = lseps;
uint8_t acp_endpoint[2];
while(disc_sep)
{
acp_endpoint[0] = disc_sep->sep.id << 2 | disc_sep->sep.inuse << 1 |disc_sep->sep.rfa0;
acp_endpoint[1] = disc_sep->sep.media_type << 4 | disc_sep->sep.tsep << 3 |disc_sep->sep.rfa1;
memcpy(rsp_buf->data + rsp_buf->len, acp_endpoint, 2);
rsp_buf->len += 2;
disc_sep = disc_sep->next;
}
#if 0
BT_DBG("rsp_buf len: %d \n", rsp_buf->len);
for(int i = 0; i < rsp_buf->len; i++)
{
BT_WARN("0x%02x, ", rsp_buf->data[i]);
}
BT_WARN("\n");
#endif
int result = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf);
if (result < 0)
{
BT_ERR("Error: BT L2CAP send fail - result = %d", result);
return;
}
}
static void handle_avdtp_get_cap_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type)
{
BT_DBG(" ");
if(!session)
{
BT_DBG("Error: Session not valid");
return;
}
struct net_buf *rsp_buf;
rsp_buf = avdtp_create_pdu(BT_AVDTP_ACCEPT, BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_GET_CAPABILITIES);
if (!rsp_buf) {
BT_ERR("Error: No Buff available");
return;
}
uint8_t svc_cat_1[2];
svc_cat_1[0] = BT_AVDTP_SERVICE_CAT_MEDIA_TRANSPORT;
svc_cat_1[1] = 0;
memcpy(rsp_buf->data + rsp_buf->len, svc_cat_1, 2);
rsp_buf->len += 2;
uint8_t svc_cat_2[8];
svc_cat_2[0] = BT_AVDTP_SERVICE_CAT_MEDIA_CODEC;
svc_cat_2[1] = 6;
svc_cat_2[2] = BT_A2DP_AUDIO;
svc_cat_2[3] = BT_A2DP_CODEC_TYPE_SBC;
svc_cat_2[4] = sbc_info.config[0];
svc_cat_2[5] = sbc_info.config[1];
svc_cat_2[6] = sbc_info.min_bitpool;
svc_cat_2[7] = sbc_info.max_bitpool;
memcpy(rsp_buf->data + rsp_buf->len, svc_cat_2, 8);
rsp_buf->len += 8;
uint8_t svc_cat_3[4];
svc_cat_3[0] = BT_AVDTP_SERVICE_CAT_CONTENT_PROTECTION;
svc_cat_3[1] = 2;
svc_cat_3[2] = BT_AVDTP_CONTENT_PROTECTION_LSB_SCMS_T;
svc_cat_3[3] = BT_AVDTP_CONTENT_PROTECTION_MSB;
memcpy(rsp_buf->data + rsp_buf->len, svc_cat_3, 4);
rsp_buf->len += 4;
#if 0
BT_DBG("rsp_buf len: %d \n", rsp_buf->len);
for(int i = 0; i < rsp_buf->len; i++)
{
BT_WARN("0x%02x, ", rsp_buf->data[i]);
}
BT_WARN("\n");
#endif
int result = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf);
if (result < 0)
{
BT_ERR("Error: BT L2CAP send fail - result = %d", result);
return;
}
}
static void handle_avdtp_set_conf_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type)
{
BT_DBG(" ");
if(!session)
{
BT_DBG("Error: Session not valid");
return;
}
uint8_t acp_seid = net_buf_pull_u8(buf) >> 2;
uint8_t int_seid = net_buf_pull_u8(buf) >> 2;
int res_pars = avdtp_parsing_capability(buf);
struct net_buf *rsp_buf;
rsp_buf = avdtp_create_pdu(BT_AVDTP_ACCEPT, BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_SET_CONFIGURATION);
if (!rsp_buf) {
BT_ERR("Error: No Buff available");
return;
}
int result = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf);
if (result < 0)
{
BT_ERR("Error: BT L2CAP send fail - result = %d", result);
return;
}
}
static void handle_avdtp_get_conf_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type)
{
BT_DBG(" ");
}
static void handle_avdtp_reconf_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type)
{
BT_DBG(" ");
}
static void handle_avdtp_open_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type)
{
BT_DBG(" ");
if(!session)
{
BT_DBG("Error: Session not valid");
return;
}
struct net_buf *rsp_buf;
rsp_buf = avdtp_create_pdu(BT_AVDTP_ACCEPT, BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_OPEN);
if (!rsp_buf) {
BT_ERR("Error: No Buff available");
return;
}
int result = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf);
if (result < 0)
{
BT_ERR("Error: BT L2CAP send fail - result = %d", result);
return;
}
}
static void handle_avdtp_start_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type)
{
BT_DBG(" ");
if(!session)
{
BT_DBG("Error: Session not valid");
return;
}
struct net_buf *rsp_buf;
rsp_buf = avdtp_create_pdu(BT_AVDTP_ACCEPT, BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_START);
if (!rsp_buf) {
BT_ERR("Error: No Buff available");
return;
}
int result = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf);
if (result < 0)
{
BT_ERR("Error: BT L2CAP send fail - result = %d", result);
return;
}
}
static void handle_avdtp_close_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type)
{
BT_DBG(" ");
if(!session)
{
BT_DBG("Error: Session not valid");
return;
}
struct net_buf *rsp_buf;
rsp_buf = avdtp_create_pdu(BT_AVDTP_ACCEPT, BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_CLOSE);
if (!rsp_buf) {
BT_ERR("Error: No Buff available");
return;
}
int result = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf);
if (result < 0)
{
BT_ERR("Error: BT L2CAP send fail - result = %d", result);
return;
}
}
static void handle_avdtp_suspend_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type)
{
BT_DBG(" ");
if(!session)
{
BT_DBG("Error: Session not valid");
return;
}
struct net_buf *rsp_buf;
rsp_buf = avdtp_create_pdu(BT_AVDTP_ACCEPT, BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_SUSPEND);
if (!rsp_buf) {
BT_ERR("Error: No Buff available");
return;
}
int result = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf);
if (result < 0)
{
BT_ERR("Error: BT L2CAP send fail - result = %d", result);
return;
}
}
static void handle_avdtp_abort_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type)
{
BT_DBG(" ");
if(!session)
{
BT_DBG("Error: Session not valid");
return;
}
struct net_buf *rsp_buf;
rsp_buf = avdtp_create_pdu(BT_AVDTP_ACCEPT, BT_AVDTP_PACKET_TYPE_SINGLE, BT_AVDTP_ABORT);
if (!rsp_buf) {
BT_ERR("Error: No Buff available");
return;
}
int result = bt_l2cap_chan_send(&session->br_chan.chan, rsp_buf);
if (result < 0)
{
BT_ERR("Error: BT L2CAP send fail - result = %d", result);
return;
}
}
static void handle_avdtp_sec_ctrl_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type)
{
BT_DBG(" ");
}
static void handle_avdtp_get_all_cap_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type)
{
BT_DBG(" ");
}
static void handle_avdtp_dly_rpt_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type)
{
BT_DBG(" ");
}
/* L2CAP Interface callbacks */
void bt_avdtp_l2cap_connected(struct bt_l2cap_chan *chan)
{
struct bt_avdtp *session;
if (!chan) {
BT_ERR("Invalid AVDTP chan");
return;
}
session = AVDTP_CHAN(chan);
BT_DBG("chan %p session %p", chan, session);
/* Init the timer */
k_delayed_work_init(&session->req->timeout_work, avdtp_timeout);
}
void bt_avdtp_l2cap_disconnected(struct bt_l2cap_chan *chan)
{
struct bt_avdtp *session = AVDTP_CHAN(chan);
BT_DBG("chan %p session %p", chan, session);
session->br_chan.chan.conn = NULL;
/* Clear the Pending req if set*/
}
void bt_avdtp_l2cap_encrypt_changed(struct bt_l2cap_chan *chan, uint8_t status)
{
BT_DBG("");
}
int bt_avdtp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
{
struct bt_avdtp_single_sig_hdr *hdr;
struct bt_avdtp *session = AVDTP_CHAN(chan);
uint8_t i, msgtype, sigid, tid;
if (buf->len < sizeof(*hdr)) {
BT_ERR("Recvd Wrong AVDTP Header");
return 0;
}
hdr = net_buf_pull_mem(buf, sizeof(*hdr));
msgtype = AVDTP_GET_MSG_TYPE(hdr->hdr);
sigid = AVDTP_GET_SIG_ID(hdr->signal_id);
tid = AVDTP_GET_TR_ID(hdr->hdr);
BT_DBG("msg_type[0x%02x] sig_id[0x%02x] tid[0x%02x]",
msgtype, sigid, tid);
#if 0
BT_DBG("avdtp payload len: %d \n", buf->len);
for(int i = 0; i < buf->len; i++)
{
BT_WARN("0x%02x, ", buf->data[i]);
}
BT_WARN("\n");
#endif
/* validate if there is an outstanding resp expected*/
if (msgtype != BT_AVDTP_CMD) {
if (session->req == NULL) {
BT_DBG("Unexpected peer response");
return 0;
}
if (session->req->sig != sigid ||
session->req->tid != tid) {
BT_DBG("Peer mismatch resp, expected sig[0x%02x]"
"tid[0x%02x]", session->req->sig,
session->req->tid);
return 0;
}
}
for (i = 0U; i < ARRAY_SIZE(handler); i++) {
if (sigid == handler[i].sig_id) {
handler[i].func(session, buf, msgtype);
return 0;
}
}
return 0;
}
int bt_avdtp_l2cap_media_stream_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
{
#if 0
BT_DBG("avdtp payload len: %d \n", buf->len);
for(int i = 0; i < buf->len; i++)
{
BT_WARN("0x%02x, ", buf->data[i]);
}
BT_WARN("\n");
#endif
int res = a2dp_sbc_decode_process(buf->data, buf->len);
if(res)
{
BT_DBG("decode fail, error: %d \n", res);
}
return 0;
}
/*A2DP Layer interface */
int bt_avdtp_connect(struct bt_conn *conn, struct bt_avdtp *session)
{
static const struct bt_l2cap_chan_ops ops = {
.connected = bt_avdtp_l2cap_connected,
.disconnected = bt_avdtp_l2cap_disconnected,
.encrypt_change = bt_avdtp_l2cap_encrypt_changed,
.recv = bt_avdtp_l2cap_recv
};
if (!session) {
return -EINVAL;
}
session->br_chan.chan.ops = &ops;
session->br_chan.chan.required_sec_level = BT_SECURITY_L2;
return bt_l2cap_chan_connect(conn, &session->br_chan.chan,
BT_L2CAP_PSM_AVDTP);
}
int bt_avdtp_disconnect(struct bt_avdtp *session)
{
if (!session) {
return -EINVAL;
}
BT_DBG("session %p", session);
return bt_l2cap_chan_disconnect(&session->br_chan.chan);
}
int bt_avdtp_l2cap_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
{
struct bt_avdtp *session = NULL;
int result;
static const struct bt_l2cap_chan_ops ops = {
.connected = bt_avdtp_l2cap_connected,
.disconnected = bt_avdtp_l2cap_disconnected,
.recv = bt_avdtp_l2cap_recv,
};
static const struct bt_l2cap_chan_ops media_ops = {
.connected = bt_avdtp_l2cap_connected,
.disconnected = bt_avdtp_l2cap_disconnected,
.recv = bt_avdtp_l2cap_media_stream_recv,
};
BT_DBG("conn %p", conn);
/* Get the AVDTP session from upper layer */
result = event_cb->accept(conn, &session);
if (result < 0) {
return result;
}
if(!session->br_chan.chan.conn)
{
BT_DBG("create l2cap_br signal stream, session %p", session);
session->br_chan.chan.ops = &ops;
session->br_chan.rx.mtu = BT_AVDTP_MAX_MTU;
*chan = &session->br_chan.chan;
}
else
{
BT_DBG("create l2cap_br AV stream, session %p", session);
session->streams->chan.chan.ops = &media_ops;
session->streams->chan.rx.mtu = BT_AVDTP_MAX_MTU;
*chan = &session->streams->chan.chan;
}
return 0;
}
/* Application will register its callback */
int bt_avdtp_register(struct bt_avdtp_event_cb *cb)
{
BT_DBG("");
if (event_cb) {
return -EALREADY;
}
event_cb = cb;
return 0;
}
int bt_avdtp_register_sep(uint8_t media_type, uint8_t role,
struct bt_avdtp_seid_lsep *lsep)
{
BT_DBG("");
static uint8_t bt_avdtp_seid = BT_AVDTP_MIN_SEID;
if (!lsep) {
return -EIO;
}
if (bt_avdtp_seid == BT_AVDTP_MAX_SEID) {
return -EIO;
}
lsep->sep.id = bt_avdtp_seid++;
lsep->sep.inuse = 0U;
lsep->sep.media_type = media_type;
lsep->sep.tsep = role;
lsep->next = lseps;
lseps = lsep;
return 0;
}
/* init function */
int bt_avdtp_init(void)
{
int err;
static struct bt_l2cap_server avdtp_l2cap = {
.psm = BT_L2CAP_PSM_AVDTP,
.sec_level = BT_SECURITY_L2,
.accept = bt_avdtp_l2cap_accept,
};
BT_DBG("");
/* Register AVDTP PSM with L2CAP */
err = bt_l2cap_br_server_register(&avdtp_l2cap);
if (err < 0) {
BT_ERR("AVDTP L2CAP Registration failed %d", err);
}
return err;
}
/* AVDTP Discover Request */
int bt_avdtp_discover(struct bt_avdtp *session,
struct bt_avdtp_discover_params *param)
{
struct net_buf *buf;
BT_DBG("");
if (!param || !session) {
BT_DBG("Error: Callback/Session not valid");
return -EINVAL;
}
buf = avdtp_create_pdu(BT_AVDTP_CMD,
BT_AVDTP_PACKET_TYPE_SINGLE,
BT_AVDTP_DISCOVER);
if (!buf) {
BT_ERR("Error: No Buff available");
return -ENOMEM;
}
/* Body of the message */
return avdtp_send(session, buf, &param->req);
}

View file

@ -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);

View file

@ -0,0 +1,372 @@
#include "ble_lib_api.h"
#include "bluetooth.h"
#include "conn.h"
#include "hci_core.h"
#include "hci_driver.h"
#include "byteorder.h"
#include "log.h"
#include "errno.h"
struct blhast_le_adv_data{
u8_t ad[31];
size_t ad_len;
};
static struct bt_le_scan_param blhast_le_scan_param;
static struct bt_le_adv_param blhast_le_adv_param;
static struct blhast_le_adv_data blhast_le_ad;
static struct blhast_le_adv_data blhast_le_sd;
static bt_le_scan_cb_t *blhast_le_scan_cb;
static void blhast_ble_scan_assist_cb(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb);
static void blhast_ble_adv_assist_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);
static struct blhast_cb assist_cb = {
.le_scan_cb = blhast_ble_scan_assist_cb,
.le_adv_cb = blhast_ble_adv_assist_cb,
};
extern struct bt_dev bt_dev;
static void blhast_ble_scan_assist_cb(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb)
{
memcpy(&blhast_le_scan_param, param, sizeof(struct bt_le_scan_param));
blhast_le_scan_cb = cb;
}
static void blhast_ble_get_ad(const struct bt_data *ad, size_t ad_len, uint8_t *output)
{
int i;
uint8_t data_len = 0;
for (i = 0; i < ad_len; i++) {
*(output + data_len) = ad[i].type;
data_len++;
*(output + data_len) = ad[i].data_len;
data_len++;
memcpy(output + data_len, ad[i].data, ad[i].data_len);
data_len += ad[i].data_len;
}
}
static void blhast_ble_construct_ad(struct blhast_le_adv_data *adv_data, struct bt_data *output)
{
int i;
size_t ad_len = adv_data->ad_len;
u8_t *p_ad = adv_data->ad;
for(i = 0; i < ad_len; i++){
memcpy(&output[i], p_ad, 2);//type, data_len
p_ad += 2;
output[i].data = (const u8_t *)p_ad;
p_ad += output[i].data_len;
}
}
static void blhast_ble_adv_assist_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)
{
memcpy(&blhast_le_adv_param, param, sizeof(struct bt_le_adv_param));
if(ad){
blhast_le_ad.ad_len = ad_len;
memset(blhast_le_ad.ad, 0, sizeof(blhast_le_ad.ad));
blhast_ble_get_ad(ad, ad_len, blhast_le_ad.ad);
}
if(sd){
blhast_le_sd.ad_len = sd_len;
memset(blhast_le_sd.ad, 0, sizeof(blhast_le_sd.ad));
blhast_ble_get_ad(sd, sd_len, blhast_le_sd.ad);
}
}
static int blhast_common_reset(void)
{
struct net_buf *rsp;
int err;
if (!(bt_dev.drv->quirks & BT_QUIRK_NO_RESET)) {
/* Send HCI_RESET */
err = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, &rsp);
if (err) {
return err;
}
bt_hci_reset_complete(rsp);
net_buf_unref(rsp);
}
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
err = bt_set_flow_control();
if (err) {
return err;
}
#endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */
return 0;
}
static int blhast_ble_reset(void)
{
struct bt_hci_cp_write_le_host_supp *cp_le;
struct net_buf *buf, *rsp;
int err;
if (!BT_FEAT_LE(bt_dev.features)) {
BT_ERR("Non-LE capable controller detected!");
return -ENODEV;
}
if (BT_FEAT_BREDR(bt_dev.features)) {
buf = bt_hci_cmd_create(BT_HCI_OP_LE_WRITE_LE_HOST_SUPP,
sizeof(*cp_le));
if (!buf) {
return -ENOBUFS;
}
cp_le = net_buf_add(buf, sizeof(*cp_le));
/* Explicitly enable LE for dual-mode controllers */
cp_le->le = 0x01;
cp_le->simul = 0x00;
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_WRITE_LE_HOST_SUPP, buf,
NULL);
if (err) {
return err;
}
}
if (IS_ENABLED(CONFIG_BT_CONN) &&
IS_ENABLED(CONFIG_BT_DATA_LEN_UPDATE) &&
BT_FEAT_LE_DLE(bt_dev.le.features)) {
struct bt_hci_cp_le_write_default_data_len *cp;
struct bt_hci_rp_le_read_max_data_len *rp;
u16_t tx_octets, tx_time;
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_MAX_DATA_LEN, NULL,
&rsp);
if (err) {
return err;
}
rp = (void *)rsp->data;
tx_octets = sys_le16_to_cpu(rp->max_tx_octets);
tx_time = sys_le16_to_cpu(rp->max_tx_time);
net_buf_unref(rsp);
buf = bt_hci_cmd_create(BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN,
sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}
cp = net_buf_add(buf, sizeof(*cp));
cp->max_tx_octets = sys_cpu_to_le16(tx_octets);
cp->max_tx_time = sys_cpu_to_le16(tx_time);
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN,
buf, NULL);
if (err) {
return err;
}
}
return bt_le_set_event_mask();
}
#if defined(CONFIG_BT_BREDR)
static int blhast_br_reset(void)
{
struct net_buf *buf;
struct bt_hci_cp_write_ssp_mode *ssp_cp;
struct bt_hci_cp_write_inquiry_mode *inq_cp;
struct bt_hci_write_local_name *name_cp;
int err;
/* Set SSP mode */
buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_SSP_MODE, sizeof(*ssp_cp));
if (!buf) {
return -ENOBUFS;
}
ssp_cp = net_buf_add(buf, sizeof(*ssp_cp));
ssp_cp->mode = 0x01;
err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_SSP_MODE, buf, NULL);
if (err) {
return err;
}
/* Enable Inquiry results with RSSI or extended Inquiry */
buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_INQUIRY_MODE, sizeof(*inq_cp));
if (!buf) {
return -ENOBUFS;
}
inq_cp = net_buf_add(buf, sizeof(*inq_cp));
inq_cp->mode = 0x02;
err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_INQUIRY_MODE, buf, NULL);
if (err) {
return err;
}
/* Set local name */
buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_LOCAL_NAME, sizeof(*name_cp));
if (!buf) {
return -ENOBUFS;
}
name_cp = net_buf_add(buf, sizeof(*name_cp));
strncpy((char *)name_cp->local_name, CONFIG_BT_DEVICE_NAME,
sizeof(name_cp->local_name));
err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_LOCAL_NAME, buf, NULL);
if (err) {
return err;
}
/* Set page timeout*/
buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_PAGE_TIMEOUT, sizeof(u16_t));
if (!buf) {
return -ENOBUFS;
}
net_buf_add_le16(buf, CONFIG_BT_PAGE_TIMEOUT);
err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_PAGE_TIMEOUT, buf, NULL);
if (err) {
return err;
}
/* Enable BR/EDR SC if supported */
if (BT_FEAT_SC(bt_dev.features)) {
struct bt_hci_cp_write_sc_host_supp *sc_cp;
buf = bt_hci_cmd_create(BT_HCI_OP_WRITE_SC_HOST_SUPP,
sizeof(*sc_cp));
if (!buf) {
return -ENOBUFS;
}
sc_cp = net_buf_add(buf, sizeof(*sc_cp));
sc_cp->sc_support = 0x01;
err = bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_SC_HOST_SUPP, buf,
NULL);
if (err) {
return err;
}
}
return 0;
}
#endif
static int blhast_host_hci_reset(void)
{
int err;
ATOMIC_DEFINE(old_flags, BT_DEV_NUM_FLAGS);
memcpy(old_flags, bt_dev.flags, sizeof(old_flags));
err = blhast_common_reset();
if (err) {
return err;
}
err = blhast_ble_reset();
if (err) {
return err;
}
#if defined(CONFIG_BT_BREDR)
if (BT_FEAT_BREDR(bt_dev.features)) {
err = blhast_br_reset();
if (err) {
return err;
}
}
#endif
err = bt_set_event_mask();
if (err) {
return err;
}
memcpy(bt_dev.flags, old_flags, sizeof(old_flags));
return 0;
}
static void blhast_host_state_restore(void)
{
struct bt_data *ad = NULL;
struct bt_data *sd = NULL;
k_sem_give(&bt_dev.ncmd_sem);
net_buf_unref(bt_dev.sent_cmd);
bt_dev.sent_cmd = NULL;
blhast_host_hci_reset();
#if defined(CONFIG_BT_CONN)
bt_notify_disconnected();
#endif
atomic_set_bit(bt_dev.flags, BT_DEV_ASSIST_RUN);
#if defined(CONFIG_BT_OBSERVER)
if(atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN))
{
BT_WARN("Restore BLE scan\r\n");
atomic_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN);
atomic_clear_bit(bt_dev.flags, BT_DEV_SCANNING);
bt_le_scan_start((const struct bt_le_scan_param *)&blhast_le_scan_param, blhast_le_scan_cb);
}
#endif
if(atomic_test_and_clear_bit(bt_dev.flags, BT_DEV_ADVERTISING))
{
BT_WARN("Restore BLE advertising\r\n");
if(blhast_le_ad.ad_len > 0)
{
ad = k_malloc(sizeof(struct bt_data) * blhast_le_ad.ad_len);
blhast_ble_construct_ad(&blhast_le_ad, ad);
}
if(blhast_le_sd.ad_len > 0)
{
sd = k_malloc(sizeof(struct bt_data) * blhast_le_sd.ad_len);
blhast_ble_construct_ad(&blhast_le_sd, sd);
}
bt_le_adv_start((const struct bt_le_adv_param *)&blhast_le_adv_param, ad,
blhast_le_ad.ad_len, sd, blhast_le_sd.ad_len);
if(ad)
k_free(ad);
if(sd)
k_free(sd);
}
atomic_clear_bit(bt_dev.flags, BT_DEV_ASSIST_RUN);
}
void blhast_bt_reset(void)
{
ble_controller_reset();
blhast_host_state_restore();
}
void blhast_init(void)
{
memset(&blhast_le_ad, 0, sizeof(struct blhast_le_adv_data));
memset(&blhast_le_sd, 0, sizeof(struct blhast_le_adv_data));
bt_register_host_assist_cb(&assist_cb);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,344 @@
/** @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

View file

@ -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;
}

View file

@ -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);

View file

@ -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

View file

@ -0,0 +1,60 @@
/** @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

View file

@ -0,0 +1,287 @@
/* 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

View file

@ -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
}

View file

@ -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);

View file

@ -0,0 +1,929 @@
/* 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)
k_lifo_init(&hf_pool.free, CONFIG_BT_MAX_CONN + 1);
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;
}

View file

@ -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
};

File diff suppressed because it is too large Load diff

View file

@ -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);

View file

@ -0,0 +1,507 @@
/* 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 */

View file

@ -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);

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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);

View file

@ -0,0 +1,29 @@
/** @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

View file

@ -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

View file

@ -0,0 +1,519 @@
/*
* 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;
}

View file

@ -0,0 +1,68 @@
/*
* 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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,213 @@
/** @file
* @brief Internal APIs for Bluetooth RFCOMM handling.
*/
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <rfcomm.h>
typedef enum {
BT_RFCOMM_CFC_UNKNOWN,
BT_RFCOMM_CFC_NOT_SUPPORTED,
BT_RFCOMM_CFC_SUPPORTED,
} __packed bt_rfcomm_cfc_t;
/* RFCOMM signalling connection specific context */
struct bt_rfcomm_session {
/* L2CAP channel this context is associated with */
struct bt_l2cap_br_chan br_chan;
/* Response Timeout eXpired (RTX) timer */
struct k_delayed_work rtx_work;
/* Binary sem for aggregate fc */
struct k_sem fc;
struct bt_rfcomm_dlc *dlcs;
uint16_t mtu;
uint8_t state;
bt_rfcomm_role_t role;
bt_rfcomm_cfc_t cfc;
};
enum {
BT_RFCOMM_STATE_IDLE,
BT_RFCOMM_STATE_INIT,
BT_RFCOMM_STATE_SECURITY_PENDING,
BT_RFCOMM_STATE_CONNECTING,
BT_RFCOMM_STATE_CONNECTED,
BT_RFCOMM_STATE_CONFIG,
BT_RFCOMM_STATE_USER_DISCONNECT,
BT_RFCOMM_STATE_DISCONNECTING,
BT_RFCOMM_STATE_DISCONNECTED,
};
struct bt_rfcomm_hdr {
uint8_t address;
uint8_t control;
uint8_t length;
} __packed;
#define BT_RFCOMM_SABM 0x2f
#define BT_RFCOMM_UA 0x63
#define BT_RFCOMM_UIH 0xef
struct bt_rfcomm_msg_hdr {
uint8_t type;
uint8_t len;
} __packed;
#define BT_RFCOMM_PN 0x20
struct bt_rfcomm_pn {
uint8_t dlci;
uint8_t flow_ctrl;
uint8_t priority;
uint8_t ack_timer;
uint16_t mtu;
uint8_t max_retrans;
uint8_t credits;
} __packed;
#define BT_RFCOMM_MSC 0x38
struct bt_rfcomm_msc {
uint8_t dlci;
uint8_t v24_signal;
} __packed;
#define BT_RFCOMM_DISC 0x43
#define BT_RFCOMM_DM 0x0f
#define BT_RFCOMM_RLS 0x14
struct bt_rfcomm_rls {
uint8_t dlci;
uint8_t line_status;
} __packed;
#define BT_RFCOMM_RPN 0x24
struct bt_rfcomm_rpn {
uint8_t dlci;
uint8_t baud_rate;
uint8_t line_settings;
uint8_t flow_control;
uint8_t xon_char;
uint8_t xoff_char;
uint16_t param_mask;
} __packed;
#define BT_RFCOMM_TEST 0x08
#define BT_RFCOMM_NSC 0x04
#define BT_RFCOMM_FCON 0x28
#define BT_RFCOMM_FCOFF 0x18
/* Default RPN Settings */
#define BT_RFCOMM_RPN_BAUD_RATE_9600 0x03
#define BT_RFCOMM_RPN_DATA_BITS_8 0x03
#define BT_RFCOMM_RPN_STOP_BITS_1 0x00
#define BT_RFCOMM_RPN_PARITY_NONE 0x00
#define BT_RFCOMM_RPN_FLOW_NONE 0x00
#define BT_RFCOMM_RPN_XON_CHAR 0x11
#define BT_RFCOMM_RPN_XOFF_CHAR 0x13
/* Set 1 to all the param mask except reserved */
#define BT_RFCOMM_RPN_PARAM_MASK_ALL 0x3f7f
#define BT_RFCOMM_SET_LINE_SETTINGS(data, stop, parity) ((data & 0x3) | \
((stop & 0x1) << 2) | \
((parity & 0x7) << 3))
/* DV = 1 IC = 0 RTR = 1 RTC = 1 FC = 0 EXT = 0 */
#define BT_RFCOMM_DEFAULT_V24_SIG 0x8d
#define BT_RFCOMM_GET_FC(v24_signal) (((v24_signal) & 0x02) >> 1)
#define BT_RFCOMM_SIG_MIN_MTU 23
#define BT_RFCOMM_SIG_MAX_MTU 32767
#define BT_RFCOMM_CHECK_MTU(mtu) (!!((mtu) >= BT_RFCOMM_SIG_MIN_MTU && \
(mtu) <= BT_RFCOMM_SIG_MAX_MTU))
/* Helper to calculate needed outgoing buffer size.
* Length in rfcomm header can be two bytes depending on user data length.
* One byte in the tail should be reserved for FCS.
*/
#define BT_RFCOMM_BUF_SIZE(mtu) (BT_BUF_RESERVE + \
BT_HCI_ACL_HDR_SIZE + BT_L2CAP_HDR_SIZE + \
sizeof(struct bt_rfcomm_hdr) + 1 + (mtu) + \
BT_RFCOMM_FCS_SIZE)
#define BT_RFCOMM_GET_DLCI(addr) (((addr) & 0xfc) >> 2)
#define BT_RFCOMM_GET_FRAME_TYPE(ctrl) ((ctrl) & 0xef)
#define BT_RFCOMM_GET_MSG_TYPE(type) (((type) & 0xfc) >> 2)
#define BT_RFCOMM_GET_MSG_CR(type) (((type) & 0x02) >> 1)
#define BT_RFCOMM_GET_LEN(len) (((len) & 0xfe) >> 1)
#define BT_RFCOMM_GET_CHANNEL(dlci) ((dlci) >> 1)
#define BT_RFCOMM_GET_PF(ctrl) (((ctrl) & 0x10) >> 4)
#define BT_RFCOMM_SET_ADDR(dlci, cr) ((((dlci) & 0x3f) << 2) | \
((cr) << 1) | 0x01)
#define BT_RFCOMM_SET_CTRL(type, pf) (((type) & 0xef) | ((pf) << 4))
#define BT_RFCOMM_SET_LEN_8(len) (((len) << 1) | 1)
#define BT_RFCOMM_SET_LEN_16(len) ((len) << 1)
#define BT_RFCOMM_SET_MSG_TYPE(type, cr) (((type) << 2) | (cr << 1) | 0x01)
#define BT_RFCOMM_LEN_EXTENDED(len) (!((len) & 0x01))
/* For CR in UIH Packet header
* Initiating station have the C/R bit set to 1 and those sent by the
* responding station have the C/R bit set to 0
*/
#define BT_RFCOMM_UIH_CR(role) ((role) == BT_RFCOMM_ROLE_INITIATOR)
/* For CR in Non UIH Packet header
* Command
* Initiator --> Responder 1
* Responder --> Initiator 0
* Response
* Initiator --> Responder 0
* Responder --> Initiator 1
*/
#define BT_RFCOMM_CMD_CR(role) ((role) == BT_RFCOMM_ROLE_INITIATOR)
#define BT_RFCOMM_RESP_CR(role) ((role) == BT_RFCOMM_ROLE_ACCEPTOR)
/* For CR in MSG header
* If the C/R bit is set to 1 the message is a command,
* if it is set to 0 the message is a response.
*/
#define BT_RFCOMM_MSG_CMD_CR 1
#define BT_RFCOMM_MSG_RESP_CR 0
#define BT_RFCOMM_DLCI(role, channel) ((((channel) & 0x1f) << 1) | \
((role) == BT_RFCOMM_ROLE_ACCEPTOR))
/* Excluding ext bit */
#define BT_RFCOMM_MAX_LEN_8 127
/* Length can be 2 bytes depending on data size */
#define BT_RFCOMM_HDR_SIZE (sizeof(struct bt_rfcomm_hdr) + 1)
#define BT_RFCOMM_FCS_SIZE 1
#define BT_RFCOMM_FCS_LEN_UIH 2
#define BT_RFCOMM_FCS_LEN_NON_UIH 3
/* For non UIH packets
* The P bit set to 1 shall be used to solicit a response frame with the
* F bit set to 1 from the other station.
*/
#define BT_RFCOMM_PF_NON_UIH 1
/* For UIH packets
* Both stations set the P-bit to 0
* If credit based flow control is used, If P/F is 1 then one credit byte
* will be there after control in the frame else no credit byte.
*/
#define BT_RFCOMM_PF_UIH 0
#define BT_RFCOMM_PF_UIH_CREDIT 1
#define BT_RFCOMM_PF_UIH_NO_CREDIT 0
#define BT_RFCOMM_PN_CFC_CMD 0xf0
#define BT_RFCOMM_PN_CFC_RESP 0xe0
/* Initialize RFCOMM signal layer */
void bt_rfcomm_init(void);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,74 @@
/* sdp_internal.h - Service Discovery Protocol handling */
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* The PDU identifiers of SDP packets between client and server
*/
#define BT_SDP_ERROR_RSP 0x01
#define BT_SDP_SVC_SEARCH_REQ 0x02
#define BT_SDP_SVC_SEARCH_RSP 0x03
#define BT_SDP_SVC_ATTR_REQ 0x04
#define BT_SDP_SVC_ATTR_RSP 0x05
#define BT_SDP_SVC_SEARCH_ATTR_REQ 0x06
#define BT_SDP_SVC_SEARCH_ATTR_RSP 0x07
/*
* Some additions to support service registration.
* These are outside the scope of the Bluetooth specification
*/
#define BT_SDP_SVC_REGISTER_REQ 0x75
#define BT_SDP_SVC_REGISTER_RSP 0x76
#define BT_SDP_SVC_UPDATE_REQ 0x77
#define BT_SDP_SVC_UPDATE_RSP 0x78
#define BT_SDP_SVC_REMOVE_REQ 0x79
#define BT_SDP_SVC_REMOVE_RSP 0x80
/*
* SDP Error codes
*/
#define BT_SDP_INVALID_VERSION 0x0001
#define BT_SDP_INVALID_RECORD_HANDLE 0x0002
#define BT_SDP_INVALID_SYNTAX 0x0003
#define BT_SDP_INVALID_PDU_SIZE 0x0004
#define BT_SDP_INVALID_CSTATE 0x0005
#define BT_SDP_MAX_SERVICES 10
struct bt_sdp_data_elem_seq {
uint8_t type; /* Type: Will be data element sequence */
uint16_t size; /* We only support 2 byte sizes for now */
} __packed;
struct bt_sdp_hdr {
uint8_t op_code;
uint16_t tid;
uint16_t param_len;
} __packed;
struct bt_sdp_svc_rsp {
uint16_t total_recs;
uint16_t current_recs;
} __packed;
struct bt_sdp_att_rsp {
uint16_t att_list_len;
} __packed;
/* Allowed attributes length in SSA Request PDU to be taken from server */
#define BT_SDP_MAX_ATTR_LEN 0xffff
/* Max allowed length of PDU Continuation State */
#define BT_SDP_MAX_PDU_CSTATE_LEN 16
/* Type mapping SDP PDU Continuation State */
struct bt_sdp_pdu_cstate {
uint8_t length;
uint8_t data[BT_SDP_MAX_PDU_CSTATE_LEN];
} __packed;
void bt_sdp_init(void);

View file

@ -0,0 +1,428 @@
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <zephyr.h>
#include <bluetooth.h>
#include <conn.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_SETTINGS)
#define LOG_MODULE_NAME bt_settings
#include "log.h"
#include "hci_core.h"
#include "settings.h"
#include "keys.h"
#include "gatt.h"
#if defined(BFLB_BLE)
#include <stdlib.h>
#if defined(CONFIG_BT_SETTINGS)
#include "easyflash.h"
#endif
#include <FreeRTOS.h>
#include "portable.h"
#endif
#if defined(CONFIG_BT_SETTINGS_USE_PRINTK)
void bt_settings_encode_key(char *path, size_t path_size, const char *subsys,
bt_addr_le_t *addr, const char *key)
{
if (key) {
snprintk(path, path_size,
"bt/%s/%02x%02x%02x%02x%02x%02x%u/%s", subsys,
addr->a.val[5], addr->a.val[4], addr->a.val[3],
addr->a.val[2], addr->a.val[1], addr->a.val[0],
addr->type, key);
} else {
snprintk(path, path_size,
"bt/%s/%02x%02x%02x%02x%02x%02x%u", subsys,
addr->a.val[5], addr->a.val[4], addr->a.val[3],
addr->a.val[2], addr->a.val[1], addr->a.val[0],
addr->type);
}
BT_DBG("Encoded path %s", log_strdup(path));
}
#else
void bt_settings_encode_key(char *path, size_t path_size, const char *subsys,
bt_addr_le_t *addr, const char *key)
{
size_t len = 3;
/* Skip if path_size is less than 3; strlen("bt/") */
if (len < path_size) {
/* Key format:
* "bt/<subsys>/<addr><type>/<key>", "/<key>" is optional
*/
strcpy(path, "bt/");
strncpy(&path[len], subsys, path_size - len);
len = strlen(path);
if (len < path_size) {
path[len] = '/';
len++;
}
for (s8_t i = 5; i >= 0 && len < path_size; i--) {
len += bin2hex(&addr->a.val[i], 1, &path[len],
path_size - len);
}
if (len < path_size) {
/* Type can be either BT_ADDR_LE_PUBLIC or
* BT_ADDR_LE_RANDOM (value 0 or 1)
*/
path[len] = '0' + addr->type;
len++;
}
if (key && len < path_size) {
path[len] = '/';
len++;
strncpy(&path[len], key, path_size - len);
len += strlen(&path[len]);
}
if (len >= path_size) {
/* Truncate string */
path[path_size - 1] = '\0';
}
} else if (path_size > 0) {
*path = '\0';
}
BT_DBG("Encoded path %s", log_strdup(path));
}
#endif
#if !defined(BFLB_BLE)
int bt_settings_decode_key(const char *key, bt_addr_le_t *addr)
{
if (settings_name_next(key, NULL) != 13) {
return -EINVAL;
}
if (key[12] == '0') {
addr->type = BT_ADDR_LE_PUBLIC;
} else if (key[12] == '1') {
addr->type = BT_ADDR_LE_RANDOM;
} else {
return -EINVAL;
}
for (u8_t i = 0; i < 6; i++) {
hex2bin(&key[i * 2], 2, &addr->a.val[5 - i], 1);
}
BT_DBG("Decoded %s as %s", log_strdup(key), bt_addr_le_str(addr));
return 0;
}
static int set(const char *name, size_t len_rd, settings_read_cb read_cb,
void *cb_arg)
{
ssize_t len;
const char *next;
if (!name) {
BT_ERR("Insufficient number of arguments");
return -ENOENT;
}
len = settings_name_next(name, &next);
if (!strncmp(name, "id", len)) {
/* Any previously provided identities supersede flash */
if (atomic_test_bit(bt_dev.flags, BT_DEV_PRESET_ID)) {
BT_WARN("Ignoring identities stored in flash");
return 0;
}
len = read_cb(cb_arg, &bt_dev.id_addr, sizeof(bt_dev.id_addr));
if (len < sizeof(bt_dev.id_addr[0])) {
if (len < 0) {
BT_ERR("Failed to read ID address from storage"
" (err %zu)", len);
} else {
BT_ERR("Invalid length ID address in storage");
BT_HEXDUMP_DBG(&bt_dev.id_addr, len,
"data read");
}
(void)memset(bt_dev.id_addr, 0,
sizeof(bt_dev.id_addr));
bt_dev.id_count = 0U;
} else {
int i;
bt_dev.id_count = len / sizeof(bt_dev.id_addr[0]);
for (i = 0; i < bt_dev.id_count; i++) {
BT_DBG("ID[%d] %s", i,
bt_addr_le_str(&bt_dev.id_addr[i]));
}
}
return 0;
}
#if defined(CONFIG_BT_DEVICE_NAME_DYNAMIC)
if (!strncmp(name, "name", len)) {
len = read_cb(cb_arg, &bt_dev.name, sizeof(bt_dev.name) - 1);
if (len < 0) {
BT_ERR("Failed to read device name from storage"
" (err %zu)", len);
} else {
bt_dev.name[len] = '\0';
BT_DBG("Name set to %s", log_strdup(bt_dev.name));
}
return 0;
}
#endif
#if defined(CONFIG_BT_PRIVACY)
if (!strncmp(name, "irk", len)) {
len = read_cb(cb_arg, bt_dev.irk, sizeof(bt_dev.irk));
if (len < sizeof(bt_dev.irk[0])) {
if (len < 0) {
BT_ERR("Failed to read IRK from storage"
" (err %zu)", len);
} else {
BT_ERR("Invalid length IRK in storage");
(void)memset(bt_dev.irk, 0, sizeof(bt_dev.irk));
}
} else {
int i, count;
count = len / sizeof(bt_dev.irk[0]);
for (i = 0; i < count; i++) {
BT_DBG("IRK[%d] %s", i,
bt_hex(bt_dev.irk[i], 16));
}
}
return 0;
}
#endif /* CONFIG_BT_PRIVACY */
return -ENOENT;
}
#define ID_DATA_LEN(array) (bt_dev.id_count * sizeof(array[0]))
static void save_id(struct k_work *work)
{
int err;
BT_INFO("Saving ID");
err = settings_save_one("bt/id", &bt_dev.id_addr,
ID_DATA_LEN(bt_dev.id_addr));
if (err) {
BT_ERR("Failed to save ID (err %d)", err);
}
#if defined(CONFIG_BT_PRIVACY)
err = settings_save_one("bt/irk", bt_dev.irk, ID_DATA_LEN(bt_dev.irk));
if (err) {
BT_ERR("Failed to save IRK (err %d)", err);
}
#endif
}
K_WORK_DEFINE(save_id_work, save_id);
#endif //!BFLB_BLE
#if defined (BFLB_BLE)
#if defined(CONFIG_BT_SETTINGS)
bool ef_ready_flag = false;
int bt_check_if_ef_ready()
{
int err = 0;
if(!ef_ready_flag){
err = easyflash_init();
if(!err)
ef_ready_flag = true;
}
return err;
}
int bt_settings_set_bin(const char *key, const uint8_t *value, size_t length)
{
const char *lookup = "0123456789abcdef";
char *str_value;
int err;
err = bt_check_if_ef_ready();
if(err)
return err;
str_value = pvPortMalloc(length*2 + 1);
BT_ASSERT(str_value != NULL);
for(size_t i = 0; i < length; i++){
str_value[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F];
str_value[(i * 2) + 1] = lookup[value[i] & 0x0F];
}
str_value[length * 2] = '\0';
err = ef_set_env(key, (const char *)str_value);
vPortFree(str_value);
return err;
}
int bt_settings_get_bin(const char *key, u8_t *value, size_t exp_len, size_t *real_len)
{
char *str_value;
size_t str_value_len;
char rand[3];
int err;
err = bt_check_if_ef_ready();
if(err)
return err;
str_value = ef_get_env(key);
if(str_value == NULL)
{
return -1;
}
str_value_len = strlen(str_value);
if((str_value_len % 2) != 0 || (exp_len >0 && str_value_len > exp_len*2))
{
return -1;
}
if(real_len)
*real_len = str_value_len/2;
for(size_t i = 0; i < str_value_len/2; i++){
strncpy(rand, str_value+2*i, 2);
rand[2] = '\0';
value[i] = strtol(rand, NULL, 16);
}
return 0;
}
int settings_delete(const char *key)
{
return ef_del_env(key);
}
int settings_save_one(const char *key, const u8_t *value, size_t length)
{
return bt_settings_set_bin(key, value, length);
}
#endif //CONFIG_BT_SETTINGS
#endif
void bt_settings_save_id(void)
{
#if defined(BFLB_BLE)
#if defined(CONFIG_BT_SETTINGS)
if(bt_check_if_ef_ready())
return;
bt_settings_set_bin(NV_LOCAL_ID_ADDR, (const u8_t *)&bt_dev.id_addr[0], sizeof(bt_addr_le_t)*CONFIG_BT_ID_MAX);
#if defined(CONFIG_BT_PRIVACY)
bt_settings_set_bin(NV_LOCAL_IRK, (const u8_t *)&bt_dev.irk[0], 16*CONFIG_BT_ID_MAX);
#endif //CONFIG_BT_PRIVACY
#endif //CONFIG_BT_SETTINGS
#else
k_work_submit(&save_id_work);
#endif
}
#if defined(BFLB_BLE)
#if defined(CONFIG_BT_SETTINGS)
void bt_settings_save_name(void)
{
if(bt_check_if_ef_ready())
return;
ef_set_env(NV_LOCAL_NAME, bt_dev.name);
}
void bt_local_info_load(void)
{
if(bt_check_if_ef_ready())
return;
#if defined(CONFIG_BT_DEVICE_NAME_DYNAMIC)
char *dev_name;
uint8_t len;
dev_name = ef_get_env(NV_LOCAL_NAME);
if(dev_name != NULL){
len = ((strlen(dev_name)+1) < CONFIG_BT_DEVICE_NAME_MAX)? (strlen(dev_name)+1):CONFIG_BT_DEVICE_NAME_MAX;
memcpy(bt_dev.name, dev_name, len);
}
#endif
bt_settings_get_bin(NV_LOCAL_ID_ADDR, (u8_t *)&bt_dev.id_addr[0], sizeof(bt_addr_le_t)*CONFIG_BT_ID_MAX, NULL);
#if defined(CONFIG_BT_PRIVACY)
bt_settings_get_bin(NV_LOCAL_IRK, (u8_t *)&bt_dev.irk[0][0], 16*CONFIG_BT_ID_MAX, NULL);
#endif
}
#endif //CONFIG_BT_SETTINGS
#endif
#if !defined(BFLB_BLE)
static int commit(void)
{
BT_DBG("");
#if defined(CONFIG_BT_DEVICE_NAME_DYNAMIC)
if (bt_dev.name[0] == '\0') {
bt_set_name(CONFIG_BT_DEVICE_NAME);
}
#endif
if (!bt_dev.id_count) {
int err;
err = bt_setup_id_addr();
if (err) {
BT_ERR("Unable to setup an identity address");
return err;
}
}
/* Make sure that the identities created by bt_id_create after
* bt_enable is saved to persistent storage. */
if (!atomic_test_bit(bt_dev.flags, BT_DEV_PRESET_ID)) {
bt_settings_save_id();
}
if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
bt_finalize_init();
}
return 0;
}
SETTINGS_STATIC_HANDLER_DEFINE(bt, "bt", NULL, set, commit, NULL);
#endif //!BFLB_BLE
int bt_settings_init(void)
{
#if defined(BFLB_BLE)
return 0;
#else
int err;
BT_DBG("");
err = settings_subsys_init();
if (err) {
BT_ERR("settings_subsys_init failed (err %d)", err);
return err;
}
return 0;
#endif
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#if defined(BFLB_BLE)
#include "addr.h"
#endif
/* Max settings key length (with all components) */
#define BT_SETTINGS_KEY_MAX 36
/* Base64-encoded string buffer size of in_size bytes */
#define BT_SETTINGS_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)
/* Helpers for keys containing a bdaddr */
void bt_settings_encode_key(char *path, size_t path_size, const char *subsys,
bt_addr_le_t *addr, const char *key);
int bt_settings_decode_key(const char *key, bt_addr_le_t *addr);
void bt_settings_save_id(void);
int bt_settings_init(void);
#if defined(BFLB_BLE)
#define NV_LOCAL_NAME "LOCAL_NAME"
#define NV_LOCAL_ID_ADDR "LOCAL_ID_ADDR"
#define NV_LOCAL_IRK "LOCAL_IRK"
#define NV_KEY_POOL "KEY_POOL"
#define NV_IMG_info "IMG_INFO"
int bt_settings_get_bin(const char *key, u8_t *value, size_t exp_len, size_t *real_len);
int bt_settings_set_bin(const char *key, const u8_t *value, size_t length);
int settings_delete(const char *key);
int settings_save_one(const char *key, const u8_t *value, size_t length);
void bt_settings_save_name(void);
void bt_local_info_load(void);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,187 @@
/**
* @file smp.h
* Security Manager Protocol implementation header
*/
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
struct bt_smp_hdr {
u8_t code;
} __packed;
#define BT_SMP_ERR_PASSKEY_ENTRY_FAILED 0x01
#define BT_SMP_ERR_OOB_NOT_AVAIL 0x02
#define BT_SMP_ERR_AUTH_REQUIREMENTS 0x03
#define BT_SMP_ERR_CONFIRM_FAILED 0x04
#define BT_SMP_ERR_PAIRING_NOTSUPP 0x05
#define BT_SMP_ERR_ENC_KEY_SIZE 0x06
#define BT_SMP_ERR_CMD_NOTSUPP 0x07
#define BT_SMP_ERR_UNSPECIFIED 0x08
#define BT_SMP_ERR_REPEATED_ATTEMPTS 0x09
#define BT_SMP_ERR_INVALID_PARAMS 0x0a
#define BT_SMP_ERR_DHKEY_CHECK_FAILED 0x0b
#define BT_SMP_ERR_NUMERIC_COMP_FAILED 0x0c
#define BT_SMP_ERR_BREDR_PAIRING_IN_PROGRESS 0x0d
#define BT_SMP_ERR_CROSS_TRANSP_NOT_ALLOWED 0x0e
#define BT_SMP_IO_DISPLAY_ONLY 0x00
#define BT_SMP_IO_DISPLAY_YESNO 0x01
#define BT_SMP_IO_KEYBOARD_ONLY 0x02
#define BT_SMP_IO_NO_INPUT_OUTPUT 0x03
#define BT_SMP_IO_KEYBOARD_DISPLAY 0x04
#define BT_SMP_OOB_DATA_MASK 0x01
#define BT_SMP_OOB_NOT_PRESENT 0x00
#define BT_SMP_OOB_PRESENT 0x01
#define BT_SMP_MIN_ENC_KEY_SIZE 7
#define BT_SMP_MAX_ENC_KEY_SIZE 16
#define BT_SMP_DIST_ENC_KEY 0x01
#define BT_SMP_DIST_ID_KEY 0x02
#define BT_SMP_DIST_SIGN 0x04
#define BT_SMP_DIST_LINK_KEY 0x08
#define BT_SMP_DIST_MASK 0x0f
#define BT_SMP_AUTH_NONE 0x00
#define BT_SMP_AUTH_BONDING 0x01
#define BT_SMP_AUTH_MITM 0x04
#define BT_SMP_AUTH_SC 0x08
#define BT_SMP_AUTH_KEYPRESS 0x10
#define BT_SMP_AUTH_CT2 0x20
#define BT_SMP_CMD_PAIRING_REQ 0x01
#define BT_SMP_CMD_PAIRING_RSP 0x02
struct bt_smp_pairing {
u8_t io_capability;
u8_t oob_flag;
u8_t auth_req;
u8_t max_key_size;
u8_t init_key_dist;
u8_t resp_key_dist;
} __packed;
#define BT_SMP_CMD_PAIRING_CONFIRM 0x03
struct bt_smp_pairing_confirm {
u8_t val[16];
} __packed;
#define BT_SMP_CMD_PAIRING_RANDOM 0x04
struct bt_smp_pairing_random {
u8_t val[16];
} __packed;
#define BT_SMP_CMD_PAIRING_FAIL 0x05
struct bt_smp_pairing_fail {
u8_t reason;
} __packed;
#define BT_SMP_CMD_ENCRYPT_INFO 0x06
struct bt_smp_encrypt_info {
u8_t ltk[16];
} __packed;
#define BT_SMP_CMD_MASTER_IDENT 0x07
struct bt_smp_master_ident {
u8_t ediv[2];
u8_t rand[8];
} __packed;
#define BT_SMP_CMD_IDENT_INFO 0x08
struct bt_smp_ident_info {
u8_t irk[16];
} __packed;
#define BT_SMP_CMD_IDENT_ADDR_INFO 0x09
struct bt_smp_ident_addr_info {
bt_addr_le_t addr;
} __packed;
#define BT_SMP_CMD_SIGNING_INFO 0x0a
struct bt_smp_signing_info {
u8_t csrk[16];
} __packed;
#define BT_SMP_CMD_SECURITY_REQUEST 0x0b
struct bt_smp_security_request {
u8_t auth_req;
} __packed;
#define BT_SMP_CMD_PUBLIC_KEY 0x0c
struct bt_smp_public_key {
u8_t x[32];
u8_t y[32];
} __packed;
#define BT_SMP_DHKEY_CHECK 0x0d
struct bt_smp_dhkey_check {
u8_t e[16];
} __packed;
int bt_smp_start_security(struct bt_conn *conn);
bool bt_smp_request_ltk(struct bt_conn *conn, u64_t rand, u16_t ediv,
u8_t *ltk);
void bt_smp_update_keys(struct bt_conn *conn);
int bt_smp_br_send_pairing_req(struct bt_conn *conn);
int bt_smp_init(void);
int bt_smp_auth_passkey_entry(struct bt_conn *conn, unsigned int passkey);
int bt_smp_auth_passkey_confirm(struct bt_conn *conn);
int bt_smp_auth_pairing_confirm(struct bt_conn *conn);
int bt_smp_auth_cancel(struct bt_conn *conn);
int bt_smp_le_oob_generate_sc_data(struct bt_le_oob_sc_data *le_sc_oob);
int bt_smp_le_oob_set_sc_data(struct bt_conn *conn,
const struct bt_le_oob_sc_data *oobd_local,
const struct bt_le_oob_sc_data *oobd_remote);
int bt_smp_le_oob_get_sc_data(struct bt_conn *conn,
const struct bt_le_oob_sc_data **oobd_local,
const struct bt_le_oob_sc_data **oobd_remote);
/** brief Verify signed message
*
* @param conn Bluetooth connection
* @param buf received packet buffer with message and signature
*
* @return 0 in success, error code otherwise
*/
int bt_smp_sign_verify(struct bt_conn *conn, struct net_buf *buf);
/** brief Sign message
*
* @param conn Bluetooth connection
* @param buf message buffer
*
* @return 0 in success, error code otherwise
*/
int bt_smp_sign(struct bt_conn *conn, struct net_buf *buf);
#if defined(CONFIG_AUTO_PTS)
int bt_le_oob_set_legacy_tk(struct bt_conn *conn, const uint8_t *tk);
#endif
#if defined(CONFIG_BLE_AT_CMD)
struct smp_parameters{
u8_t auth;
u8_t iocap;
u16_t key_size;
u8_t init_key;
u8_t rsp_key;
u8_t set;
};
struct smp_parameters user_smp_paras;
int ble_set_smp_paramters(const struct smp_parameters *paras);
int ble_get_smp_paramters(const struct bt_conn *conn,struct smp_parameters *paras);
#endif
#if defined(BFLB_BLE_SMP_LOCAL_AUTH)
void smp_set_auth(u8_t auth);
#endif

View file

@ -0,0 +1,101 @@
/**
* @file smp_null.c
* Security Manager Protocol stub
*/
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <errno.h>
#include <atomic.h>
#include <misc/util.h>
#include <bluetooth.h>
#include <conn.h>
#include <../include/bluetooth/buf.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE)
#define LOG_MODULE_NAME bt_smp
#include "log.h"
#include "hci_core.h"
#include "conn_internal.h"
#include "l2cap_internal.h"
#include "smp.h"
static struct bt_l2cap_le_chan bt_smp_pool[CONFIG_BT_MAX_CONN];
int bt_smp_sign_verify(struct bt_conn *conn, struct net_buf *buf)
{
return -ENOTSUP;
}
int bt_smp_sign(struct bt_conn *conn, struct net_buf *buf)
{
return -ENOTSUP;
}
static int bt_smp_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
{
struct bt_conn *conn = chan->conn;
struct bt_smp_pairing_fail *rsp;
struct bt_smp_hdr *hdr;
/* If a device does not support pairing then it shall respond with
* a Pairing Failed command with the reason set to "Pairing Not
* Supported" when any command is received.
* Core Specification Vol. 3, Part H, 3.3
*/
buf = bt_l2cap_create_pdu(NULL, 0);
/* NULL is not a possible return due to K_FOREVER */
hdr = net_buf_add(buf, sizeof(*hdr));
hdr->code = BT_SMP_CMD_PAIRING_FAIL;
rsp = net_buf_add(buf, sizeof(*rsp));
rsp->reason = BT_SMP_ERR_PAIRING_NOTSUPP;
bt_l2cap_send(conn, BT_L2CAP_CID_SMP, buf);
return 0;
}
static int bt_smp_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
{
int i;
static struct bt_l2cap_chan_ops ops = {
.recv = bt_smp_recv,
};
BT_DBG("conn %p handle %u", conn, conn->handle);
for (i = 0; i < ARRAY_SIZE(bt_smp_pool); i++) {
struct bt_l2cap_le_chan *smp = &bt_smp_pool[i];
if (smp->chan.conn) {
continue;
}
smp->chan.ops = &ops;
*chan = &smp->chan;
return 0;
}
BT_ERR("No available SMP context for conn %p", conn);
return -ENOMEM;
}
BT_L2CAP_CHANNEL_DEFINE(smp_fixed_chan, BT_L2CAP_CID_SMP, bt_smp_accept);
int bt_smp_init(void)
{
return 0;
}

View file

@ -0,0 +1,139 @@
/* uuid.c - Bluetooth UUID handling */
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <errno.h>
#include <misc/byteorder.h>
#include <misc/printk.h>
#include <uuid.h>
#define UUID_16_BASE_OFFSET 12
/* TODO: Decide whether to continue using BLE format or switch to RFC 4122 */
/* Base UUID : 0000[0000]-0000-1000-8000-00805F9B34FB
* 0x2800 : 0000[2800]-0000-1000-8000-00805F9B34FB
* little endian 0x2800 : [00 28] -> no swapping required
* big endian 0x2800 : [28 00] -> swapping required
*/
static const struct bt_uuid_128 uuid128_base = {
.uuid = { BT_UUID_TYPE_128 },
.val = { BT_UUID_128_ENCODE(
0x00000000, 0x0000, 0x1000, 0x8000, 0x00805F9B34FB) }
};
static void uuid_to_uuid128(const struct bt_uuid *src, struct bt_uuid_128 *dst)
{
switch (src->type) {
case BT_UUID_TYPE_16:
*dst = uuid128_base;
sys_put_le16(BT_UUID_16(src)->val,
&dst->val[UUID_16_BASE_OFFSET]);
return;
case BT_UUID_TYPE_32:
*dst = uuid128_base;
sys_put_le32(BT_UUID_32(src)->val,
&dst->val[UUID_16_BASE_OFFSET]);
return;
case BT_UUID_TYPE_128:
memcpy(dst, src, sizeof(*dst));
return;
}
}
static int uuid128_cmp(const struct bt_uuid *u1, const struct bt_uuid *u2)
{
struct bt_uuid_128 uuid1, uuid2;
uuid_to_uuid128(u1, &uuid1);
uuid_to_uuid128(u2, &uuid2);
return memcmp(uuid1.val, uuid2.val, 16);
}
int bt_uuid_cmp(const struct bt_uuid *u1, const struct bt_uuid *u2)
{
/* Convert to 128 bit if types don't match */
if (u1->type != u2->type) {
return uuid128_cmp(u1, u2);
}
switch (u1->type) {
case BT_UUID_TYPE_16:
return (int)BT_UUID_16(u1)->val - (int)BT_UUID_16(u2)->val;
case BT_UUID_TYPE_32:
return (int)BT_UUID_32(u1)->val - (int)BT_UUID_32(u2)->val;
case BT_UUID_TYPE_128:
return memcmp(BT_UUID_128(u1)->val, BT_UUID_128(u2)->val, 16);
}
return -EINVAL;
}
bool bt_uuid_create(struct bt_uuid *uuid, const u8_t *data, u8_t data_len)
{
/* Copy UUID from packet data/internal variable to internal bt_uuid */
switch (data_len) {
case 2:
uuid->type = BT_UUID_TYPE_16;
BT_UUID_16(uuid)->val = sys_get_le16(data);
break;
case 4:
uuid->type = BT_UUID_TYPE_32;
BT_UUID_32(uuid)->val = sys_get_le32(data);
break;
case 16:
uuid->type = BT_UUID_TYPE_128;
memcpy(&BT_UUID_128(uuid)->val, data, 16);
break;
default:
return false;
}
return true;
}
#if defined(CONFIG_BT_DEBUG)
void bt_uuid_to_str(const struct bt_uuid *uuid, char *str, size_t len)
{
u32_t tmp1, tmp5;
u16_t tmp0, tmp2, tmp3, tmp4;
switch (uuid->type) {
case BT_UUID_TYPE_16:
snprintk(str, len, "%04x", BT_UUID_16(uuid)->val);
break;
case BT_UUID_TYPE_32:
snprintk(str, len, "%04x", BT_UUID_32(uuid)->val);
break;
case BT_UUID_TYPE_128:
memcpy(&tmp0, &BT_UUID_128(uuid)->val[0], sizeof(tmp0));
memcpy(&tmp1, &BT_UUID_128(uuid)->val[2], sizeof(tmp1));
memcpy(&tmp2, &BT_UUID_128(uuid)->val[6], sizeof(tmp2));
memcpy(&tmp3, &BT_UUID_128(uuid)->val[8], sizeof(tmp3));
memcpy(&tmp4, &BT_UUID_128(uuid)->val[10], sizeof(tmp4));
memcpy(&tmp5, &BT_UUID_128(uuid)->val[12], sizeof(tmp5));
snprintk(str, len, "%08x-%04x-%04x-%04x-%08x%04x",
tmp5, tmp4, tmp3, tmp2, tmp1, tmp0);
break;
default:
(void)memset(str, 0, len);
return;
}
}
const char *bt_uuid_str_real(const struct bt_uuid *uuid)
{
static char str[37];
bt_uuid_to_str(uuid, str, sizeof(str));
return str;
}
#endif /* CONFIG_BT_DEBUG */