<commit_before>// Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string.h>
#include <errno.h>

#include "mesh.h"
#include "mesh_main.h"
#include "transport.h"
#include "foundation.h"
#include "client_common.h"
#include "mesh_common.h"

#define UNSEG_ACCESS_MSG_MAX_LEN    11  /* 11 octets (Opcode + Payload), 4 octets TransMIC */
#define SEG_ACCESS_MSG_SEG_LEN      12  /* 12 * 32 = 384 octets (Opcode + Payload + TransMIC) */
#define HCI_TIME_FOR_START_ADV      K_MSEC(5)   /* Three adv related hci commands may take 4 ~ 5ms */

static bt_mesh_client_node_t *bt_mesh_client_pick_node(sys_slist_t *list, u16_t tx_dst)
{
    bt_mesh_client_node_t *node = NULL;
    sys_snode_t *cur = NULL;

    bt_mesh_list_lock();
    if (sys_slist_is_empty(list)) {
        bt_mesh_list_unlock();
        return NULL;
    }

    for (cur = sys_slist_peek_head(list);
            cur != NULL; cur = sys_slist_peek_next(cur)) {
        node = (bt_mesh_client_node_t *)cur;
        if (node->ctx.addr == tx_dst) {
            bt_mesh_list_unlock();
            return node;
        }
    }

    bt_mesh_list_unlock();
    return NULL;
}

bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(
    struct bt_mesh_model *model,
    struct bt_mesh_msg_ctx *ctx,
    struct net_buf_simple *buf, bool need_pub)
{
    bt_mesh_client_internal_data_t *data = NULL;
    bt_mesh_client_user_data_t *cli = NULL;
    bt_mesh_client_node_t *node = NULL;

    if (!model || !ctx || !buf) {
        BT_ERR("%s, Invalid parameter", __func__);
        return NULL;
    }

    cli = (bt_mesh_client_user_data_t *)model->user_data;
    if (!cli) {
        BT_ERR("%s, Clinet user_data is NULL", __func__);
        return NULL;
    }

    /** If the received message address is not a unicast address,
     *  the address may be a group/virtual address, and we push
     *  this message to the application layer.
     */
    if (!BLE_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) {
        BT_DBG("Unexpected status message 0x%x", ctx->recv_op);
        if (cli->publish_status && need_pub) {
            cli->publish_status(ctx->recv_op, model, ctx, buf);
        }
        return NULL;
    }

    /** If the source address of the received status message is
     *  different with the destination address of the sending
     *  message, then the message is from another element and
     *  push it to application layer.
     */
    data = (bt_mesh_client_internal_data_t *)cli->internal_data;
    if (!data) {
        BT_ERR("%s, Client internal_data is NULL", __func__);
        return NULL;
    }

    if ((node = bt_mesh_client_pick_node(&data->queue, ctx->addr)) == NULL) {
        BT_DBG("Unexpected status message 0x%x", ctx->recv_op);
        if (cli->publish_status && need_pub) {
            cli->publish_status(ctx->recv_op, model, ctx, buf);
        }
        return NULL;
    }

    if (node->op_pending != ctx->recv_op) {
        BT_DBG("Unexpected status message 0x%x", ctx->recv_op);
        if (cli->publish_status && need_pub) {
            cli->publish_status(ctx->recv_op, model, ctx, buf);
        }
        return NULL;
    }

    if (k_delayed_work_remaining_get(&node->timer) == 0) {
        BT_DBG("Unexpected status message 0x%x", ctx->recv_op);
        if (cli->publish_status && need_pub) {
            cli->publish_status(ctx->recv_op, model, ctx, buf);
        }
        return NULL;
    }

    return node;
}

static bool bt_mesh_client_check_node_in_list(sys_slist_t *list, u16_t tx_dst)
{
    bt_mesh_client_node_t *node = NULL;
    sys_snode_t *cur = NULL;

    bt_mesh_list_lock();
    if (sys_slist_is_empty(list)) {
        bt_mesh_list_unlock();
        return false;
    }

    for (cur = sys_slist_peek_head(list);
            cur != NULL; cur = sys_slist_peek_next(cur)) {
        node = (bt_mesh_client_node_t *)cur;
        if (node->ctx.addr == tx_dst) {
            bt_mesh_list_unlock();
            return true;
        }
    }

    bt_mesh_list_unlock();
    return false;
}

