411 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			411 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /****************************************************************************
 | ||
|  | 
 | ||
|  | 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; | ||
|  | } | ||
|  | 
 | ||
|  | 
 |