462 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			462 lines
		
	
	
		
			15 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. | ||
|  | 
 | ||
|  | ****************************************************************************/ | ||
|  | 
 | ||
|  | #ifndef MAC_VDEV_H
 | ||
|  | #define MAC_VDEV_H
 | ||
|  | 
 | ||
|  | #include "beacon.h"
 | ||
|  | #include "mac_vdev_api.h"
 | ||
|  | #include "plc_utils.h"
 | ||
|  | #include "mac_avln.h"
 | ||
|  | #include "iot_queue.h"
 | ||
|  | #include "command_list.h"
 | ||
|  | #include "os_timer_api.h"
 | ||
|  | #include "mac_ppm_scan.h"
 | ||
|  | #include "mac_mm_sniffer.h"
 | ||
|  | #include "mac_rf.h"
 | ||
|  | 
 | ||
|  | #ifdef __cplusplus
 | ||
|  | extern "C" { | ||
|  | #endif
 | ||
|  | 
 | ||
|  | /* rate control callback */ | ||
|  | typedef uint32_t(*rate_control_func_t)(\ | ||
|  |     void *peer, \ | ||
|  |     void *arg); | ||
|  | 
 | ||
|  | /* NB: not to expose the structs to the upper layer directly */ | ||
|  | typedef struct _mac_vdev { | ||
|  |     vdevid_t vdev_id; | ||
|  |     vdevid_t rf_vdev_id; | ||
|  |     mac_beacon_ctx_t bcn_ctx; | ||
|  |     uint32_t is_up; | ||
|  |     mac_vdev_cfg_t mac_vdev_cfg; | ||
|  |     mac_vdev_start_cfg_t start_cfg; | ||
|  |     mac_avln_t *avln; | ||
|  |     iot_list_head_t *peer_list; // peer list for this vdev
 | ||
|  |     void *self_peer; | ||
|  |     void *bcast_peer; | ||
|  |     pdevid_t ref_pdev_id; | ||
|  |     tei_t proxy_tei;        /* proxy tei for MAC layer MPDU forwarding */ | ||
|  |     /* logical phase of the device.
 | ||
|  |      * sta role device only use phase 1. | ||
|  |      * cco role device may use multiple phases. | ||
|  |      */ | ||
|  |     /* phase 1 */ | ||
|  |     uint8_t l_phase1          :2, | ||
|  |     /* phase 2 */ | ||
|  |             l_phase2          :2, | ||
|  |     /* phase 3 */ | ||
|  |             l_phase3          :2, | ||
|  |     /* flag to mark if vdev stopped */ | ||
|  |             stop_flag         :1, | ||
|  |     /* nncco time division tx in 3 phase */ | ||
|  |             nncco_tx_3phase   :1; | ||
|  |     /* scheduler context */ | ||
|  |     void *sched_ctx; | ||
|  |     /* current ppm sync target nid */ | ||
|  |     uint32_t sync_nid; | ||
|  |     /* current ppm sync target proxy */ | ||
|  |     tei_t sync_proxy; | ||
|  |     /* sub peer and proxy cnt */ | ||
|  |     uint32_t sub_peer_cnt               :14, | ||
|  |     /* black list nid cnt */ | ||
|  |             nid_bl_list_cnt             :8, | ||
|  |     /* is block dbg pkt tx in rx only scheduler period or not */ | ||
|  |             block_dbg_pkt_4_rx_only     :1, | ||
|  |     /* is sync_nid inited */ | ||
|  |             sync_nid_inited             :1, | ||
|  |     /* flag to mark if cco has sta joined network */ | ||
|  |             sta_joined                  :1, | ||
|  |     /* whether bcsma slot exist in current beacon period  */ | ||
|  |             bcsma_slot_exist            :1, | ||
|  |     /* bcsma nonentity cnt */ | ||
|  |             bcsma_non_exist_cnt         :3, | ||
|  |     /* LID_BCSMA_FB_DETECT exist or no at beacon period */ | ||
|  |             fb_lid_exist                :1, | ||
|  |     /* flag to mark if suspend sending and receiving */ | ||
|  |             tx_rx_suspend               :1, | ||
|  |     /* flag to mark if 3ps sta physical phase is opposite */ | ||
|  |             opposite_3ps                :1; | ||
|  |     /* black list nid array */ | ||
|  |     uint32_t nid_bl_list[PLC_BL_NID_LIST_MAX]; | ||
|  | 
 | ||
|  |     /* rate control context start
 | ||
|  |      * TODO: put them into the ctxt */ | ||
|  |     void *rate_control_ctxt; | ||
|  |     /* rate control callback */ | ||
|  |     rate_control_func_t ra_cb; | ||
|  |     /*fixed rate or not*/ | ||
|  |     uint32_t fixed_rate_flag       : 1, | ||
|  |     /* rate level show RA_LEVEL_xx */ | ||
|  |              rate_level            : 2, | ||
|  |     /* nncco time division tx phase */ | ||
|  |              nncco_td_tx_phase     : 2, | ||
|  |              rev1                  : 27; | ||
|  | 
 | ||
|  |     uint32_t high_power_req_reason_bitmap; | ||
|  | 
 | ||
|  |     uint16_t  power_cap             :     8,   //max power enable
 | ||
|  |               fixed_power_cap_flag  :     1,   //is power cap set
 | ||
|  |               high_power_flag       :     1,   //is high power cur
 | ||
|  |               high_power_req_ena    :     5,   //enable or disable auto power control'
 | ||
|  |     /* flag to mark if PLC high power is currently allowed */ | ||
|  |               high_power_plc_allow  :     1; | ||
|  |     /* rate control context end */ | ||
|  | 
 | ||
|  |     uint32_t last_rx_ntb; | ||
|  |     uint32_t last_tx_ntb; | ||
|  | #if MAC_STREAM_TIMEOUT_SUPPORT
 | ||
|  |     timer_id_t stream_timeout_timer; | ||
|  | #endif
 | ||
|  |     mac_ppm_ctxt_t mac_ppm; | ||
|  |     /* sync ntb record context */ | ||
|  |     mac_ntb_record_ctxt_t sync_ntb_record; | ||
|  | 
 | ||
|  | #if CERT_WAR_TX_PWR == 1
 | ||
|  |     uint32_t cert_war_pwr;              /* pwr rise or not - 1: rise */ | ||
|  | #endif
 | ||
|  | 
 | ||
|  |     /* mac rf info */ | ||
|  |     mac_rf_t *mac_rf; | ||
|  | 
 | ||
|  |     uint32_t peer_cnt; | ||
|  |     uint32_t stream_cnt; | ||
|  |     uint32_t stream_overflow_cnt; | ||
|  |     uint32_t proxy_peer_cnt; | ||
|  |     uint32_t rx_stream_cnt; | ||
|  |     /* sub peer bitmap only for vdev not reduced valid */ | ||
|  |     void *sub_peer_bitmap; | ||
|  |     mac_sec_key_t *sec_key; | ||
|  | } mac_vdev_t; | ||
|  | 
 | ||
|  | tei_t vdev_get_tei(mac_vdev_t* vdev); | ||
|  | 
 | ||
|  | void vdev_set_tei(mac_vdev_t* vdev, tei_t tei); | ||
|  | 
 | ||
|  | mac_vdev_t *get_vdev_ptr(uint32_t pdev_id, uint32_t vdev_id); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * mac_create_vdev_internal() - create mac layer virtual device. this function | ||
|  |  *                              is similar to mac_create_vdev but can only be | ||
|  |  *                              called inside mac context. | ||
|  |  * @pdev_id:    phasical mac device on top of which to create the vdev | ||
|  |  * @vdev_id:    pointer to receive the created vdev id | ||
|  |  * @cfg:        configuration for the created vdev | ||
|  |  * | ||
|  |  * return: | ||
|  |  *      0         -- for success case | ||
|  |  *      othersie  -- error code | ||
|  |  */ | ||
|  | uint32_t mac_create_vdev_internal(uint8_t pdev_id, uint8_t *vdev_id, | ||
|  |     mac_vdev_cfg_t *cfg); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * mac_start_vdev_internal() - start mac layer virtual device. this function | ||
|  |  *                             is similar to mac_start_vdev but can only be | ||
|  |  *                             called inside mac context. | ||
|  |  * @pdev_id:    phasical mac device id | ||
|  |  * @vdev_id:    virtual mac device id | ||
|  |  * @cfg:        configuration for the start | ||
|  |  * | ||
|  |  * return: | ||
|  |  *      0         -- for success case | ||
|  |  *      othersie  -- error code | ||
|  |  */ | ||
|  | uint32_t mac_start_vdev_internal(uint8_t pdev_id, uint8_t vdev_id, | ||
|  |     mac_vdev_start_cfg_t *cfg); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * mac_stop_vdev_internal() - stop mac layer virtual device. this function | ||
|  |  *                            is similar to mac_stop_vdev but can only be | ||
|  |  *                            called inside mac context. | ||
|  |  * @pdev_id:    phasical mac device id | ||
|  |  * @vdev_id:    virtual mac device id | ||
|  |  * | ||
|  |  * return: | ||
|  |  *      0         -- for success case | ||
|  |  *      othersie  -- error code | ||
|  |  */ | ||
|  | uint32_t mac_stop_vdev_internal(uint8_t pdev_id, uint8_t vdev_id); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * mac_set_vdev_cfg_internal() - set a vdev's config. this function is | ||
|  |  *                               similar to mac_set_vdev_cfg but can only be | ||
|  |  *                               called inside mac context. | ||
|  |  * @pdev_id:        which pdev to config | ||
|  |  * @vdev_id:        which vdev to config | ||
|  |  * @cfg_struct_ptr: the pointer to the param config structure which can be | ||
|  |  *                  decoded according to the type. | ||
|  |  * | ||
|  |  * return: | ||
|  |  *      0         -- for success case | ||
|  |  *      othersie  -- error code | ||
|  |  */ | ||
|  | uint32_t mac_set_vdev_cfg_internal(pdevid_t pdev_id, vdevid_t vdev_id, | ||
|  |     cfg_data_tlv *cfg_struct_ptr); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * mac_get_vdev_cfg_internal() - get a vdev's config. this function is | ||
|  |  *                               similar to mac_get_vdev_cfg but can only be | ||
|  |  *                               called inside mac context. | ||
|  |  * @pdev_id:        which pdev to config | ||
|  |  * @vdev_id:        which vdev to config | ||
|  |  * @cfg_struct_ptr: the pointer to the param config structure which can be | ||
|  |  *                  decoded according to the type. | ||
|  |  * | ||
|  |  * return: | ||
|  |  *      0         -- for success case | ||
|  |  *      othersie  -- error code | ||
|  |  */ | ||
|  | uint32_t mac_get_vdev_cfg_internal(pdevid_t pdev_id, vdevid_t vdev_id, | ||
|  |     cfg_data_tlv *tlv); | ||
|  | 
 | ||
|  | /* find vdev according to nid */ | ||
|  | mac_vdev_t *find_vdev_by_nid(pdevid_t pid, nid_t nid); | ||
|  | 
 | ||
|  | /* associate a vdev and a peer */ | ||
|  | uint32_t vdev_add_peer(mac_vdev_t *vdev, void *peer); | ||
|  | 
 | ||
|  | uint32_t vdev_del_peer(mac_vdev_t *vdev, void *peer); | ||
|  | 
 | ||
|  | 
 | ||
|  | uint32_t vdev_del_all_peer(mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | 
 | ||
|  | /* get vdev's nid */ | ||
|  | uint32_t vdev_get_nid(mac_vdev_t *vdev, nid_t *nid); | ||
|  | 
 | ||
|  | /* set vdev's nid */ | ||
|  | void vdev_set_nid(mac_vdev_t *vdev, uint32_t nid); | ||
|  | 
 | ||
|  | /* reset vdev's nid */ | ||
|  | void vdev_reset_nid(mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * @brief vdev_reset_ppm_sync() - reset vdev ppm sync status | ||
|  |  * @param vdev: mac vdev pointer | ||
|  |  */ | ||
|  | void vdev_reset_ppm_sync(mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * @brief vdev_is_bl_nid() - cehck if one nid is blacklisted | ||
|  |  * @param vdev: mac vdev pointer | ||
|  |  * @param nid:  nid to be checked | ||
|  |  * @return 1 if the nid is blacklisted. 0 if the nid is not blacklisted. | ||
|  |  */ | ||
|  | 
 | ||
|  | uint32_t vdev_is_bl_nid(mac_vdev_t *vdev, uint32_t nid); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * @brief vdev_get_sync_nid() - get target nid current vdev is syncing to | ||
|  |  * @param vdev: mac vdev pointer | ||
|  |  * @return network id | ||
|  |  */ | ||
|  | uint32_t vdev_get_sync_nid(mac_vdev_t *vdev, nid_t *sync_nid); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * @brief vdev_set_sync_nid() - set target nid current vdev is syncing to | ||
|  |  * @param vdev: mac vdev pointer | ||
|  |  */ | ||
|  | void vdev_set_sync_nid(mac_vdev_t *vdev, uint32_t nid); | ||
|  | 
 | ||
|  | void vdev_reset_sync_nid(mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * @brief vdev_get_sync_proxy() - get target proxy current vdev is syncing to | ||
|  |  * @param vdev: mac vdev pointer | ||
|  |  * @return target proxy tei | ||
|  |  */ | ||
|  | tei_t vdev_get_sync_proxy(mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * @brief vdev_set_sync_proxy() - set target proxy current vdev is syncing to | ||
|  |  * @param vdev: mac vdev pointer | ||
|  |  */ | ||
|  | void vdev_set_sync_proxy(mac_vdev_t *vdev, tei_t proxy); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * @brief vdev_reset_proxy_tei() - reset vdev's proxy tei | ||
|  |  * | ||
|  |  * @param mac_vdev_t *vdev [the pointer of the vdev that get from] | ||
|  |  * @return void | ||
|  |  */ | ||
|  | void vdev_reset_proxy_tei(mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * @brief vdev_get_proxy_tei() - get vdev's proxy tei | ||
|  |  * | ||
|  |  * @param mac_vdev_t *vdev [the pointer of the vdev that get from] | ||
|  |  * @return tei_t [tei that in the vdev structure] | ||
|  |  */ | ||
|  | tei_t vdev_get_proxy_tei(mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * @breif vdev_set_proxy_tei() - set vdev's proxy tei | ||
|  |  * @param mac_vdev_t *vdev [the pointer of the vdev that get from] | ||
|  |  * @param proxy_tei [the value of tei] | ||
|  |  * @return [none] | ||
|  |  */ | ||
|  | void vdev_set_proxy_tei(mac_vdev_t *vdev, tei_t proxy_tei); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @brief vdev_get_logic_phase() - get vdev's phase | ||
|  | *        if STA, the return is the current logic phase. | ||
|  | *        if CCo, it's the phase1's value. | ||
|  | * @param mac_vdev_t *vdev [the pointer of the vdev that get from] | ||
|  | * @return phase_t [phase that in the vdev structure] | ||
|  | */ | ||
|  | phase_t vdev_get_logic_phase(mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif vdev_set_proxy_tei() - set vdev's phase | ||
|  | * @param mac_vdev_t *vdev [the pointer of the vdev that get from] | ||
|  | * @param phase [the value of phase, plc protocol, 0:unknown;1:A;2:B;3:C] | ||
|  | * @return [none] | ||
|  | */ | ||
|  | void vdev_set_logic_phase(mac_vdev_t *vdev, phase_t phase); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif vdev_set_ra_cb() - set vdev's ra cb | ||
|  | * @param mac_vdev_t *vdev [the pointer of the vdev that get from] | ||
|  | * @param cb [the callback of the rate control function] | ||
|  | * @return [none] | ||
|  | */ | ||
|  | void vdev_set_ra_cb(mac_vdev_t * vdev, rate_control_func_t cb); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif vdev_set_sta_cap_phase() - set sta cap phase pointer of vdev | ||
|  | * @param uint32_t proto [protocol type] | ||
|  | * @param mac_vdev_t *vdev [the pointer of the vdev that get from] | ||
|  | * @param uint8_t phase [phase] | ||
|  | * @return void | ||
|  | */ | ||
|  | void vdev_set_sta_cap_phase(uint32_t proto, mac_vdev_t *vdev, uint8_t phase); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif vdev_get_bc_period_cnt_ptr() - get bc period cnt pointer of vdev | ||
|  | * @param uint32_t proto [protocol type] | ||
|  | * @param mac_vdev_t *vdev [the pointer of the vdev that get from] | ||
|  | * @return uint8_t * [poiter of beacon period counter] | ||
|  | */ | ||
|  | uint32_t *vdev_get_bc_period_cnt_ptr(uint32_t proto, mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif vdev_get_bc_period_cnt() - get beacon period counter | ||
|  | * @param uint32_t proto [protocol type] | ||
|  | * @param mac_vdev_t *vdev [the pointer of the vdev that get from] | ||
|  | * @return uint32  [beacon period counter] | ||
|  | */ | ||
|  | uint32_t vdev_get_bc_period_cnt(uint32_t proto, mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif vdev_set_fixed_rate() - set fixed rate | ||
|  | * @param mac_vdev_t *vdev [the pointer of the vdev that get from] | ||
|  | * @param uint8_t flag [true or flase] | ||
|  | * @return uint32  [0] | ||
|  | */ | ||
|  | uint32_t vdev_set_fixed_rate(mac_vdev_t *vdev, uint8_t flag); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif vdev_get_fixed_rate() - set fixed rate | ||
|  | * @param mac_vdev_t *vdev [the pointer of the vdev that get from] | ||
|  | * @return uint8  [is fixed rate or not] | ||
|  | */ | ||
|  | uint32_t vdev_get_fixed_rate(mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif vdev_set_fixed_rate_level() - set fixed rate level | ||
|  | * @param mac_vdev_t *vdev            - the pointer of the vdev that get from | ||
|  | * @param uint8_t rate_level          - rate level show RA_LEVEL_xx | ||
|  | * @return uint32                     - 0 | ||
|  | */ | ||
|  | uint32_t vdev_set_fixed_rate_level(mac_vdev_t *vdev, uint8_t rate_level); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif vdev_get_fixed_rate() - set fixed rate | ||
|  | * @param mac_vdev_t *vdev      - the pointer of the vdev that get from | ||
|  | * @return uint32               - is rate level show RA_LEVEL_xx | ||
|  | */ | ||
|  | uint32_t vdev_get_fixed_rate_level(mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif mac_vdev_sort_peer_list() - sort peer list | ||
|  | * @param mac_vdev_t *vdev       [the pointer of the vdev that get from] | ||
|  | * @param void *peer       [the pointer of the peer] | ||
|  | * @return uint32  [0] | ||
|  | */ | ||
|  | uint32_t mac_vdev_sort_peer_list(mac_vdev_t *vdev, void *peer); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @brief mac_vdev_del_timeout_stream_internal - del timeout stream function | ||
|  | * @param data                                   msg data vdev of mac | ||
|  | * @param judge_time                             whether to judge the time | ||
|  | * @retrun void | ||
|  | */ | ||
|  | void mac_vdev_del_timeout_stream_internal(void *data, uint32_t judge_time); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @brief mac_vdev_del_overflow_peer() - del overflow peer function | ||
|  | * @param vdev                           vdev of mac | ||
|  | * @retrun void | ||
|  | */ | ||
|  | void mac_vdev_del_overflow_peer(mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif mac_vdev_del_timeout_stream() - del the oldest peer | ||
|  | * @param timer_id_t timer_id             [timer] | ||
|  | * @param void *arg                       [the pointer of the vdev that get from] | ||
|  | * @return void | ||
|  | */ | ||
|  | void mac_vdev_del_timeout_stream(timer_id_t timer_id, void *arg); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif mac_vdev_cfg_get_node_role() - get node_role from mac_vdev_cfg | ||
|  | * @param mac_vdev_t *vdev               [the pointer of the vdev that get from] | ||
|  | * @return uint8_t                       see PLC_DEV_ROLE_xxx | ||
|  | */ | ||
|  | uint8_t mac_vdev_cfg_get_node_role(mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | uint32_t vdev_get_bc_period_ms(mac_vdev_t *vdev, uint32_t proto); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif vdev_set_block_dbg_pkt_4_rx_only() - set block or not for dbg pkt in | ||
|  | *                                       rx only period | ||
|  | * @param mac_vdev_t *vdev               [the pointer of the vdev that get from] | ||
|  | * @return uint8_t                       ERR_OK | ||
|  | */ | ||
|  | uint32_t vdev_set_block_dbg_pkt_4_rx_only(mac_vdev_t *vdev, uint32_t block); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif vdev_get_block_dbg_pkt_4_rx_only() - get block or not for dbg pkt in | ||
|  | *                                       rx only period | ||
|  | * @param mac_vdev_t *vdev               [the pointer of the vdev that get from] | ||
|  | * @return uint8_t                       0: false; other: true; | ||
|  | */ | ||
|  | uint32_t vdev_get_block_dbg_pkt_4_rx_only(mac_vdev_t *vdev); | ||
|  | 
 | ||
|  | /*
 | ||
|  | * @breif mac_vdev_war_rx_abort_init() - int war rx abort context | ||
|  | * | ||
|  | * @return none | ||
|  | */ | ||
|  | void mac_vdev_war_rx_abort_init(void); | ||
|  | 
 | ||
|  | #ifdef __cplusplus
 | ||
|  | } | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #endif // !MAC_VDEV_H
 |