static u32_t bt_mesh_client_get_status_op(const bt_mesh_client_op_pair_t *op_pair,
        int size, u32_t opcode)
{
    if (!op_pair || size == 0) {
        return 0;
    }

    const bt_mesh_client_op_pair_t *op = op_pair;
    for (int i = 0; i < size; i++) {
        if (op->cli_op == opcode) {
            return op->status_op;
        }
        op++;
    }

    return 0;
}

static s32_t bt_mesh_get_adv_duration(void)
{
    u16_t duration, adv_int;
    u8_t xmit;

    xmit = bt_mesh_net_transmit_get();  /* Network transmit */
    adv_int = BLE_MESH_TRANSMIT_INT(xmit);
    duration = (BLE_MESH_TRANSMIT_COUNT(xmit) + 1) * (adv_int + 10);

    return (s32_t)duration;
}

static s32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx,
                                         struct net_buf_simple *msg,
                                         u32_t opcode, s32_t timeout)
{
    s32_t seg_retrans_to, duration, time;
    u8_t seg_count, seg_retrans_num;
    u8_t mic_size;
    bool need_seg;

    if (msg->len > UNSEG_ACCESS_MSG_MAX_LEN || ctx->send_rel) {
        need_seg = true;    /* Needs segmentation */
    }

    mic_size = (need_seg && net_buf_simple_tailroom(msg) >= 8U) ? 8U : 4U;

    if (need_seg) {
        /* Based on the message length, calculate how many segments are needed.
         * All the messages sent from here are access messages.
         */
        seg_retrans_num = bt_mesh_get_seg_retrans_num();
        seg_retrans_to = bt_mesh_get_seg_retrans_timeout(ctx->send_ttl);
        seg_count = (msg->len + mic_size - 1) / 12U + 1U;

        duration = bt_mesh_get_adv_duration();

        /* Currenlty only consider the time consumption of the same segmented
         * messages, but if there are other messages between any two retrans-
         * missions of the same segmented messages, then the whole time will
         * be longer.
         */
        if (duration + HCI_TIME_FOR_START_ADV < seg_retrans_to) {
            s32_t seg_duration = seg_count * (duration + HCI_TIME_FOR_START_ADV);<commit_msg>ble_mesh: Fix client local parameters not initialized<commit_after>// Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string.h>
#include <errno.h>

#include "mesh.h"
#include "mesh_main.h"
#include "transport.h"
#include "foundation.h"
#include "client_common.h"
#include "mesh_common.h"

#define UNSEG_ACCESS_MSG_MAX_LEN    11  /* 11 octets (Opcode + Payload), 4 octets TransMIC */
#define SEG_ACCESS_MSG_SEG_LEN      12  /* 12 * 32 = 384 octets (Opcode + Payload + TransMIC) */
#define HCI_TIME_FOR_START_ADV      K_MSEC(5)   /* Three adv related hci commands may take 4 ~ 5ms */

static bt_mesh_client_node_t *bt_mesh_client_pick_node(sys_slist_t *list, u16_t tx_dst)
{
    bt_mesh_client_node_t *node = NULL;
    sys_snode_t *cur = NULL;

    bt_mesh_list_lock();
    if (sys_slist_is_empty(list)) {
        bt_mesh_list_unlock();
        return NULL;
    }

    for (cur = sys_slist_peek_head(list);
            cur != NULL; cur = sys_slist_peek_next(cur)) {
        node = (bt_mesh_client_node_t *)cur;
        if (node->ctx.addr == tx_dst) {
            bt_mesh_list_unlock();
            return node;
        }
    }

    bt_mesh_list_unlock();
    return NULL;
}

bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(
    struct bt_mesh_model *model,
    struct bt_mesh_msg_ctx *ctx,
    struct net_buf_simple *buf, bool need_pub)
{
    bt_mesh_client_internal_data_t *data = NULL;
    bt_mesh_client_user_data_t *cli = NULL;
    bt_mesh_client_node_t *node = NULL;

    if (!model || !ctx || !buf) {
        BT_ERR("%s, Invalid parameter", __func__);
        return NULL;
    }

    cli = (bt_mesh_client_user_data_t *)model->user_data;
    if (!cli) {
        BT_ERR("%s, Clinet user_data is NULL", __func__);
        return NULL;
    }

    /** If the received message address is not a unicast address,
     *  the address may be a group/virtual address, and we push
     *  this message to the application layer.
     */
    if (!BLE_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) {
        BT_DBG("Unexpected status message 0x%x", ctx->recv_op);
        if (cli->publish_status && need_pub) {
            cli->publish_status(ctx->recv_op, model, ctx, buf);
        }
        return NULL;
    }

    /** If the source address of the received status message is
     *  different with the destination address of the sending
     *  message, then the message is from another element and
     *  push it to application layer.
     */
    data = (bt_mesh_client_internal_data_t *)cli->internal_data;
    if (!data) {
        BT_ERR("%s, Client internal_data is NULL", __func__);
        return NULL;
    }

    if ((node = bt_mesh_client_pick_node(&data->queue, ctx->addr)) == NULL) {
        BT_DBG("Unexpected status message 0x%x", ctx->recv_op);
        if (cli->publish_status && need_pub) {
            cli->publish_status(ctx->recv_op, model, ctx, buf);
        }
        return NULL;
    }

    if (node->op_pending != ctx->recv_op) {
        BT_DBG("Unexpected status message 0x%x", ctx->recv_op);
        if (cli->publish_status && need_pub) {
            cli->publish_status(ctx->recv_op, model, ctx, buf);
        }
        return NULL;
    }

    if (k_delayed_work_remaining_get(&node->timer) == 0) {
        BT_DBG("Unexpected status message 0x%x", ctx->recv_op);
        if (cli->publish_status && need_pub) {
            cli->publish_status(ctx->recv_op, model, ctx, buf);
        }
        return NULL;
    }

    return node;
}

static bool bt_mesh_client_check_node_in_list(sys_slist_t *list, u16_t tx_dst)
{
    bt_mesh_client_node_t *node = NULL;
    sys_snode_t *cur = NULL;

    bt_mesh_list_lock();
    if (sys_slist_is_empty(list)) {
        bt_mesh_list_unlock();
        return false;
    }

    for (cur = sys_slist_peek_head(list);
            cur != NULL; cur = sys_slist_peek_next(cur)) {
        node = (bt_mesh_client_node_t *)cur;
        if (node->ctx.addr == tx_dst) {
            bt_mesh_list_unlock();
            return true;
        }
    }

    bt_mesh_list_unlock();
    return false;
}

static u32_t bt_mesh_client_get_status_op(const bt_mesh_client_op_pair_t *op_pair,
        int size, u32_t opcode)
{
    if (!op_pair || size == 0) {
        return 0;
    }

    const bt_mesh_client_op_pair_t *op = op_pair;
    for (int i = 0; i < size; i++) {
        if (op->cli_op == opcode) {
            return op->status_op;
        }
        op++;
    }

    return 0;
}

static s32_t bt_mesh_get_adv_duration(void)
{
    u16_t duration, adv_int;
    u8_t xmit;

    xmit = bt_mesh_net_transmit_get();  /* Network transmit */
    adv_int = BLE_MESH_TRANSMIT_INT(xmit);
    duration = (BLE_MESH_TRANSMIT_COUNT(xmit) + 1) * (adv_int + 10);

    return (s32_t)duration;
}

static s32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx,
                                         struct net_buf_simple *msg,
                                         u32_t opcode, s32_t timeout)
{
    s32_t seg_retrans_to = 0, duration = 0, time = 0;
    u8_t seg_count = 0, seg_retrans_num = 0;
    bool need_seg = false;
    u8_t mic_size = 0;

    if (msg->len > UNSEG_ACCESS_MSG_MAX_LEN || ctx->send_rel) {
        need_seg = true;    /* Needs segmentation */
    }

    mic_size = (need_seg && net_buf_simple_tailroom(msg) >= 8U) ? 8U : 4U;

    if (need_seg) {
        /* Based on the message length, calculate how many segments are needed.
         * All the messages sent from here are access messages.
         */
        seg_retrans_num = bt_mesh_get_seg_retrans_num();
        seg_retrans_to = bt_mesh_get_seg_retrans_timeout(ctx->send_ttl);
        seg_count = (msg->len + mic_size - 1) / 12U + 1U;

        duration = bt_mesh_get_adv_duration();

        /* Currenlty only consider the time consumption of the same segmented
         * messages, but if there are other messages between any two retrans-
         * missions of the same segmented messages, then the whole time will
         * be longer.
         */
        if (duration + HCI_TIME_FOR_START_ADV < seg_retrans_to) {
            s32_t seg_duration = seg_count * (duration + HCI_TIME_FOR_START_ADV);
{'fraction_non_alphanumeric': 0.10287693929808706, 'fraction_numerical': 0.01174875734297334, 'mean_word_length': 2.627151051625239, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6814687', 'n_tokens_mistral': 4622, 'n_tokens_neox': 4449, 'n_words': 1140}