411 lines
10 KiB
C
Executable File
411 lines
10 KiB
C
Executable File
/****************************************************************************
|
|
|
|
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
|
|
|
|
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
|
|
be copied by any method or incorporated into another program without
|
|
the express written consent of Aerospace C.Power. This Information or any portion
|
|
thereof remains the property of Aerospace C.Power. The Information contained herein
|
|
is believed to be accurate and Aerospace C.Power assumes no responsibility or
|
|
liability for its use in any way and conveys no license or title under
|
|
any patent or copyright and makes no representation or warranty that this
|
|
Information is free from patent or copyright infringement.
|
|
|
|
****************************************************************************/
|
|
#include "mac_peer.h"
|
|
#include "plc_peer_api.h"
|
|
#include "mac_pdev.h"
|
|
#include "mac_vdev.h"
|
|
#include "mac_desc_engine.h"
|
|
#include "iot_errno.h"
|
|
#include "mac_stream.h"
|
|
#include "iot_queue.h"
|
|
#include "hash_table.h"
|
|
#include "rate_control.h"
|
|
#include "plc_protocol.h"
|
|
#include "iot_io.h"
|
|
#include "os_utils_api.h"
|
|
#include "rf_rate_control.h"
|
|
|
|
mac_peer_t *peer_hash_tbl[peer_tbl_sz] = { 0 };
|
|
|
|
|
|
uint32_t plc_create_peer(pdevid_t pid, vdevid_t vid, tei_t tei)
|
|
{
|
|
(void)pid;
|
|
(void)vid;
|
|
(void)tei;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t plc_free_peer(pdevid_t pid, vdevid_t vid, tei_t tei)
|
|
{
|
|
(void)pid;
|
|
(void)vid;
|
|
(void)tei;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t mac_peer_alloc(mac_vdev_t *vdev, tei_t tei,
|
|
uint32_t is_self, uint32_t is_direct_conn, \
|
|
uint32_t is_sub_peer, uint32_t is_proxy_peer, mac_peer_t **peer)
|
|
{
|
|
mac_peer_t *tmp;
|
|
(void)is_direct_conn;
|
|
uint32_t ret = mac_desc_get(&g_mac_desc_eng, \
|
|
PLC_MAC_PEER_POOL, (void **)&tmp);
|
|
if (ret) {
|
|
mac_vdev_del_overflow_peer(vdev);
|
|
ret = mac_desc_get(&g_mac_desc_eng, \
|
|
PLC_MAC_PEER_POOL, (void **)&tmp);
|
|
}
|
|
if (ret) {
|
|
mac_peer_stream_overflow_cnt_dbglog();
|
|
return ERR_NOMEM;
|
|
}
|
|
else {
|
|
/* init peer */
|
|
os_mem_set(tmp, 0, sizeof(mac_peer_t));
|
|
tmp->pdev_id = vdev->ref_pdev_id;
|
|
tmp->vdev_id = vdev->vdev_id;
|
|
tmp->tei = tei;
|
|
tmp->is_self_peer = is_self & 0x1;
|
|
if (tei == PLC_TEI_BCAST) {
|
|
/* if bcast, should not be self peer */
|
|
IOT_ASSERT(is_self == 0);
|
|
tmp->is_bcast_peer = 1;
|
|
}
|
|
else {
|
|
tmp->is_bcast_peer = 0;
|
|
}
|
|
tmp->next = NULL;
|
|
if (mac_tei_map_is_set((mac_tei_map_t *)vdev->sub_peer_bitmap, tei)) {
|
|
tmp->is_sub_peer = 1;
|
|
} else {
|
|
tmp->is_sub_peer = !!is_sub_peer;
|
|
}
|
|
tmp->is_proxy_peer = !!is_proxy_peer;
|
|
iot_list_init(&tmp->vdev_node);
|
|
/* add into vdev peer list */
|
|
vdev_add_peer(vdev, tmp);
|
|
/* add into peer hash table */
|
|
peer_hash_tbl_add(tmp);
|
|
|
|
/* rate info init */
|
|
mac_rate_ctxt_init(tmp);
|
|
/* rf rate info init */
|
|
mac_rf_rate_ctxt_init(tmp);
|
|
|
|
/* perr cnt ++*/
|
|
vdev->peer_cnt++;
|
|
|
|
if (tmp->is_proxy_peer) {
|
|
vdev->proxy_peer_cnt++;
|
|
}
|
|
|
|
/* return value for the new peer */
|
|
*peer = tmp;
|
|
}
|
|
return ERR_OK;
|
|
}
|
|
|
|
mac_peer_t * IRAM_ATTR find_peer(mac_vdev_t *vdev,
|
|
nid_t nid, tei_t tei)
|
|
{
|
|
mac_peer_t *tmp;
|
|
peer_hash_src_t hash;
|
|
hash.vid = vdev->vdev_id;
|
|
hash.nid = nid;
|
|
hash.tei = tei;
|
|
nid_t tmp_nid;
|
|
|
|
if (!vdev->mac_vdev_cfg.is_reduced_vdev
|
|
&& (ERR_OK == vdev_get_nid(vdev, &tmp_nid))) {
|
|
if (nid != tmp_nid) {
|
|
return NULL;
|
|
}
|
|
uint32_t hash_code = peer_get_hash(hash);
|
|
mac_peer_t **tmp_entry_addr = \
|
|
&peer_hash_tbl[hash_code];
|
|
for (tmp = *tmp_entry_addr; tmp; tmp = tmp->next)
|
|
{
|
|
if (tmp->tei == tei) {
|
|
return tmp;
|
|
}
|
|
}
|
|
} else {
|
|
return vdev->self_peer;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* @return - 0 for successful
|
|
* other for failed
|
|
*/
|
|
uint32_t peer_hash_tbl_add(mac_peer_t *peer)
|
|
{
|
|
nid_t nid;
|
|
|
|
if (!peer) {
|
|
return ERR_INVAL;
|
|
}
|
|
mac_vdev_t *vdev = get_vdev_ptr(peer->pdev_id, peer->vdev_id);
|
|
if (!vdev) {
|
|
return ERR_INVAL;
|
|
}
|
|
|
|
peer_hash_src_t hash = { 0 };
|
|
hash.vid = vdev->vdev_id;
|
|
hash.tei = (tei_t)peer->tei;
|
|
if (ERR_OK != vdev_get_nid(vdev, &nid)) {
|
|
if (peer->is_bcast_peer || peer->is_self_peer) {
|
|
nid = (nid_t)PLC_NID_INVALID;
|
|
} else {
|
|
IOT_ASSERT(0);
|
|
return ERR_INVAL;
|
|
}
|
|
}
|
|
hash.nid = nid;
|
|
|
|
if (find_peer(vdev, \
|
|
hash.nid, hash.tei)) {
|
|
/* if already exist */
|
|
return ERR_EXIST;
|
|
}
|
|
uint32_t hash_code = peer_get_hash(hash);
|
|
mac_peer_t **peer_entry = \
|
|
&peer_hash_tbl[hash_code];
|
|
if ( *peer_entry == NULL)
|
|
{
|
|
*peer_entry = peer;
|
|
}
|
|
else {
|
|
peer->next = *peer_entry;
|
|
*peer_entry = peer;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint32_t peer_hash_tbl_del(mac_peer_t *peer)
|
|
{
|
|
uint32_t hash_code;
|
|
peer_hash_src_t hash = { 0 };
|
|
mac_vdev_t *vdev = get_vdev_ptr(peer->pdev_id, peer->vdev_id);
|
|
mac_peer_t *entry = NULL;
|
|
nid_t nid;
|
|
|
|
hash.vid = vdev->vdev_id;
|
|
hash.tei = (tei_t)peer->tei;
|
|
if (ERR_OK != vdev_get_nid(vdev, &nid)) {
|
|
if (peer->is_bcast_peer || peer->is_self_peer) {
|
|
nid = (nid_t)PLC_NID_INVALID;
|
|
} else {
|
|
IOT_ASSERT(0);
|
|
return ERR_INVAL;
|
|
}
|
|
}
|
|
hash.nid = nid;
|
|
hash_code = peer_get_hash(hash);
|
|
for(mac_peer_t **cur = &peer_hash_tbl[hash_code]; *cur;){
|
|
entry = *cur;
|
|
if(peer == entry){
|
|
*cur = entry->next;
|
|
break;
|
|
}
|
|
else{
|
|
cur = &entry->next;
|
|
}
|
|
}
|
|
|
|
|
|
if(peer != entry){
|
|
hash.tei = 0;
|
|
hash_code = peer_get_hash(hash);
|
|
for(mac_peer_t **cur = &peer_hash_tbl[hash_code]; *cur;){
|
|
entry = *cur;
|
|
if(peer == entry){
|
|
*cur = entry->next;
|
|
break;
|
|
}
|
|
else{
|
|
cur = &entry->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if(peer != entry){
|
|
hash.tei = 0;
|
|
hash.nid = 0;
|
|
hash_code = peer_get_hash(hash);
|
|
for(mac_peer_t **cur = &peer_hash_tbl[hash_code]; *cur;){
|
|
entry = *cur;
|
|
if(peer == entry){
|
|
*cur = entry->next;
|
|
break;
|
|
}
|
|
else{
|
|
cur = &entry->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (peer != entry) {
|
|
iot_printf("peer:0x%x not found.\n", peer);
|
|
IOT_ASSERT(0);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
return ERR_OK;
|
|
|
|
}
|
|
|
|
/* return 0 for success, else for failed */
|
|
uint32_t peer_add_stream(mac_peer_t *peer, void *stream)
|
|
{
|
|
if (!peer || !stream)
|
|
{
|
|
return ERR_INVAL;
|
|
}
|
|
mac_stream_t *str = (mac_stream_t *)stream;
|
|
if (!str->is_tx) {
|
|
peer->rate_info.last_rx_ts = os_boot_time32();
|
|
}
|
|
iot_single_list_add(&str->peer_node, &peer->data_stream_list);
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t peer_del_stream(mac_peer_t *peer, void *stream)
|
|
{
|
|
mac_stream_t *str = (mac_stream_t*)stream;
|
|
IOT_ASSERT(str->peer == peer);
|
|
|
|
/* delete from peer streamlist */
|
|
iot_single_list_del(&str->peer_node, &peer->data_stream_list);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t peer_del_all_stream(mac_peer_t *peer, uint32_t del_tx_rx_stream)
|
|
{
|
|
uint32_t i = 0;
|
|
mac_stream_t *stream;
|
|
iot_single_list_head_t *tmp;
|
|
|
|
again:
|
|
tmp = peer->data_stream_list;
|
|
while (tmp) {
|
|
stream = iot_list_entry(tmp, mac_stream_t, peer_node);
|
|
if ((del_tx_rx_stream == DEL_TX_STREAM && !stream->is_tx)
|
|
|| (del_tx_rx_stream == DEL_RX_STREAM && stream->is_tx)) {
|
|
tmp = tmp->next;
|
|
continue;
|
|
}
|
|
mac_stream_free(peer, stream);
|
|
i++;
|
|
goto again;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
uint32_t mac_peer_free(mac_vdev_t *vdev, mac_peer_t *peer)
|
|
{
|
|
mac_peer_t *tmp = peer;
|
|
|
|
/* del peer from vdev */
|
|
vdev_del_peer(vdev, tmp);
|
|
/* del peer from hash table */
|
|
if(tmp->is_self_peer == 0 &&\
|
|
tmp->is_bcast_peer == 0){
|
|
/* if not self or bcast peer,
|
|
* del this peer in hash table
|
|
*/
|
|
peer_hash_tbl_del(tmp);
|
|
}
|
|
|
|
peer_del_all_stream(tmp, DEL_ALL_STREAM);
|
|
|
|
/* destroy peer */
|
|
if(tmp->is_self_peer == 0 && \
|
|
tmp->is_bcast_peer == 0){
|
|
/* if not self or bcast peer
|
|
* free the peer
|
|
*/
|
|
mac_desc_free(&g_mac_desc_eng, PLC_MAC_PEER_POOL, tmp);
|
|
/* peer cnt --*/
|
|
vdev->peer_cnt--;
|
|
|
|
if (tmp->is_proxy_peer) {
|
|
vdev->proxy_peer_cnt--;
|
|
}
|
|
}
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t is_peer_empty(mac_peer_t *peer)
|
|
{
|
|
mac_stream_t *stream;
|
|
iot_single_list_head_t *tmp;
|
|
|
|
tmp = peer->data_stream_list;
|
|
while (tmp) {
|
|
stream = iot_list_entry(tmp, mac_stream_t, peer_node);
|
|
if (is_stream_empty(stream) == 0) {
|
|
return 0;
|
|
}
|
|
tmp = tmp->next;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
uint32_t mac_peer_del_temp_peer(mac_peer_t *peer)
|
|
{
|
|
IOT_ASSERT(peer);
|
|
mac_vdev_t *vdev = get_vdev_ptr(peer->pdev_id, peer->vdev_id);
|
|
IOT_ASSERT(vdev);
|
|
if ((mac_vdev_cfg_get_node_role(vdev) != PLC_DEV_ROLE_CCO) && \
|
|
peer->is_self_peer == 0 && peer->is_bcast_peer == 0 && \
|
|
peer->is_sub_peer == 0 && peer->is_proxy_peer == 0 && \
|
|
is_peer_empty(peer) == 1) {
|
|
iot_printf("DEL none sub peer 0x%x:tei=%d\n", \
|
|
peer, peer->tei);
|
|
mac_peer_free(vdev, peer);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
uint32_t mac_peer_del_overflow_peer(mac_peer_t *peer)
|
|
{
|
|
if (!peer) {
|
|
return ERR_FAIL;
|
|
}
|
|
mac_vdev_t *vdev = get_vdev_ptr(peer->pdev_id, peer->vdev_id);
|
|
IOT_ASSERT(vdev);
|
|
if ((peer->is_self_peer == 0) && (peer->is_bcast_peer == 0) &&
|
|
(peer->is_proxy_peer == 0)) {
|
|
if (peer->is_sub_peer) {
|
|
mac_add_overflow_peer_del_cnt(PEER_SUB);
|
|
} else {
|
|
mac_add_overflow_peer_del_cnt(PEER_TMP);
|
|
}
|
|
mac_peer_free(vdev, peer);
|
|
return ERR_OK;
|
|
}
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t mac_peer_rx_ts_update(mac_peer_t *peer, uint32_t cur_ts)
|
|
{
|
|
IOT_ASSERT(peer);
|
|
if(peer->is_bcast_peer || peer->is_self_peer)
|
|
return 1;
|
|
peer->rate_info.last_rx_ts = cur_ts;
|
|
return 0;
|
|
}
|
|
|
|
|