Merge pull request #748 from michal-narajowski/mesh-zephyr-ports

Some mesh fixes from Zephyr

X-Original-Commit: a45035b6de7ba35df30eba59b8aabe342f3c4f2c
This commit is contained in:
Michał Narajowski
2018-02-16 14:05:54 +01:00
committed by GitHub
17 changed files with 727 additions and 436 deletions
+20
View File
@@ -28,6 +28,7 @@
#include "os/os_mbuf.h"
#include "os/os_callout.h"
#include "os/os_eventq.h"
#include "os/queue.h"
#include "atomic.h"
#include "nimble/ble.h"
@@ -341,6 +342,7 @@ static inline unsigned int find_msb_set(u32_t op)
#define CONFIG_BT_MESH_PB_ADV BLE_MESH_PB_ADV
#define CONFIG_BT_MESH_PB_GATT BLE_MESH_PB_GATT
#define CONFIG_BT_MESH_PROV BLE_MESH_PROV
#define CONFIG_BT_TESTING BLE_MESH_TESTING
/* Above flags are used with IS_ENABLED macro */
#define IS_ENABLED(config) MYNEWT_VAL(config)
@@ -394,4 +396,22 @@ static inline int net_buf_id(struct os_mbuf *buf)
return (buf_ptr - pool_start) / BUF_SIZE(pool);
}
/* XXX: We should not use os_mbuf_pkthdr chains to represent a list of
* packets, this is a hack. For now this is not an issue, because mesh
* does not use os_mbuf chains. We should change this in the future.
*/
STAILQ_HEAD(net_buf_slist_t, os_mbuf_pkthdr);
void net_buf_slist_init(struct net_buf_slist_t *list);
bool net_buf_slist_is_empty(struct net_buf_slist_t *list);
struct os_mbuf *net_buf_slist_peek_head(struct net_buf_slist_t *list);
struct os_mbuf *net_buf_slist_peek_next(struct os_mbuf *buf);
struct os_mbuf *net_buf_slist_get(struct net_buf_slist_t *list);
void net_buf_slist_put(struct net_buf_slist_t *list, struct os_mbuf *buf);
void net_buf_slist_remove(struct net_buf_slist_t *list, struct os_mbuf *prev,
struct os_mbuf *cur);
void net_buf_slist_merge_slist(struct net_buf_slist_t *list,
struct net_buf_slist_t *list_to_append);
#define NET_BUF_SLIST_FOR_EACH_NODE(head, var) STAILQ_FOREACH(var, head, omp_next)
#endif
+4
View File
@@ -218,6 +218,10 @@ int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers);
#define BT_MESH_FEAT_PROXY BIT(1)
#define BT_MESH_FEAT_FRIEND BIT(2)
#define BT_MESH_FEAT_LOW_POWER BIT(3)
#define BT_MESH_FEAT_SUPPORTED (BT_MESH_FEAT_RELAY | \
BT_MESH_FEAT_PROXY | \
BT_MESH_FEAT_FRIEND | \
BT_MESH_FEAT_LOW_POWER)
/** @brief Initialize Mesh support
*
+259 -31
View File
@@ -19,15 +19,22 @@
#include <stddef.h>
#include <stdbool.h>
#include "os/queue.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct os_mbuf sys_snode_t;
STAILQ_HEAD(_slist, os_mbuf_pkthdr);
struct _snode {
struct _snode *next;
};
typedef struct _snode sys_snode_t;
struct _slist {
sys_snode_t *head;
sys_snode_t *tail;
};
typedef struct _slist sys_slist_t;
@@ -46,9 +53,98 @@ typedef struct _slist sys_slist_t;
* @param __sl A pointer on a sys_slist_t to iterate on
* @param __sn A sys_snode_t pointer to peek each node of the list
*/
#define SYS_SLIST_FOR_EACH_NODE(__sl, __sn) \
for (__sn = sys_slist_peek_head(__sl); __sn; \
__sn = sys_slist_peek_next(__sn))
#define SYS_SLIST_FOR_EACH_NODE(__sl, __sn) \
for (__sn = sys_slist_peek_head(__sl); __sn; \
__sn = sys_slist_peek_next(__sn))
/**
* @brief Provide the primitive to iterate on a list, from a node in the list
* Note: the loop is unsafe and thus __sn should not be removed
*
* User _MUST_ add the loop statement curly braces enclosing its own code:
*
* SYS_SLIST_ITERATE_FROM_NODE(l, n) {
* <user code>
* }
*
* Like SYS_SLIST_FOR_EACH_NODE(), but __dn already contains a node in the list
* where to start searching for the next entry from. If NULL, it starts from
* the head.
*
* This and other SYS_SLIST_*() macros are not thread safe.
*
* @param __sl A pointer on a sys_slist_t to iterate on
* @param __sn A sys_snode_t pointer to peek each node of the list
* it contains the starting node, or NULL to start from the head
*/
#define SYS_SLIST_ITERATE_FROM_NODE(__sl, __sn) \
for (__sn = __sn ? sys_slist_peek_next_no_check(__sn) \
: sys_slist_peek_head(__sl); \
__sn; \
__sn = sys_slist_peek_next(__sn))
/**
* @brief Provide the primitive to safely iterate on a list
* Note: __sn can be removed, it will not break the loop.
*
* User _MUST_ add the loop statement curly braces enclosing its own code:
*
* SYS_SLIST_FOR_EACH_NODE_SAFE(l, n, s) {
* <user code>
* }
*
* This and other SYS_SLIST_*() macros are not thread safe.
*
* @param __sl A pointer on a sys_slist_t to iterate on
* @param __sn A sys_snode_t pointer to peek each node of the list
* @param __sns A sys_snode_t pointer for the loop to run safely
*/
#define SYS_SLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \
for (__sn = sys_slist_peek_head(__sl), \
__sns = sys_slist_peek_next(__sn); \
__sn; __sn = __sns, \
__sns = sys_slist_peek_next(__sn))
/*
* @brief Provide the primitive to resolve the container of a list node
* Note: it is safe to use with NULL pointer nodes
*
* @param __ln A pointer on a sys_node_t to get its container
* @param __cn Container struct type pointer
* @param __n The field name of sys_node_t within the container struct
*/
#define SYS_SLIST_CONTAINER(__ln, __cn, __n) \
((__ln) ? CONTAINER_OF((__ln), __typeof__(*(__cn)), __n) : NULL)
/*
* @brief Provide the primitive to peek container of the list head
*
* @param __sl A pointer on a sys_slist_t to peek
* @param __cn Container struct type pointer
* @param __n The field name of sys_node_t within the container struct
*/
#define SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n) \
SYS_SLIST_CONTAINER(sys_slist_peek_head(__sl), __cn, __n)
/*
* @brief Provide the primitive to peek container of the list tail
*
* @param __sl A pointer on a sys_slist_t to peek
* @param __cn Container struct type pointer
* @param __n The field name of sys_node_t within the container struct
*/
#define SYS_SLIST_PEEK_TAIL_CONTAINER(__sl, __cn, __n) \
SYS_SLIST_CONTAINER(sys_slist_peek_tail(__sl), __cn, __n)
/*
* @brief Provide the primitive to peek the next container
*
* @param __cn Container struct type pointer
* @param __n The field name of sys_node_t within the container struct
*/
#define SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n) \
((__cn) ? SYS_SLIST_CONTAINER(sys_slist_peek_next(&((__cn)->__n)), \
__cn, __n) : NULL)
/**
* @brief Provide the primitive to iterate on a list under a container
@@ -64,17 +160,42 @@ typedef struct _slist sys_slist_t;
* @param __cn A pointer to peek each entry of the list
* @param __n The field name of sys_node_t within the container struct
*/
#define SYS_SLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \
STAILQ_FOREACH(__cn, __sl, omp_next)
#define SYS_SLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \
for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n); __cn; \
__cn = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n))
/**
* @brief Provide the primitive to safely iterate on a list under a container
* Note: __cn can be detached, it will not break the loop.
*
* User _MUST_ add the loop statement curly braces enclosing its own code:
*
* SYS_SLIST_FOR_EACH_NODE_SAFE(l, c, cn, n) {
* <user code>
* }
*
* @param __sl A pointer on a sys_slist_t to iterate on
* @param __cn A pointer to peek each entry of the list
* @param __cns A pointer for the loop to run safely
* @param __n The field name of sys_node_t within the container struct
*/
#define SYS_SLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n) \
for (__cn = SYS_SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n), \
__cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n); __cn; \
__cn = __cns, __cns = SYS_SLIST_PEEK_NEXT_CONTAINER(__cn, __n))
/**
* @brief Initialize a list
*
* @param list A pointer on the list to initialize
*/
void sys_slist_init(sys_slist_t *list);
static inline void sys_slist_init(sys_slist_t *list)
{
list->head = NULL;
list->tail = NULL;
}
#define SYS_SLIST_STATIC_INIT(ptr_to_list) STAILQ_HEAD_INITIALIZER(ptr_to_list)
#define SYS_SLIST_STATIC_INIT(ptr_to_list) {NULL, NULL}
/**
* @brief Test if the given list is empty
@@ -83,7 +204,10 @@ void sys_slist_init(sys_slist_t *list);
*
* @return a boolean, true if it's empty, false otherwise
*/
bool sys_slist_is_empty(sys_slist_t *list);
static inline bool sys_slist_is_empty(sys_slist_t *list)
{
return (!list->head);
}
/**
* @brief Peek the first node from the list
@@ -92,7 +216,10 @@ bool sys_slist_is_empty(sys_slist_t *list);
*
* @return A pointer on the first node of the list (or NULL if none)
*/
sys_snode_t *sys_slist_peek_head(sys_slist_t *list);
static inline sys_snode_t *sys_slist_peek_head(sys_slist_t *list)
{
return list->head;
}
/**
* @brief Peek the last node from the list
@@ -101,7 +228,10 @@ sys_snode_t *sys_slist_peek_head(sys_slist_t *list);
*
* @return A pointer on the last node of the list (or NULL if none)
*/
sys_snode_t *sys_slist_peek_tail(sys_slist_t *list);
static inline sys_snode_t *sys_slist_peek_tail(sys_slist_t *list)
{
return list->tail;
}
/**
* @brief Peek the next node from current node, node is not NULL
@@ -112,7 +242,10 @@ sys_snode_t *sys_slist_peek_tail(sys_slist_t *list);
*
* @return a pointer on the next node (or NULL if none)
*/
sys_snode_t *sys_slist_peek_next_no_check(sys_snode_t *node);
static inline sys_snode_t *sys_slist_peek_next_no_check(sys_snode_t *node)
{
return node->next;
}
/**
* @brief Peek the next node from current node
@@ -121,7 +254,10 @@ sys_snode_t *sys_slist_peek_next_no_check(sys_snode_t *node);
*
* @return a pointer on the next node (or NULL if none)
*/
sys_snode_t *sys_slist_peek_next(sys_snode_t *node);
static inline sys_snode_t *sys_slist_peek_next(sys_snode_t *node)
{
return node ? sys_slist_peek_next_no_check(node) : NULL;
}
/**
* @brief Prepend a node to the given list
@@ -131,7 +267,16 @@ sys_snode_t *sys_slist_peek_next(sys_snode_t *node);
* @param list A pointer on the list to affect
* @param node A pointer on the node to prepend
*/
void sys_slist_prepend(sys_slist_t *list, sys_snode_t *node);
static inline void sys_slist_prepend(sys_slist_t *list,
sys_snode_t *node)
{
node->next = list->head;
list->head = node;
if (!list->tail) {
list->tail = list->head;
}
}
/**
* @brief Append a node to the given list
@@ -141,7 +286,19 @@ void sys_slist_prepend(sys_slist_t *list, sys_snode_t *node);
* @param list A pointer on the list to affect
* @param node A pointer on the node to append
*/
void sys_slist_append(sys_slist_t *list, sys_snode_t *node);
static inline void sys_slist_append(sys_slist_t *list,
sys_snode_t *node)
{
node->next = NULL;
if (!list->tail) {
list->tail = node;
list->head = node;
} else {
list->tail->next = node;
list->tail = node;
}
}
/**
* @brief Append a list to the given list
@@ -154,7 +311,17 @@ void sys_slist_append(sys_slist_t *list, sys_snode_t *node);
* @param head A pointer to the first element of the list to append
* @param tail A pointer to the last element of the list to append
*/
void sys_slist_append_list(sys_slist_t *list, sys_slist_t *list_append);
static inline void sys_slist_append_list(sys_slist_t *list,
void *head, void *tail)
{
if (!list->tail) {
list->head = (sys_snode_t *)head;
list->tail = (sys_snode_t *)tail;
} else {
list->tail->next = (sys_snode_t *)head;
list->tail = (sys_snode_t *)tail;
}
}
/**
* @brief merge two slists, appending the second one to the first
@@ -165,7 +332,13 @@ void sys_slist_append_list(sys_slist_t *list, sys_slist_t *list_append);
* @param list A pointer on the list to affect
* @param list_to_append A pointer to the list to append.
*/
void sys_slist_merge_slist(sys_slist_t *list, sys_slist_t *list_to_append);
static inline void sys_slist_merge_slist(sys_slist_t *list,
sys_slist_t *list_to_append)
{
sys_slist_append_list(list, list_to_append->head,
list_to_append->tail);
sys_slist_init(list_to_append);
}
/**
* @brief Insert a node to the given list
@@ -176,9 +349,19 @@ void sys_slist_merge_slist(sys_slist_t *list, sys_slist_t *list_to_append);
* @param prev A pointer on the previous node
* @param node A pointer on the node to insert
*/
void sys_slist_insert(sys_slist_t *list,
sys_snode_t *prev,
sys_snode_t *node);
static inline void sys_slist_insert(sys_slist_t *list,
sys_snode_t *prev,
sys_snode_t *node)
{
if (!prev) {
sys_slist_prepend(list, node);
} else if (!prev->next) {
sys_slist_append(list, node);
} else {
node->next = prev->next;
prev->next = node;
}
}
/**
* @brief Fetch and remove the first node of the given list
@@ -190,7 +373,18 @@ void sys_slist_insert(sys_slist_t *list,
*
* @return A pointer to the first node of the list
*/
sys_snode_t *sys_slist_get_not_empty(sys_slist_t *list);
static inline sys_snode_t *sys_slist_get_not_empty(sys_slist_t *list)
{
sys_snode_t *node = list->head;
list->head = node->next;
if (list->tail == node) {
list->tail = list->head;
}
return node;
}
/**
* @brief Fetch and remove the first node of the given list
*
@@ -200,7 +394,10 @@ sys_snode_t *sys_slist_get_not_empty(sys_slist_t *list);
*
* @return A pointer to the first node of the list (or NULL if empty)
*/
sys_snode_t *sys_slist_get(sys_slist_t *list);
static inline sys_snode_t *sys_slist_get(sys_slist_t *list)
{
return sys_slist_is_empty(list) ? NULL : sys_slist_get_not_empty(list);
}
/**
* @brief Remove a node
@@ -212,9 +409,28 @@ sys_snode_t *sys_slist_get(sys_slist_t *list);
* (can be NULL, which means the node is the list's head)
* @param node A pointer on the node to remove
*/
void sys_slist_remove(sys_slist_t *list,
sys_snode_t *prev_node,
sys_snode_t *node);
static inline void sys_slist_remove(sys_slist_t *list,
sys_snode_t *prev_node,
sys_snode_t *node)
{
if (!prev_node) {
list->head = node->next;
/* Was node also the tail? */
if (list->tail == node) {
list->tail = list->head;
}
} else {
prev_node->next = node->next;
/* Was node the tail? */
if (list->tail == node) {
list->tail = prev_node;
}
}
node->next = NULL;
}
/**
* @brief Find and remove a node from a list
@@ -226,12 +442,24 @@ void sys_slist_remove(sys_slist_t *list,
*
* @return true if node was removed
*/
bool sys_slist_find_and_remove(sys_slist_t *list,
sys_snode_t *node);
static inline bool sys_slist_find_and_remove(sys_slist_t *list,
sys_snode_t *node)
{
sys_snode_t *prev = NULL;
sys_snode_t *test;
void net_buf_slist_put(sys_slist_t *list, struct os_mbuf *buf);
SYS_SLIST_FOR_EACH_NODE(list, test) {
if (test == node) {
sys_slist_remove(list, prev, node);
return true;
}
prev = test;
}
return false;
}
struct os_mbuf *net_buf_slist_get(sys_slist_t *list);
#ifdef __cplusplus
}
+68
View File
@@ -0,0 +1,68 @@
/**
* @file testing.h
* @brief Internal API for Bluetooth testing.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BT_TESTING_H
#define __BT_TESTING_H
#include "slist.h"
#include "glue.h"
#include "access.h"
/**
* @brief Bluetooth testing
* @defgroup bt_test_cb Bluetooth testing callbacks
* @ingroup bluetooth
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Bluetooth Testing callbacks structure.
*
* Callback structure to be used for Bluetooth testing purposes.
* Allows access to Bluetooth stack internals, not exposed by public API.
*/
struct bt_test_cb {
void (*mesh_net_recv)(u8_t ttl, u8_t ctl, u16_t src, u16_t dst,
const void *payload, size_t payload_len);
void (*mesh_model_bound)(u16_t addr, struct bt_mesh_model *model,
u16_t key_idx);
void (*mesh_model_unbound)(u16_t addr, struct bt_mesh_model *model,
u16_t key_idx);
void (*mesh_prov_invalid_bearer)(u8_t opcode);
void (*mesh_trans_incomp_timer_exp)(void);
sys_snode_t node;
};
/** Register callbacks for Bluetooth testing purposes
*
* @param cb bt_test_cb callback structure
*/
void bt_test_cb_register(struct bt_test_cb *cb);
/** Unregister callbacks for Bluetooth testing purposes
*
* @param cb bt_test_cb callback structure
*/
void bt_test_cb_unregister(struct bt_test_cb *cb);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __BT_TESTING_H */
+1 -1
View File
@@ -258,7 +258,7 @@ static void bt_mesh_scan_cb(const bt_addr_le_t *addr, s8_t rssi,
return;
}
if (len > buf->om_len || buf->om_len < 1) {
if (len > buf->om_len) {
BT_WARN("AD malformed");
return;
}
+80 -34
View File
@@ -27,12 +27,14 @@
#include "proxy.h"
#include "foundation.h"
#include "friend.h"
#include "testing.h"
#define DEFAULT_TTL 7
static struct bt_mesh_cfg_srv *conf;
static struct label {
u16_t ref;
u16_t addr;
u8_t uuid[16];
} labels[MYNEWT_VAL(BLE_MESH_LABEL_COUNT)];
@@ -344,11 +346,9 @@ static u8_t mod_unbind(struct bt_mesh_model *model, u16_t key_idx)
_mod_pub_set(model, BT_MESH_ADDR_UNASSIGNED,
0, 0, 0, 0, 0);
}
return STATUS_SUCCESS;
}
return STATUS_CANNOT_BIND;
return STATUS_SUCCESS;
}
static struct bt_mesh_app_key *app_key_alloc(u16_t app_idx)
@@ -1115,39 +1115,24 @@ send_status:
}
#if MYNEWT_VAL(BLE_MESH_LABEL_COUNT) > 0
static u16_t va_find(u8_t *label_uuid, struct label **free_slot)
static u8_t va_add(u8_t *label_uuid, u16_t *addr)
{
struct label *free_slot = NULL;
int i;
if (free_slot) {
*free_slot = NULL;
}
for (i = 0; i < ARRAY_SIZE(labels); i++) {
if (!BT_MESH_ADDR_IS_VIRTUAL(labels[i].addr)) {
if (free_slot) {
*free_slot = &labels[i];
}
if (!labels[i].ref) {
free_slot = &labels[i];
continue;
}
if (!memcmp(labels[i].uuid, label_uuid, 16)) {
return labels[i].addr;
*addr = labels[i].addr;
labels[i].ref++;
return STATUS_SUCCESS;
}
}
return BT_MESH_ADDR_UNASSIGNED;
}
static u8_t va_add(u8_t *label_uuid, u16_t *addr)
{
struct label *free_slot;
*addr = va_find(label_uuid, &free_slot);
if (*addr != BT_MESH_ADDR_UNASSIGNED) {
return STATUS_SUCCESS;
}
if (!free_slot) {
return STATUS_INSUFF_RESOURCES;
}
@@ -1156,12 +1141,59 @@ static u8_t va_add(u8_t *label_uuid, u16_t *addr)
return STATUS_UNSPECIFIED;
}
free_slot->ref = 1;
free_slot->addr = *addr;
memcpy(free_slot->uuid, label_uuid, 16);
return STATUS_SUCCESS;
}
static u8_t va_del(u8_t *label_uuid, u16_t *addr)
{
int i;
for (i = 0; i < ARRAY_SIZE(labels); i++) {
if (!memcmp(labels[i].uuid, label_uuid, 16)) {
if (addr) {
*addr = labels[i].addr;
}
labels[i].ref--;
return STATUS_SUCCESS;
}
}
if (addr) {
*addr = BT_MESH_ADDR_UNASSIGNED;
}
return STATUS_CANNOT_REMOVE;
}
static void mod_sub_list_clear(struct bt_mesh_model *mod)
{
u8_t *label_uuid;
int i;
/* Unref stored labels related to this model */
for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
if (!BT_MESH_ADDR_IS_VIRTUAL(mod->groups[i])) {
continue;
}
label_uuid = bt_mesh_label_uuid_get(mod->groups[i]);
if (!label_uuid) {
BT_ERR("Label UUID not found");
continue;
}
va_del(label_uuid, NULL);
}
/* Clear all subscriptions (0x0000 is the unassigned address) */
memset(mod->groups, 0, sizeof(mod->groups));
}
static void mod_pub_va_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
@@ -1226,6 +1258,12 @@ send_status:
status, mod_id);
}
#else
static void mod_sub_list_clear(struct bt_mesh_model *mod)
{
/* Clear all subscriptions (0x0000 is the unassigned address) */
memset(mod->groups, 0, sizeof(mod->groups));
}
static void mod_pub_va_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
@@ -1464,8 +1502,7 @@ static void mod_sub_overwrite(struct bt_mesh_model *model,
bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups));
}
/* Clear all subscriptions (0x0000 is the unassigned address) */
memset(mod->groups, 0, sizeof(mod->groups));
mod_sub_list_clear(mod);
if (ARRAY_SIZE(mod->groups) > 0) {
mod->groups[0] = sub_addr;
@@ -1519,8 +1556,7 @@ static void mod_sub_del_all(struct bt_mesh_model *model,
bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups));
}
/* Clear all subscriptions (0x0000 is the unassigned address) */
memset(mod->groups, 0, sizeof(mod->groups));
mod_sub_list_clear(mod);
status = STATUS_SUCCESS;
@@ -1750,12 +1786,15 @@ static void mod_sub_va_del(struct bt_mesh_model *model,
goto send_status;
}
sub_addr = va_find(label_uuid, NULL);
status = va_del(label_uuid, &sub_addr);
if (sub_addr == BT_MESH_ADDR_UNASSIGNED) {
status = STATUS_CANNOT_REMOVE;
goto send_status;
}
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
bt_mesh_lpn_group_del(&sub_addr, 1);
}
match = bt_mesh_model_find_group(mod, sub_addr);
if (match) {
*match = BT_MESH_ADDR_UNASSIGNED;
@@ -1807,8 +1846,7 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model,
bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups));
}
/* Clear all subscriptions (0x0000 is the unassigned address) */
memset(mod->groups, 0, sizeof(mod->groups));
mod_sub_list_clear(mod);
if (ARRAY_SIZE(mod->groups) > 0) {
status = va_add(label_uuid, &sub_addr);
@@ -2359,6 +2397,10 @@ static void mod_app_bind(struct bt_mesh_model *model,
status = mod_bind(mod, key_app_idx);
if (IS_ENABLED(CONFIG_BT_TESTING) && status == STATUS_SUCCESS) {
bt_test_mesh_model_bound(ctx->addr, mod, key_app_idx);
}
send_status:
BT_DBG("status 0x%02x", status);
create_mod_app_status(msg, mod, vnd, elem_addr, key_app_idx, status,
@@ -2403,6 +2445,10 @@ static void mod_app_unbind(struct bt_mesh_model *model,
status = mod_unbind(mod, key_app_idx);
if (IS_ENABLED(CONFIG_BT_TESTING) && status == STATUS_SUCCESS) {
bt_test_mesh_model_unbound(ctx->addr, mod, key_app_idx);
}
send_status:
BT_DBG("status 0x%02x", status);
create_mod_app_status(msg, mod, vnd, elem_addr, key_app_idx, status,
@@ -2860,7 +2906,7 @@ static void heartbeat_pub_set(struct bt_mesh_model *model,
cfg->hb_pub.dst = dst;
cfg->hb_pub.period = param->period_log;
cfg->hb_pub.feat = feat;
cfg->hb_pub.feat = feat & BT_MESH_FEAT_SUPPORTED;
cfg->hb_pub.net_idx = idx;
if (dst == BT_MESH_ADDR_UNASSIGNED) {
+16 -16
View File
@@ -175,14 +175,14 @@ static void friend_clear(struct bt_mesh_friend *frnd)
frnd->last = NULL;
}
while (!sys_slist_is_empty(&frnd->queue)) {
while (!net_buf_slist_is_empty(&frnd->queue)) {
net_buf_unref(net_buf_slist_get(&frnd->queue));
}
for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
struct bt_mesh_friend_seg *seg = &frnd->seg[i];
while (!sys_slist_is_empty(&seg->queue)) {
while (!net_buf_slist_is_empty(&seg->queue)) {
net_buf_unref(net_buf_slist_get(&seg->queue));
}
}
@@ -592,7 +592,7 @@ int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
frnd->fsn = msg->fsn;
if (sys_slist_is_empty(&frnd->queue)) {
if (net_buf_slist_is_empty(&frnd->queue)) {
enqueue_update(frnd, 0);
BT_DBG("Enqueued Friend Update to empty queue");
}
@@ -894,7 +894,7 @@ static struct bt_mesh_friend_seg *get_seg(struct bt_mesh_friend *frnd,
for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
struct bt_mesh_friend_seg *seg = &frnd->seg[i];
struct os_mbuf *buf = (void *)sys_slist_peek_head(&seg->queue);
struct os_mbuf *buf = (void *)net_buf_slist_peek_head(&seg->queue);
if (buf && BT_MESH_ADV(buf)->addr == src &&
FRIEND_ADV(buf)->seq_auth == *seq_auth) {
@@ -948,14 +948,14 @@ static void enqueue_friend_pdu(struct bt_mesh_friend *frnd,
* the SeqAuth information from the segments before merging.
*/
struct os_mbuf *m;
struct os_mbuf_pkthdr *mp;
SYS_SLIST_FOR_EACH_CONTAINER(&seg->queue, mp,) {
m = OS_MBUF_PKTHDR_TO_MBUF(mp);
struct os_mbuf_pkthdr *pkthdr;
NET_BUF_SLIST_FOR_EACH_NODE(&seg->queue, pkthdr) {
m = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
FRIEND_ADV(m)->seq_auth = TRANS_SEQ_AUTH_NVAL;
frnd->queue_size++;
}
sys_slist_merge_slist(&frnd->queue, &seg->queue);
net_buf_slist_merge_slist(&frnd->queue, &seg->queue);
}
}
@@ -1058,7 +1058,7 @@ int bt_mesh_friend_init(void)
frnd->net_idx = BT_MESH_KEY_UNUSED;
sys_slist_init(&frnd->queue);
net_buf_slist_init(&frnd->queue);
k_delayed_work_init(&frnd->timer, friend_timeout);
k_delayed_work_add_arg(&frnd->timer, frnd);
@@ -1066,7 +1066,7 @@ int bt_mesh_friend_init(void)
k_delayed_work_add_arg(&frnd->clear.timer, frnd);
for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) {
sys_slist_init(&frnd->seg[j].queue);
net_buf_slist_init(&frnd->seg[j].queue);
}
}
@@ -1076,19 +1076,19 @@ int bt_mesh_friend_init(void)
static void friend_purge_old_ack(struct bt_mesh_friend *frnd, u64_t *seq_auth,
u16_t src)
{
sys_snode_t *cur, *prev = NULL;
struct os_mbuf *cur, *prev = NULL;
BT_DBG("SeqAuth %llx src 0x%04x", *seq_auth, src);
for (cur = sys_slist_peek_head(&frnd->queue);
cur != NULL; prev = cur, cur = sys_slist_peek_next(cur)) {
for (cur = net_buf_slist_peek_head(&frnd->queue);
cur != NULL; prev = cur, cur = net_buf_slist_peek_next(cur)) {
struct os_mbuf *buf = (void *)cur;
if (BT_MESH_ADV(buf)->addr == src &&
FRIEND_ADV(buf)->seq_auth == *seq_auth) {
BT_DBG("Removing old ack from Friend Queue");
sys_slist_remove(&frnd->queue, prev, cur);
net_buf_slist_remove(&frnd->queue, prev, cur);
frnd->queue_size--;
net_buf_unref(buf);
@@ -1304,7 +1304,7 @@ void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, u16_t src,
struct bt_mesh_friend_seg *seg = &frnd->seg[j];
struct os_mbuf *buf;
buf = (void *)sys_slist_peek_head(&seg->queue);
buf = (void *)net_buf_slist_peek_head(&seg->queue);
if (!buf) {
continue;
}
@@ -1319,7 +1319,7 @@ void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, u16_t src,
BT_WARN("Clearing incomplete segments for 0x%04x", src);
while (!sys_slist_is_empty(&seg->queue)) {
while (!net_buf_slist_is_empty(&seg->queue)) {
net_buf_unref(net_buf_slist_get(&seg->queue));
}
}
+89
View File
@@ -505,3 +505,92 @@ bt_mesh_register_gatt(void)
bt_mesh_proxy_svcs_register();
#endif
}
void net_buf_slist_init(struct net_buf_slist_t *list)
{
STAILQ_INIT(list);
}
bool net_buf_slist_is_empty(struct net_buf_slist_t *list)
{
return STAILQ_EMPTY(list);
}
struct os_mbuf *net_buf_slist_peek_head(struct net_buf_slist_t *list)
{
struct os_mbuf_pkthdr *pkthdr;
/* Get mbuf pointer from packet header pointer */
pkthdr = STAILQ_FIRST(list);
if (!pkthdr) {
return NULL;
}
return OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
}
struct os_mbuf *net_buf_slist_peek_next(struct os_mbuf *buf)
{
struct os_mbuf_pkthdr *pkthdr;
/* Get mbuf pointer from packet header pointer */
pkthdr = OS_MBUF_PKTHDR(buf);
pkthdr = STAILQ_NEXT(pkthdr, omp_next);
if (!pkthdr) {
return NULL;
}
return OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
}
struct os_mbuf *net_buf_slist_get(struct net_buf_slist_t *list)
{
os_sr_t sr;
struct os_mbuf *m;
m = net_buf_slist_peek_head(list);
if (!m) {
return NULL;
}
/* Remove from queue */
OS_ENTER_CRITICAL(sr);
STAILQ_REMOVE_HEAD(list, omp_next);
OS_EXIT_CRITICAL(sr);
return m;
}
void net_buf_slist_put(struct net_buf_slist_t *list, struct os_mbuf *buf)
{
struct os_mbuf_pkthdr *pkthdr;
pkthdr = OS_MBUF_PKTHDR(buf);
STAILQ_INSERT_TAIL(list, pkthdr, omp_next);
}
void net_buf_slist_remove(struct net_buf_slist_t *list, struct os_mbuf *prev,
struct os_mbuf *cur)
{
struct os_mbuf_pkthdr *pkthdr, *cur_pkthdr;
cur_pkthdr = OS_MBUF_PKTHDR(cur);
STAILQ_FOREACH(pkthdr, list, omp_next) {
if (cur_pkthdr == pkthdr) {
STAILQ_REMOVE(list, cur_pkthdr, os_mbuf_pkthdr, omp_next);
break;
}
}
}
void net_buf_slist_merge_slist(struct net_buf_slist_t *list,
struct net_buf_slist_t *list_to_append)
{
struct os_mbuf_pkthdr *pkthdr;
STAILQ_FOREACH(pkthdr, list_to_append, omp_next) {
STAILQ_INSERT_TAIL(list, pkthdr, omp_next);
}
STAILQ_INIT(list);
}
+2 -1
View File
@@ -75,7 +75,7 @@ static u16_t msg_cache_next;
/* Singleton network context (the implementation only supports one) */
struct bt_mesh_net bt_mesh = {
.local_queue = SYS_SLIST_STATIC_INIT(bt_mesh.local_queue),
.local_queue = STAILQ_HEAD_INITIALIZER(bt_mesh.local_queue),
.sub = {
[0 ... (MYNEWT_VAL(BLE_MESH_SUBNET_COUNT) - 1)] = {
.net_idx = BT_MESH_KEY_UNUSED,
@@ -1351,4 +1351,5 @@ void bt_mesh_net_init(void)
k_delayed_work_init(&bt_mesh.ivu_complete, ivu_complete);
k_work_init(&bt_mesh.local_work, bt_mesh_net_local);
net_buf_slist_init(&bt_mesh.local_queue);
}
+4 -4
View File
@@ -22,7 +22,7 @@
#include <stdbool.h>
#include "mesh/mesh.h"
#include "mesh/slist.h"
#include "mesh/glue.h"
struct bt_mesh_app_key {
u16_t net_idx;
@@ -103,12 +103,12 @@ struct bt_mesh_friend {
struct k_delayed_work timer;
struct bt_mesh_friend_seg {
sys_slist_t queue;
struct net_buf_slist_t queue;
} seg[FRIEND_SEG_RX];
struct os_mbuf *last;
sys_slist_t queue;
struct net_buf_slist_t queue;
u32_t queue_size;
/* Friend Clear Procedure */
@@ -201,7 +201,7 @@ struct bt_mesh_net {
/* Local network interface */
struct os_callout local_work;
sys_slist_t local_queue;
struct net_buf_slist_t local_queue;
#if MYNEWT_VAL(BLE_MESH_FRIEND)
/* Friend state, unique for each LPN that we're Friends for */
+6
View File
@@ -26,6 +26,7 @@
#include "foundation.h"
#include "proxy.h"
#include "prov.h"
#include "testing.h"
/* 3 transmissions, 20ms interval */
#define PROV_XMIT_COUNT 2
@@ -1236,6 +1237,11 @@ static void gen_prov_ctl(struct prov_rx *rx, struct os_mbuf *buf)
break;
default:
BT_ERR("Unknown bearer opcode: 0x%02x", BEARER_CTL(rx->gpc));
if (IS_ENABLED(CONFIG_BT_TESTING)) {
bt_test_mesh_prov_invalid_bearer(BEARER_CTL(rx->gpc));
}
return;
}
}
+1 -1
View File
@@ -1627,7 +1627,7 @@ static int cmd_provision(int argc, char *argv[])
addr = strtoul(argv[2], NULL, 0);
if (argc > 3) {
iv_index = strtoul(argv[1], NULL, 0);
iv_index = strtoul(argv[3], NULL, 0);
} else {
iv_index = 0;
}
-323
View File
@@ -1,323 +0,0 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <stdbool.h>
#include "mesh/slist.h"
#include "os/queue.h"
#include "os/os.h"
#include "os/os_mbuf.h"
/**
* @brief Initialize a list
*
* @param list A pointer on the list to initialize
*/
void sys_slist_init(sys_slist_t *list)
{
STAILQ_INIT(list);
}
/**
* @brief Test if the given list is empty
*
* @param list A pointer on the list to test
*
* @return a boolean, true if it's empty, false otherwise
*/
bool sys_slist_is_empty(sys_slist_t *list)
{
return STAILQ_EMPTY(list);
}
/**
* @brief Peek the first node from the list
*
* @param list A point on the list to peek the first node from
*
* @return A pointer on the first node of the list (or NULL if none)
*/
sys_snode_t *sys_slist_peek_head(sys_slist_t *list)
{
struct os_mbuf_pkthdr *mp;
struct os_mbuf *m;
mp = STAILQ_FIRST(list);
if (mp) {
m = OS_MBUF_PKTHDR_TO_MBUF(mp);
} else {
m = NULL;
}
return m;
}
/**
* @brief Peek the last node from the list
*
* @param list A point on the list to peek the last node from
*
* @return A pointer on the last node of the list (or NULL if none)
*/
sys_snode_t *sys_slist_peek_tail(sys_slist_t *list)
{
struct os_mbuf_pkthdr *mp;
struct os_mbuf *m;
mp = STAILQ_LAST(list, os_mbuf_pkthdr, omp_next);
if (mp) {
m = OS_MBUF_PKTHDR_TO_MBUF(mp);
} else {
m = NULL;
}
return m;
}
/**
* @brief Peek the next node from current node, node is not NULL
*
* Faster then sys_slist_peek_next() if node is known not to be NULL.
*
* @param node A pointer on the node where to peek the next node
*
* @return a pointer on the next node (or NULL if none)
*/
sys_snode_t *sys_slist_peek_next_no_check(sys_snode_t *node)
{
struct os_mbuf_pkthdr *mp;
struct os_mbuf *m;
mp = OS_MBUF_PKTHDR(node);
if (!mp) {
return NULL;
}
mp = STAILQ_NEXT(mp, omp_next);
if (mp) {
m = OS_MBUF_PKTHDR_TO_MBUF(mp);
} else {
m = NULL;
}
return m;
}
/**
* @brief Peek the next node from current node
*
* @param node A pointer on the node where to peek the next node
*
* @return a pointer on the next node (or NULL if none)
*/
sys_snode_t *sys_slist_peek_next(sys_snode_t *node)
{
return node ? sys_slist_peek_next_no_check(node) : NULL;
}
/**
* @brief Prepend a node to the given list
*
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
* @param node A pointer on the node to prepend
*/
void sys_slist_prepend(sys_slist_t *list,
sys_snode_t *node)
{
struct os_mbuf_pkthdr *mp;
mp = OS_MBUF_PKTHDR(node);
if (!mp) {
return;
}
STAILQ_INSERT_HEAD(list, mp, omp_next);
}
/**
* @brief Append a node to the given list
*
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
* @param node A pointer on the node to append
*/
void sys_slist_append(sys_slist_t *list,
sys_snode_t *node)
{
struct os_mbuf_pkthdr *mp;
mp = OS_MBUF_PKTHDR(node);
if (!mp) {
return;
}
STAILQ_INSERT_TAIL(list, mp, omp_next);
}
/**
* @brief Append a list to the given list
*
* Append a singly-linked, NULL-terminated list consisting of nodes containing
* the pointer to the next node as the first element of a node, to @a list.
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
* @param head A pointer to the first element of the list to append
* @param tail A pointer to the last element of the list to append
*/
void sys_slist_append_list(sys_slist_t *list,
sys_slist_t *list_append)
{
struct os_mbuf_pkthdr *mp;
STAILQ_FOREACH(mp, list_append, omp_next) {
STAILQ_INSERT_TAIL(list, mp, omp_next);
}
}
/**
* @brief merge two slists, appending the second one to the first
*
* When the operation is completed, the appending list is empty.
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
* @param list_to_append A pointer to the list to append.
*/
void sys_slist_merge_slist(sys_slist_t *list,
sys_slist_t *list_to_append)
{
sys_slist_append_list(list, list_to_append);
sys_slist_init(list_to_append);
}
/**
* @brief Insert a node to the given list
*
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
* @param prev A pointer on the previous node
* @param node A pointer on the node to insert
*/
void sys_slist_insert(sys_slist_t *list,
sys_snode_t *prev,
sys_snode_t *node)
{
struct os_mbuf_pkthdr *mp, *mp_prev;
if (!prev) {
sys_slist_prepend(list, node);
} else {
mp_prev = OS_MBUF_PKTHDR(prev);
mp = OS_MBUF_PKTHDR(node);
STAILQ_INSERT_AFTER(list, mp_prev, mp, omp_next);
}
}
/**
* @brief Fetch and remove the first node of the given list
*
* List must be known to be non-empty.
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
*
* @return A pointer to the first node of the list
*/
sys_snode_t *sys_slist_get_not_empty(sys_slist_t *list)
{
struct os_mbuf_pkthdr *mp;
struct os_mbuf *m;
mp = STAILQ_FIRST(list);
m = OS_MBUF_PKTHDR_TO_MBUF(mp);
STAILQ_REMOVE_HEAD(list, omp_next);
return m;
}
/**
* @brief Fetch and remove the first node of the given list
*
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
*
* @return A pointer to the first node of the list (or NULL if empty)
*/
sys_snode_t *sys_slist_get(sys_slist_t *list)
{
return sys_slist_is_empty(list) ? NULL : sys_slist_get_not_empty(list);
}
/**
* @brief Remove a node
*
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
* @param prev_node A pointer on the previous node
* (can be NULL, which means the node is the list's head)
* @param node A pointer on the node to remove
*/
void sys_slist_remove(sys_slist_t *list,
sys_snode_t *prev_node,
sys_snode_t *node)
{
struct os_mbuf_pkthdr *mp;
mp = OS_MBUF_PKTHDR(node);
STAILQ_REMOVE(list, mp, os_mbuf_pkthdr, omp_next);
}
/**
* @brief Find and remove a node from a list
*
* This and other sys_slist_*() functions are not thread safe.
*
* @param list A pointer on the list to affect
* @param node A pointer on the node to remove from the list
*
* @return true if node was removed
*/
bool sys_slist_find_and_remove(sys_slist_t *list,
sys_snode_t *node)
{
sys_snode_t *prev = NULL;
sys_snode_t *test;
SYS_SLIST_FOR_EACH_NODE(list, test) {
if (test == node) {
sys_slist_remove(list, prev, node);
return true;
}
prev = test;
}
return false;
}
void net_buf_slist_put(sys_slist_t *list, struct os_mbuf *buf)
{
sys_slist_append(list, buf);
}
struct os_mbuf *net_buf_slist_get(sys_slist_t *list)
{
return sys_slist_get(list);
}
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include "mesh/testing.h"
#include "mesh/slist.h"
#include "mesh/glue.h"
#include "mesh/access.h"
#include "net.h"
#include "testing.h"
static sys_slist_t cb_slist;
void bt_test_cb_register(struct bt_test_cb *cb)
{
sys_slist_append(&cb_slist, &cb->node);
}
void bt_test_cb_unregister(struct bt_test_cb *cb)
{
sys_slist_find_and_remove(&cb_slist, &cb->node);
}
void bt_test_mesh_net_recv(u8_t ttl, u8_t ctl, u16_t src, u16_t dst,
const void *payload, size_t payload_len)
{
struct bt_test_cb *cb;
SYS_SLIST_FOR_EACH_CONTAINER(&cb_slist, cb, node) {
if (cb->mesh_net_recv) {
cb->mesh_net_recv(ttl, ctl, src, dst, payload,
payload_len);
}
}
}
void bt_test_mesh_model_bound(u16_t addr, struct bt_mesh_model *model,
u16_t key_idx)
{
struct bt_test_cb *cb;
SYS_SLIST_FOR_EACH_CONTAINER(&cb_slist, cb, node) {
if (cb->mesh_model_bound) {
cb->mesh_model_bound(addr, model, key_idx);
}
}
}
void bt_test_mesh_model_unbound(u16_t addr, struct bt_mesh_model *model,
u16_t key_idx)
{
struct bt_test_cb *cb;
SYS_SLIST_FOR_EACH_CONTAINER(&cb_slist, cb, node) {
if (cb->mesh_model_unbound) {
cb->mesh_model_unbound(addr, model, key_idx);
}
}
}
void bt_test_mesh_prov_invalid_bearer(u8_t opcode)
{
struct bt_test_cb *cb;
SYS_SLIST_FOR_EACH_CONTAINER(&cb_slist, cb, node) {
if (cb->mesh_prov_invalid_bearer) {
cb->mesh_prov_invalid_bearer(opcode);
}
}
}
void bt_test_mesh_trans_incomp_timer_exp(void)
{
struct bt_test_cb *cb;
SYS_SLIST_FOR_EACH_CONTAINER(&cb_slist, cb, node) {
if (cb->mesh_trans_incomp_timer_exp) {
cb->mesh_trans_incomp_timer_exp();
}
}
}
+22
View File
@@ -0,0 +1,22 @@
/**
* @file testing.h
* @brief Internal API for Bluetooth testing.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "mesh/glue.h"
#include "mesh/access.h"
void bt_test_mesh_model_bound(u16_t addr, struct bt_mesh_model *model,
u16_t key_idx);
void bt_test_mesh_model_unbound(u16_t addr, struct bt_mesh_model *model,
u16_t key_idx);
void bt_test_mesh_prov_invalid_bearer(u8_t opcode);
void bt_test_mesh_net_recv(u8_t ttl, u8_t ctl, u16_t src, u16_t dst,
const void *payload, size_t payload_len);
void bt_test_mesh_trans_incomp_timer_exp(void);
+64 -25
View File
@@ -25,6 +25,7 @@
#include "access.h"
#include "foundation.h"
#include "transport.h"
#include "testing.h"
#define AID_MASK ((u8_t)(BIT_MASK(6)))
@@ -42,9 +43,6 @@
#define SEQ_AUTH(iv_index, seq) (((u64_t)iv_index) << 24 | (u64_t)seq)
/* Retransmit timeout after which to retransmit unacked segments */
#define SEG_RETRANSMIT_TIMEOUT K_MSEC(400)
/* Number of retransmit attempts (after the initial transmit) per segment */
#define SEG_RETRANSMIT_ATTEMPTS 4
@@ -59,6 +57,7 @@ static struct seg_tx {
u8_t seg_n:5, /* Last segment index */
new_key:1; /* New/old key */
u8_t nack_count; /* Number of unacked segs */
u8_t ttl;
const struct bt_mesh_send_cb *cb;
void *cb_data;
struct k_delayed_work retransmit; /* Retransmit timer */
@@ -204,8 +203,16 @@ static void seg_send_start(u16_t duration, int err, void *user_data)
static void seg_sent(int err, void *user_data)
{
struct seg_tx *tx = user_data;
s32_t timeout;
k_delayed_work_submit(&tx->retransmit, SEG_RETRANSMIT_TIMEOUT);
/* "This timer shall be set to a minimum of 200 + 50 * TTL
* milliseconds.". We use 400 since 300 is a common send
* duration for standard HCI, and we need to have a timeout
* that's bigger than that.
*/
timeout = K_MSEC(400) + 50 * tx->ttl;
k_delayed_work_submit(&tx->retransmit, timeout);
}
static const struct bt_mesh_send_cb first_sent_cb = {
@@ -307,6 +314,12 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct os_mbuf *sdu,
tx->cb = cb;
tx->cb_data = cb_data;
if (net_tx->ctx->send_ttl == BT_MESH_TTL_DEFAULT) {
tx->ttl = bt_mesh_default_ttl_get();
} else {
tx->ttl = net_tx->ctx->send_ttl;
}
seq_zero = tx->seq_auth & 0x1fff;
BT_DBG("SeqZero 0x%04x", seq_zero);
@@ -846,11 +859,18 @@ static int trans_unseg(struct os_mbuf *buf, struct bt_mesh_net_rx *rx,
static inline s32_t ack_timeout(struct seg_rx *rx)
{
s32_t to;
u8_t ttl;
if (rx->ttl == BT_MESH_TTL_DEFAULT) {
ttl = bt_mesh_default_ttl_get();
} else {
ttl = rx->ttl;
}
/* The acknowledgment timer shall be set to a minimum of
* 150 + 50 * TTL milliseconds.
*/
to = K_MSEC(150 + (50 * rx->ttl));
to = K_MSEC(150 + (50 * ttl));
/* 100 ms for every not yet received segment */
to += K_MSEC(((rx->seg_n + 1) - popcount(rx->block)) * 100);
@@ -940,7 +960,7 @@ static int send_ack(struct bt_mesh_subnet *sub, u16_t src, u16_t dst,
NULL, NULL, NULL);
}
static void seg_rx_reset(struct seg_rx *rx)
static void seg_rx_reset(struct seg_rx *rx, bool full_reset)
{
BT_DBG("rx %p", rx);
@@ -953,12 +973,18 @@ static void seg_rx_reset(struct seg_rx *rx)
&rx->seq_auth);
}
/* We don't reset rx->net and rx->seq_auth here since we need to
* be able to send an ack if we receive a segment after we've
* already received the full SDU.
*/
rx->in_use = 0;
/* We don't always reset these values since we need to be able to
* send an ack if we receive a segment after we've already received
* the full SDU.
*/
if (full_reset) {
rx->seq_auth = 0;
rx->sub = NULL;
rx->src = BT_MESH_ADDR_UNASSIGNED;
rx->dst = BT_MESH_ADDR_UNASSIGNED;
}
}
static void seg_ack(struct os_event *work)
@@ -967,11 +993,16 @@ static void seg_ack(struct os_event *work)
BT_DBG("rx %p", rx);
if (k_uptime_get_32() - rx->last > (60 * MSEC_PER_SEC)) {
if (k_uptime_get_32() - rx->last > K_SECONDS(60)) {
BT_WARN("Incomplete timer expired");
send_ack(rx->sub, rx->dst, rx->src, rx->ttl,
&rx->seq_auth, 0, rx->obo);
seg_rx_reset(rx);
seg_rx_reset(rx, true);
if (IS_ENABLED(CONFIG_BT_TESTING)) {
bt_test_mesh_trans_incomp_timer_exp();
}
return;
}
@@ -1007,7 +1038,10 @@ static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx,
continue;
}
if (rx->seq_auth == *seq_auth) {
/* Return newer RX context in addition to an exact match, so
* the calling function can properly discard an old SeqAuth.
*/
if (rx->seq_auth >= *seq_auth) {
return rx;
}
@@ -1018,7 +1052,7 @@ static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx,
/* Clear out the old context since the sender
* has apparently started sending a new SDU.
*/
seg_rx_reset(rx);
seg_rx_reset(rx, true);
/* Return non-match so caller can re-allocate */
return NULL;
@@ -1122,6 +1156,12 @@ static int trans_seg(struct os_mbuf *buf, struct bt_mesh_net_rx *net_rx,
/* Look for old RX sessions */
rx = seg_rx_find(net_rx, seq_auth);
if (rx) {
/* Discard old SeqAuth packet */
if (rx->seq_auth > *seq_auth) {
BT_WARN("Ignoring old SeqAuth");
return -EINVAL;
}
if (!seg_rx_is_valid(rx, net_rx, hdr, seg_n)) {
return -EINVAL;
}
@@ -1189,7 +1229,7 @@ found_rx:
BT_ERR("Too large SDU len");
send_ack(net_rx->sub, net_rx->dst, net_rx->ctx.addr,
net_rx->ctx.send_ttl, seq_auth, 0, rx->obo);
seg_rx_reset(rx);
seg_rx_reset(rx, true);
return -EMSGSIZE;
}
} else {
@@ -1245,7 +1285,7 @@ found_rx:
err = sdu_recv(net_rx, *hdr, ASZMIC(hdr), rx->buf);
}
seg_rx_reset(rx);
seg_rx_reset(rx, false);
return err;
}
@@ -1272,6 +1312,11 @@ int bt_mesh_trans_recv(struct os_mbuf *buf, struct bt_mesh_net_rx *rx)
BT_DBG("Payload %s", bt_hex(buf->om_data, buf->om_len));
if (IS_ENABLED(CONFIG_BT_TESTING)) {
bt_test_mesh_net_recv(rx->ctx.recv_ttl, rx->ctl, rx->ctx.addr,
rx->dst, buf->om_data, buf->om_len);
}
/* If LPN mode is enabled messages are only accepted when we've
* requested the Friend to send them. The messages must also
* be encrypted using the Friend Credentials.
@@ -1307,16 +1352,12 @@ int bt_mesh_trans_recv(struct os_mbuf *buf, struct bt_mesh_net_rx *rx)
* bt_mesh_lpn_waiting_update() function will return false:
* we still need to go through the actual sending to the bearer and
* wait for ReceiveDelay before transitioning to WAIT_UPDATE state.
*
* Another situation where we want to notify the LPN state machine
* is if it's configured to use an automatic Friendship establishment
* timer, in which case we want to reset the timer at this point.
*
* ENOENT is a special condition that's only used to indicate that
* the Transport OpCode was invalid, in which case we should ignore
* the PDU completely, as per MESH/NODE/FRND/LPN/BI-02-C.
*/
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && err != -ENOENT &&
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) &&
(bt_mesh_lpn_timer() ||
(bt_mesh_lpn_established() && bt_mesh_lpn_waiting_update()))) {
bt_mesh_lpn_msg_received(rx);
@@ -1342,9 +1383,7 @@ void bt_mesh_rx_reset(void)
BT_DBG("");
for (i = 0; i < ARRAY_SIZE(seg_rx); i++) {
seg_rx_reset(&seg_rx[i]);
seg_rx[i].src = BT_MESH_ADDR_UNASSIGNED;
seg_rx[i].dst = BT_MESH_ADDR_UNASSIGNED;
seg_rx_reset(&seg_rx[i], true);
}
}
+5
View File
@@ -371,6 +371,11 @@ syscfg.defs:
Procedure and lets the state be changed at any time.
value: 0
BLE_MESH_TESTING:
description: >
This option enables testing API.
value: 0
BLE_MESH_DEV_UUID:
description: >
Device UUID