- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# /space/home/slher/rel/Beken/v6_4_5/macsw/ip/lmac/src/mm/mm.c

Go to the documentation of this file.

    00001
    00020 /*
    00021  * INCLUDE FILES
    00022  ****************************************************************************************
    00023  */
    00024 #include "mac_frame.h"
    00025 #include "mm.h"
    00026 #include "mm_timer.h"
    00027 #include "mm_bcn.h"
    00028 #include "co_endian.h"
    00029 #include "sta_mgmt.h"
    00030 #include "vif_mgmt.h"
    00031 #include "phy.h"
    00032 #include "dbg.h"
    00033 #include "rd.h"
    00034 #include "ps.h"
    00035 #include "txl_cntrl.h"
    00036 #include "txl_frame.h"
    00037 #include "rxl_cntrl.h"
    00038 #include "rxl_hwdesc.h"
    00039 #include "hal_machw.h"
    00040 #include "scan.h"
    00041 #include "chan.h"
    00042 #include "hal_dma.h"
    00043 #if (NX_P2P)
    00044 #include "p2p.h"
    00045 #endif //(NX_P2P)
    00046 #if (NX_TD)
    00047 #include "td.h"
    00048 #endif //(NX_TD)
    00049 #if (RW_BFMER_EN)
    00050 #include "bfr.h"
    00051 #endif //(RW_BFMER_EN)
    00052 #if (RW_UMESH_EN)
    00053 #include "mesh.h"
    00054 #endif //(RW_UMESH_EN)
    00055 #if (NX_UMAC_PRESENT && NX_BEACONING)
    00056 #include "apm.h"
    00057 #endif // NX_BEACONING
    00058
    00059 #include "reg_mac_core.h"
    00060 #include "reg_mac_pl.h"
    00061
    00062 // For IE access functions
    00063 #include "mac_ie.h"
    00064
    00065
    00067 #if NX_BEACONING
    00068 #define MM_TBTT_EVT_MASK (KE_EVT_PRIMARY_TBTT_BIT | KE_EVT_SECONDARY_TBTT_BIT)
    00069 #else
    00070 #define MM_TBTT_EVT_MASK KE_EVT_PRIMARY_TBTT_BIT
    00071 #endif
    00072
    00074 #define MM_BEACON_LOSS_THD 10
    00075
    00077 #define MM_KEEP_ALIVE_PERIOD (30 * 1000000)
    00078
    00080 #define MM_TBTT_IRQ_MASK (NXMAC_IMP_PRI_DTIM_BIT | NXMAC_IMP_PRI_TBTT_BIT)
    00081
    00083 #define MM_MAC_ADDR_MSK  ((NX_VIRT_DEV_MAX - 1) << 8)
    00084
    00086 #define TXOP(limit)  (((limit)==0) || ((limit) > MM_DEFAULT_MAX_AMPDU_DURATION))?       \
    00087                                   MM_DEFAULT_MAX_AMPDU_DURATION:(limit);
    00088
    00089 #if NX_MULTI_ROLE
    00091 #define TBTT_DELAY   400
    00092 #endif
    00093
    00106 #if !NX_MAC_HE
    00107 // newRead, newWrite, newSearch, SearchError, keyIdx, cType, vlanIdx, spp, usedefkey, cLen
    00108 #define KEY_RAM_WR(key_idx, ctype, vif_idx, spp, usedefkey, clen)                        \
    00109 {                                                                                        \
    00110     nxmac_encr_cntrl_pack(0, 1, 0, 0, key_idx, ctype, vif_idx, spp, usedefkey, clen);    \
    00111     while(nxmac_new_write_getf());                                                       \
    00112 }
    00113 #else
    00114 // newRead, newWrite, newSearch, SearchError, keyIdx, cLen, cType, vlanIdx, spp, usedefkey
    00115 #define KEY_RAM_WR(key_idx, ctype, vif_idx, spp, usedefkey, clen)                        \
    00116 {                                                                                        \
    00117     nxmac_encr_cntrl_pack(0, 1, 0, 0, key_idx, clen, ctype, vif_idx, spp, usedefkey);    \
    00118     while(nxmac_new_write_getf());                                                       \
    00119 }
    00120 #endif
    00121
    00122
    00124 #if NX_CHNL_CTXT
    00125 #define MM_TBTT_COMPUTE_MARGIN (CHAN_SWITCH_DELAY + 300)
    00126 #else
    00127 #define MM_TBTT_COMPUTE_MARGIN 300
    00128 #endif
    00129
    00131 #if NX_UMAC_PRESENT
    00132 #define TASK_IND  TASK_SM
    00133 #else
    00134 #define TASK_IND  TASK_API
    00135 #endif
    00136
    00137 /*
    00138  * GLOBAL VARIABLES
    00139  ****************************************************************************************
    00140  */
    00142
    00145 struct mm_env_tag mm_env;
    00146
    00147
    00159 static void mm_key_ram_param_get(uint8_t cipher_suite, struct mac_sec_key const *key,
    00160                                  uint8_t *ctype, uint8_t *clen)
    00161 {
    00162     *clen = 1;
    00163     *ctype = MM_SEC_CTYPE_NULL;
    00164
    00165     // Check which encryption type has to be used
    00166     switch(cipher_suite)
    00167     {
    00168         case MAC_CIPHER_WEP40:
    00169             *clen = 0;
    00170         case MAC_CIPHER_WEP104:
    00171             *ctype = MM_SEC_CTYPE_WEP;
    00172             break;
    00173         case MAC_CIPHER_TKIP:
    00174             *ctype = MM_SEC_CTYPE_TKIP;
    00175             break;
    00176         case MAC_CIPHER_CCMP:
    00177             #if NX_MAC_HE
    00178             switch (key->length)
    00179             {
    00180                 case 16:
    00181                     *clen = 0;
    00182                     break;
    00183                 case 32:
    00184                     *clen = 2;
    00185                     break;
    00186                 default:
    00187                     break;
    00188             }
    00189             #endif
    00190             *ctype = MM_SEC_CTYPE_CCMP;
    00191             break;
    00192         #if RW_WAPI_EN
    00193         case MAC_CIPHER_WPI_SMS4:
    00194             *ctype = MM_SEC_CTYPE_WPI_SMS4;
    00195             break;
    00196         #endif
    00197         default:
    00198             ASSERT_ERR(0);
    00199             break;
    00200     }
    00201
    00202
    00203 }
    00204
    00205 #if NX_BEACONING
    00206
    00215 static void mm_ap_tbtt_move_cb(void *offset)
    00216 {
    00217     // Allocate TBTT move message
    00218     struct mm_tbtt_move_req *req = KE_MSG_ALLOC(MM_TBTT_MOVE_REQ, TASK_MM, TASK_NONE, mm_tbtt_move_req);
    00219
    00220     // Set the offset
    00221     req->offset = (int32_t)offset;
    00222
    00223     // Send the message
    00224     ke_msg_send(req);
    00225 }
    00226 #endif
    00227
    00228 void mm_env_max_ampdu_duration_set(void)
    00229 {
    00230     // Initialize the TXOP values
    00231     mm_env.ampdu_max_dur[AC_BK] = TXOP(nxmac_tx_op_limit_0_getf());
    00232     mm_env.ampdu_max_dur[AC_BE] = TXOP(nxmac_tx_op_limit_1_getf());
    00233     mm_env.ampdu_max_dur[AC_VI] = TXOP(nxmac_tx_op_limit_2_getf());
    00234     mm_env.ampdu_max_dur[AC_VO] = TXOP(nxmac_tx_op_limit_3_getf());
    00235
    00236     #if NX_BEACONING
    00237     // For BCN queue, put same parameter as VO
    00238     mm_env.ampdu_max_dur[AC_BCN] = mm_env.ampdu_max_dur[AC_VO];
    00239     #endif
    00240 }
    00241
    00242 void mm_env_init(void)
    00243 {
    00244     // Reset the complete environment
    00245     memset(&mm_env, 0, sizeof(mm_env));
    00246
    00247     mm_env.prev_mm_state = MM_IDLE;
    00248     mm_env.prev_hw_state = HW_IDLE;
    00249     #if NX_UMAC_PRESENT
    00250     mm_env.host_idle = 1;
    00251     #endif
    00252     mm_env.rx_filter_lmac_enable = 0;
    00253     mm_rx_filter_umac_set(MM_RX_FILTER_MONITOR);
    00254
    00255     // Initialize the TXOP values
    00256     mm_env_max_ampdu_duration_set();
    00257     #if NX_BEACONING
    00258     mm_env.tbtt_move_tmr.cb = mm_ap_tbtt_move_cb;
    00259     #endif
    00260 }
    00261
    00265 void mm_init(void)
    00266 {
    00267     // TODO reset PHY
    00268
    00269     // Initialize the MAC HW
    00270     hal_machw_init();
    00271
    00272     // Init All LMAC MM env data
    00273     mm_env_init();
    00274
    00275     // Initialize the VIF table
    00276     vif_mgmt_init();
    00277
    00278     // Initialize the peer station tables
    00279     sta_mgmt_init();
    00280
    00281     #if (NX_TD)
    00282     // Initialize the TD module
    00283     td_init();
    00284     #endif //(NX_TD)
    00285
    00286     #if NX_POWERSAVE
    00287     // Initialize the PS module
    00288     ps_init();
    00289     #endif
    00290
    00291     #if (NX_P2P)
    00292     // Initialize P2P module
    00293     p2p_init();
    00294     #endif //(NX_P2P)
    00295
    00296     // Initialize Tx
    00297     txl_cntrl_init();
    00298
    00299     // Initialize Rx
    00300     rxl_init();
    00301
    00302     #if NX_RADAR_DETECT
    00303     // Initialize radar
    00304     rd_init();
    00305     #endif
    00306
    00307     #if NX_MM_TIMER
    00308     mm_timer_init();
    00309     #endif
    00310
    00311     #if NX_HW_SCAN
    00312     scan_init();
    00313     #endif
    00314
    00315     #if NX_CHNL_CTXT
    00316     chan_init();
    00317     #endif
    00318
    00319     #if NX_GP_DMA
    00320     hal_dma_init();
    00321     #endif
    00322
    00323     #if NX_BCN_AUTONOMOUS_TX
    00324     // Init MM beacon module
    00325     mm_bcn_init();
    00326     #endif
    00327
    00328     #if (RW_BFMER_EN)
    00329     // Initialize Beamformer module
    00330     bfr_init();
    00331     #endif //(RW_BFMER_EN)
    00332 }
    00333
    00334 #if NX_MULTI_ROLE
    00335 void mm_tbtt_compute(struct bcn_frame *bcn, uint16_t len, struct rx_hd *rhd,
    00336                      struct vif_info_tag *vif,
    00337                      struct sta_info_tag *sta, uint32_t tim)
    00338 {
    00339     // Get peer AP information
    00340     uint64_t tsf_start_local = ((uint64_t)rhd->tsflo) | (((uint64_t)rhd->tsfhi) << 32);
    00341     uint64_t tsf_start_peer = bcn->tsf;
    00342     int64_t tsf_offset;
    00343     uint32_t next_tbtt;
    00344     uint32_t duration_to_timestamp;
    00345     uint32_t duration_of_frame;
    00346     uint64_t next_tbtt_tsf;
    00347     uint64_t tbtt_tsf;
    00348     uint32_t bcn_int = (bcn->bcnint << 10);
    00349     uint16_t interval = 1;
    00350     uint32_t drift = 0;
    00351
    00352     #if NX_POWERSAVE
    00353     if ((vif->type == VIF_STA) && (vif->u.sta.listen_interval))
    00354     {
    00355         interval = vif->u.sta.listen_interval;
    00356     }
    00357     else
    00358     #endif
    00359     if (tim)
    00360     {
    00361         // Get DTIM information
    00362         interval = co_read8p(tim + MAC_TIM_CNT_OFT);
    00363         if (interval == 0)
    00364             interval = co_read8p(tim + MAC_TIM_PERIOD_OFT);
    00365     }
    00366
    00367     #if (NX_POWERSAVE)
    00368     drift = sta->drift * interval;
    00369     #endif //(NX_POWERSAVE)
    00370
    00371     // Compute the local time at first bit of timestamp
    00372     duration_of_frame = hal_machw_rx_bcn_duration(rhd, len);
    00373     duration_to_timestamp = hal_machw_rx_bcn_duration(rhd, MAC_BEACON_TIMESTAMP_OFT);
    00374     tsf_start_local -= (duration_of_frame - duration_to_timestamp);
    00375
    00376     // Compute the TSF offset between the peer and the local counters
    00377     tsf_offset = tsf_start_peer - tsf_start_local;
    00378
    00379     #if (NX_P2P)
    00380     if (vif->type == VIF_STA)
    00381     {
    00382         vif->u.sta.ctw_add_dur = drift + TBTT_DELAY;
    00383         vif->u.sta.last_tsf_offset = tsf_offset;
    00384     }
    00385     #endif //(NX_P2P)
    00386
    00387     // Compute what was the current TBTT time
    00388     tbtt_tsf = (tsf_start_peer / bcn_int) * bcn_int;
    00389
    00390     // Check if the beacon was not sent too early
    00391     if (tbtt_tsf > (tsf_start_peer - duration_to_timestamp))
    00392         tbtt_tsf = tsf_start_peer - duration_to_timestamp;
    00393
    00394     // Compute the next TBTT time at peer time
    00395     next_tbtt_tsf = tbtt_tsf + interval * bcn_int;
    00396
    00397     // Compute the next TBTT at local time based on the TSF offset
    00398     next_tbtt = (uint32_t)(next_tbtt_tsf - tsf_offset) - TBTT_DELAY - drift;
    00399
    00400     // Check if next TBTT is in the past
    00401     if (hal_machw_time_past(next_tbtt - MM_TBTT_COMPUTE_MARGIN))
    00402     {
    00403         next_tbtt += bcn_int;
    00404     }
    00405
    00406     // Convert TSF time to local time
    00407     next_tbtt += (ke_time() - nxmac_tsf_lo_get());
    00408
    00409     #if (RW_UMESH_EN)
    00410     if (vif->type == VIF_MESH_POINT)
    00411     {
    00412         // Forward extracted TBTT information to the Mesh module
    00413         sta->bcn_int = bcn_int;
    00414         mesh_update_tbtt_info(vif, sta, next_tbtt);
    00415     }
    00416     else
    00417     #endif //(RW_UMESH_EN)
    00418     {
    00419         // Program the next TBTT
    00420         if (next_tbtt != vif->tbtt_timer.time)
    00421         {
    00422             mm_timer_set(&vif->tbtt_timer, next_tbtt);
    00423             #if NX_CHNL_CTXT
    00424             chan_tbtt_updated(vif);
    00425             #endif
    00426         }
    00427     }
    00428 }
    00429 #endif
    00430
    00431 #if NX_CONNECTION_MONITOR
    00432
    00441 static void mm_ap_probe_cfm(void *env, uint32_t status)
    00442 {
    00443     struct vif_info_tag *vif = (struct vif_info_tag *) env;
    00444
    00445     // Check if NULL frame was acknowledged
    00446     if (status & FRAME_SUCCESSFUL_TX_BIT)
    00447     {
    00448         // Frame was acknowledged, reset the beacon loss counter
    00449         vif->u.sta.beacon_loss_cnt = 0;
    00450     }
    00451     else
    00452     {
    00453         // Otherwise, we consider that the connection is lost
    00454         mm_send_connection_loss_ind(vif);
    00455     }
    00456 }
    00457
    00471 static uint32_t mm_compute_beacon_crc(struct bcn_frame *bcn, uint16_t len, uint32_t *tim)
    00472 {
    00473     uint32_t crc;
    00474     uint32_t bcn_addr = CPU2HW(bcn);
    00475     uint32_t addr = bcn_addr + MAC_BEACON_VARIABLE_PART_OFT;
    00476
    00477     // Only beacon interval and capability information are of interest in the constant part
    00478     crc = co_crc32(bcn_addr + MAC_BEACON_INTERVAL_OFT, 4, 0);
    00479
    00480     // Remove the length of the constant part + MAC header
    00481     len -= MAC_BEACON_VARIABLE_PART_OFT;
    00482
    00483     // By default we consider that we won't find the TIM IE
    00484     *tim = 0;
    00485
    00486     // Now compute the CRC on the variable part IEs, skipping the ones we handle internally
    00487     while (len >= MAC_INFOELT_INFO_OFT)
    00488     {
    00489         uint8_t ie_id = co_read8p(addr++);
    00490         uint8_t ie_len = co_read8p(addr++);
    00491
    00492         // Ensure IE is complete
    00493         if ((ie_len + MAC_INFOELT_INFO_OFT) > len)
    00494             break;
    00495
    00496         // Check if we compute the CRC on this IE or not
    00497         switch (ie_id)
    00498         {
    00499             case MAC_ELTID_TIM:
    00500                 // Skip this element, so we do nothing
    00501                 *tim = addr - MAC_INFOELT_INFO_OFT;
    00502                 break;
    00503             default:
    00504                 // Compute the CRC on this element
    00505                 crc = co_crc32(addr, ie_len, crc);
    00506                 break;
    00507         }
    00508
    00509         // Decrease the length and increase the pointer
    00510         len -= ie_len + MAC_INFOELT_INFO_OFT;
    00511         addr += ie_len;
    00512     }
    00513
    00514     return (crc);
    00515 }
    00516 #endif
    00517
    00518 #if NX_CONNECTION_MONITOR || NX_MULTI_ROLE
    00519 bool mm_check_beacon(struct rx_hd *rhd, struct vif_info_tag *vif,
    00520                      struct sta_info_tag *sta, uint32_t *tim)
    00521 {
    00522     struct rx_pbd *pbd = HW2CPU(rhd->first_pbd_ptr);
    00523     struct bcn_frame *bcn = HW2CPU(pbd->datastartptr);
    00524     uint16_t len = rhd->frmlen;
    00525
    00526     #if NX_CONNECTION_MONITOR
    00527     int8_t rssi;
    00528     int8_t rx_rssi[2];
    00529     uint32_t crc_prev = vif->u.sta.mon_last_crc;
    00530
    00531     // Reset the beacon loss count
    00532     vif->u.sta.beacon_loss_cnt = 0;
    00533
    00534     #if NX_UMAC_PRESENT
    00535     if (vif->u.sta.csa_occured)
    00536     {
    00537         mm_send_csa_traffic_ind(vif->index, true);
    00538         vif->u.sta.csa_occured = false;
    00539     }
    00540     #endif
    00541
    00542     #if (NX_P2P_GO)
    00543     // Remind that at least one beacon has been received
    00544     vif->u.sta.bcn_rcved = true;
    00545     #endif //(NX_P2P_GO)
    00546
    00547     // Check if we need to send a keep-alive frame
    00548     if ((ke_time_past(vif->u.sta.mon_last_tx + MM_KEEP_ALIVE_PERIOD)) &&
    00549             (txl_frame_send_null_frame(vif->u.sta.ap_id, NULL, NULL) == CO_OK))
    00550     {
    00551         // Update the keep-alive time
    00552         vif->u.sta.mon_last_tx = ke_time();
    00553     }
    00554
    00555     // Retrieve the RSSI values from the RX vector
    00556     rssi = hal_desc_get_rssi(&rhd->rx_vec_1, rx_rssi);
    00557
    00558     #if (NX_ANT_DIV)
    00559     // Update RSSI
    00560     mm_ant_div_update_rssi(rx_rssi);
    00561     #endif // (NX_ANT_DIV)
    00562
    00563     // Check if RSSI is below or above the threshold
    00564     mm_check_rssi(vif, rssi);
    00565
    00566     // Compute the beacon CRC to check if some fields have changed
    00567     vif->u.sta.mon_last_crc = mm_compute_beacon_crc(bcn, len, tim);
    00568     #else // NX_CONNECTION_MONITOR
    00569     *tim = mac_ie_tim_find(pbd->datastartptr + MAC_BEACON_VARIABLE_PART_OFT,
    00570                            len - MAC_BEACON_VARIABLE_PART_OFT);
    00571     #endif // NX_CONNECTION_MONITOR
    00572
    00573     #if NX_MULTI_ROLE
    00574     // Compute the time of the next TBTT
    00575     mm_tbtt_compute(bcn, len, rhd, vif, sta, *tim);
    00576     #endif
    00577
    00578     #if NX_CONNECTION_MONITOR
    00579     return (crc_prev != vif->u.sta.mon_last_crc);
    00580     #else
    00581     return (true);
    00582     #endif
    00583 }
    00584 #endif
    00585
    00586 void mm_reset(void)
    00587 {
    00588     // Check what was the state of the MM when the error occurred and behave accordingly
    00589     switch (ke_state_get(TASK_MM))
    00590     {
    00591         case MM_ACTIVE:
    00592             // MM was active or doze, so put back the HW in active state
    00593             mm_active();
    00594             break;
    00595
    00596         default:
    00597             // MM was IDLE, or going to IDLE, so set its state to IDLE
    00598             ke_state_set(TASK_MM, MM_IDLE);
    00599             break;
    00600     }
    00601 }
    00602
    00603 void mm_active(void)
    00604 {
    00605     // Put the HW in active state
    00606     nxmac_next_state_setf(HW_ACTIVE);
    00607     ke_state_set(TASK_MM, MM_ACTIVE);
    00608 }
    00609
    00610 #if NX_POWERSAVE || NX_CONNECTION_MONITOR || NX_MULTI_ROLE
    00611 void mm_sta_tbtt(void *env)
    00612 {
    00613     // Get the VIF entry from the env pointer
    00614     struct vif_info_tag *vif = (struct vif_info_tag *)env;
    00615     #if (NX_MULTI_ROLE || NX_CHNL_CTXT)
    00616     // TBTT Time
    00617     uint32_t tbtt_time, next_tbtt_time;
    00618     #endif //(NX_MULTI_ROLE || NX_CHNL_CTXT)
    00619
    00620     PROF_STA_TBTT_SET();
    00621     PROF_TBTT_IDX_SET(vif->chan_ctxt->idx);
    00622
    00623     do
    00624     {
    00625         if (!vif->active)
    00626             // STA is not associated, exit immediately
    00627             break;
    00628
    00629         #if NX_UMAC_PRESENT
    00630         if (vif->u.sta.csa_count)
    00631         {
    00632             vif->u.sta.csa_count--;
    00633             if (vif->u.sta.csa_count <= 1)
    00634             {
    00635                 vif_mgmt_switch_channel(vif);
    00636                 break;
    00637             }
    00638             else if (vif->u.sta.csa_count == 2)
    00639             {
    00640                 mm_send_csa_traffic_ind(vif->index, false);
    00641             }
    00642         }
    00643         #endif
    00644
    00645         #if (NX_MULTI_ROLE || NX_CHNL_CTXT)
    00646         tbtt_time = vif->tbtt_timer.time;
    00647         next_tbtt_time = tbtt_time + sta_info_tab[vif->u.sta.ap_id].bcn_int;
    00648         #endif //(NX_MULTI_ROLE || NX_CHNL_CTXT)
    00649
    00650         #if NX_MULTI_ROLE
    00651         // Program next TBTT based on previous TBTT
    00652         mm_timer_set(&vif->tbtt_timer, next_tbtt_time);
    00653         #endif
    00654
    00655         #if (NX_P2P || NX_CHNL_CTXT)
    00656         vif_mgmt_bcn_to_prog(vif);
    00657         #endif //(NX_P2P || NX_CHNL_CTXT)
    00658
    00659         #if (NX_P2P)
    00660         p2p_tbtt_handle(vif, tbtt_time + vif->u.sta.ctw_add_dur);
    00661         #endif //(NX_P2P)
    00662
    00663         #if (NX_CHNL_CTXT)
    00664         if (chan_tbtt_start(vif, tbtt_time, next_tbtt_time))
    00665             break;
    00666         #endif //(NX_CHNL_CTXT)
    00667
    00668         #if NX_POWERSAVE
    00669         vif->prevent_sleep |= PS_VIF_WAITING_BCN;
    00670         #endif
    00671
    00672         #if NX_CONNECTION_MONITOR
    00673         // Increase the beacon loss count (it will be reset upon beacon reception)
    00674         vif->u.sta.beacon_loss_cnt++;
    00675
    00676         // Check if we reached the beacon loss threshold
    00677         if (vif->u.sta.beacon_loss_cnt > MM_BEACON_LOSS_THD)
    00678         {
    00679             // No beacons received for a long time, send a NULL frame to the AP
    00680             txl_frame_send_null_frame(vif->u.sta.ap_id, mm_ap_probe_cfm, vif);
    00681         }
    00682         #if (NX_CHNL_CTXT)
    00683         else if (vif->u.sta.beacon_loss_cnt > (MM_BEACON_LOSS_THD - 1))
    00684         {
    00685             // Try to spend more time on channel in order to catch a beacon
    00686             chan_bcn_detect_start(vif);
    00687         }
    00688         #endif //(NX_CHNL_CTXT)
    00689         #endif
    00690
    00691         #if (NX_ANT_DIV)
    00692         // Check if an antenna switch is needed
    00693         mm_ant_div_check(vif->u.sta.beacon_loss_cnt);
    00694         #endif //(NX_ANT_DIV)
    00695
    00696     } while(0);
    00697     PROF_STA_TBTT_CLR();
    00698 }
    00699 #endif
    00700
    00701 #if NX_BEACONING
    00702
    00712 static void mm_ap_tbtt(uint32_t evt)
    00713 {
    00714     struct vif_info_tag *vif = (struct vif_info_tag *)co_list_pick(&vif_mgmt_env.used_list);
    00715
    00716     PROF_AP_TBTT_SET();
    00717
    00718     // Protect from interrupt while flushing the queue
    00719     GLOBAL_INT_DISABLE();
    00720
    00721     // Halt the beacon queue
    00722     txl_cntrl_halt_ac(AC_BCN);
    00723
    00724     // Flush the beacon queue in case some old packets are still blocked
    00725     txl_cntrl_flush_ac(AC_BCN, DESC_DONE_SW_TX_BIT);
    00726
    00727     // Reenable the interrupts
    00728     GLOBAL_INT_RESTORE();
    00729
    00730     while (vif != NULL)
    00731     {
    00732         switch (vif->type)
    00733         {
    00734             case (VIF_AP):
    00735             #if (RW_MESH_EN)
    00736             case (VIF_MESH_POINT):
    00737             #endif //(RW_MESH_EN)
    00738             {
    00739                 #if (NX_CHNL_CTXT || NX_P2P_GO)
    00740                 uint32_t beacon_int;
    00741                 uint32_t next_tbtt;
    00742                 #endif //(NX_CHNL_CTXT || NX_P2P_GO)
    00743
    00744                 #if (NX_UMAC_PRESENT)
    00745                 vif->u.ap.bcn_tbtt_cnt--;
    00746
    00747                 // Check if VIF has to send a beacon on this TBTT
    00748                 if (vif->u.ap.bcn_tbtt_cnt)
    00749                 {
    00750                     break;
    00751                 }
    00752
    00753                 // Reset the TBTT counter
    00754                 vif->u.ap.bcn_tbtt_cnt = vif->u.ap.bcn_tbtt_ratio;
    00755                 #endif //(NX_UMAC_PRESENT)
    00756
    00757                 #if (NX_CHNL_CTXT || NX_P2P_GO)
    00758                 // Program the Beacon Timeout timer
    00759                 vif_mgmt_bcn_to_prog(vif);
    00760                 #endif //(NX_P2P || NX_CHNL_CTXT)
    00761
    00762                 #if (NX_P2P_GO)
    00763                 p2p_tbtt_handle(vif, vif->tbtt_timer.time + HAL_MACHW_BCN_TX_DELAY_US +
    00764                                 MM_PRE_AP_TBTT_DELAY_US);
    00765                 #endif //(NX_P2P_GO)
    00766
    00767                 #if (NX_CHNL_CTXT || NX_P2P_GO)
    00768                 beacon_int = (uint32_t)vif->u.ap.bcn_int << 10;
    00769                 next_tbtt = nxmac_next_tbtt_get() << 5;
    00770                 if (next_tbtt < (HAL_MACHW_BCN_TX_DELAY_US + MM_PRE_AP_TBTT_DELAY_US))
    00771                     next_tbtt += beacon_int;
    00772                 next_tbtt += ke_time();
    00773                 next_tbtt -= (HAL_MACHW_BCN_TX_DELAY_US + MM_PRE_AP_TBTT_DELAY_US);
    00774                 #endif //(NX_CHNL_CTXT || NX_P2P_GO)
    00775
    00776                 #if (NX_CHNL_CTXT)
    00777                 if (vif->chan_ctxt != NULL)
    00778                 {
    00779                     chan_tbtt_start(vif, vif->tbtt_timer.time, next_tbtt);
    00780                 }
    00781                 #endif //(NX_CHNL_CTXT)
    00782
    00783                 #if (NX_P2P_GO)
    00784                 if (vif->p2p)
    00785                 {
    00786                     /*
    00787                      * When HW is in doze mode, it does not trigger the TBTT interrupt anymore. Hence we use a
    00788                      * timer in order to wake up slightly before AP_TBTT occurs
    00789                      */
    00790                     mm_timer_set(&vif->tbtt_timer, next_tbtt);
    00791                 }
    00792                 #endif //(NX_P2P_GO)
    00793             } break;
    00794
    00795             default:
    00796             {
    00797             } break;
    00798         }
    00799
    00800         // Go to next entry
    00801         vif = vif_mgmt_next(vif);
    00802     }
    00803
    00804     #if NX_BCN_AUTONOMOUS_TX
    00805     // Transmit the beacon(s)
    00806     mm_bcn_transmit();
    00807     #endif
    00808
    00809     PROF_AP_TBTT_CLR();
    00810 }
    00811 #endif
    00812
    00813 #if (NX_P2P_GO && NX_POWERSAVE)
    00814 void mm_ap_pre_tbtt(void *env)
    00815 {
    00816     // Get the VIF on which the TBTT will occur soon
    00817     struct vif_info_tag *vif = (struct vif_info_tag *)env;
    00818
    00819     // Inform the P2P module about the coming TBTT
    00820     p2p_go_pre_tbtt(vif);
    00821 }
    00822 #endif //(NX_P2P_GO && NX_POWERSAVE)
    00823
    00824 #if NX_BEACONING && ((NX_POWERSAVE || NX_CONNECTION_MONITOR || NX_UMAC_PRESENT) && !NX_MULTI_ROLE)
    00825 void mm_tbtt_evt(int dummy)
    00826 {
    00827     uint32_t evt = ke_evt_get() & MM_TBTT_EVT_MASK;
    00828     #if NX_POWERSAVE || NX_CONNECTION_MONITOR || NX_UMAC_PRESENT
    00829     // Get the current VIF entry. For the moment we support only one VIF in STA
    00830     // mode, so the first of the list is this one
    00831     struct vif_info_tag *vif =
    00832                         (struct vif_info_tag *)co_list_pick(&vif_mgmt_env.used_list);
    00833     #endif
    00834
    00835     PROF_HW_TBTT_EVT_SET();
    00836
    00837     // Sanity check - Primary and secondary TBTT events should not be active
    00838     // at the same time
    00839     ASSERT_ERR(evt != MM_TBTT_EVT_MASK);
    00840
    00841     // Clear the event
    00842     ke_evt_clear(evt);
    00843
    00844     #if NX_POWERSAVE || NX_CONNECTION_MONITOR
    00845     // Check if VIF is of STA type
    00846     if (vif->type == VIF_STA)
    00847     {
    00848         // Call the specific STA TBTT handler
    00849         mm_sta_tbtt(vif);
    00850     }
    00851     #if NX_BEACONING
    00852     else
    00853     #endif
    00854     #endif
    00855     {
    00856         #if NX_BEACONING
    00857         // Check if beaconing is enabled
    00858         if (mm_env.beaconing)
    00859         {
    00860             mm_ap_tbtt(evt);
    00861         }
    00862         #endif
    00863     }
    00864
    00865     PROF_HW_TBTT_EVT_CLR();
    00866 }
    00867 #elif ((NX_POWERSAVE || NX_CONNECTION_MONITOR || NX_UMAC_PRESENT) && !NX_MULTI_ROLE)
    00868 void mm_tbtt_evt(int dummy)
    00869 {
    00870     uint32_t evt = ke_evt_get() & MM_TBTT_EVT_MASK;
    00871     // Get the current VIF entry. For the moment we support only one VIF in STA
    00872     // mode, so the first of the list is this one
    00873     struct vif_info_tag *vif =
    00874                         (struct vif_info_tag *)co_list_pick(&vif_mgmt_env.used_list);
    00875
    00876     PROF_HW_TBTT_EVT_SET();
    00877
    00878     // Sanity check - Primary and secondary TBTT events should not be active
    00879     // at the same time
    00880     ASSERT_ERR(evt != MM_TBTT_EVT_MASK);
    00881
    00882     // Clear the event
    00883     ke_evt_clear(evt);
    00884
    00885     // Call the specific STA TBTT handler
    00886     mm_sta_tbtt(vif);
    00887
    00888     PROF_HW_TBTT_EVT_CLR();
    00889 }
    00890 #elif NX_BEACONING
    00891 void mm_tbtt_evt(int dummy)
    00892 {
    00893     uint32_t evt = ke_evt_get() & MM_TBTT_EVT_MASK;
    00894
    00895     PROF_HW_TBTT_EVT_SET();
    00896
    00897     // Sanity check - Primary and secondary TBTT events should not be active
    00898     // at the same time
    00899     ASSERT_ERR(evt != MM_TBTT_EVT_MASK);
    00900
    00901     // Clear the event
    00902     ke_evt_clear(evt);
    00903
    00904     // Call the AP specific TBTT handler
    00905     mm_ap_tbtt(evt);
    00906
    00907     PROF_HW_TBTT_EVT_CLR();
    00908 }
    00909 #endif
    00910
    00911 uint8_t mm_sec_machwaddr_wr(uint8_t sta_idx, uint8_t inst_nbr)
    00912 {
    00913     uint8_t hw_sta_idx;
    00914     struct sta_info_tag *sta = &sta_info_tab[sta_idx];
    00915     uint32_t enc_cntrl;
    00916
    00917     // Compute the HW STA index
    00918     hw_sta_idx = MM_SEC_DEFAULT_KEY_COUNT + sta_idx;
    00919
    00920     // Copy the MAC addr
    00921     nxmac_encr_mac_addr_low_set(sta->mac_addr.array[0] | (((uint32_t)sta->mac_addr.array[1]) << 16));
    00922     nxmac_encr_mac_addr_high_set(sta->mac_addr.array[2]);
    00923
    00924     // Reset the key data
    00925     nxmac_encr_key_0_set(0);
    00926     nxmac_encr_key_1_set(0);
    00927     nxmac_encr_key_2_set(0);
    00928     nxmac_encr_key_3_set(0);
    00929
    00930     // For AP vif, key ram is not cleared when STA is removed, ensure that there is only
    00931     // one entry for this MAC, by deleting previous one if present
    00932     nxmac_encr_cntrl_set(NXMAC_NEW_SEARCH_BIT);
    00933     do
    00934     {
    00935         enc_cntrl = nxmac_encr_cntrl_get();
    00936     } while(enc_cntrl & NXMAC_NEW_SEARCH_BIT);
    00937
    00938     if (!(enc_cntrl & NXMAC_SEARCH_ERROR_BIT))
    00939     {
    00940         uint8_t hw_sta_idx_prev = nxmac_key_index_ram_getf();
    00941
    00942         if (hw_sta_idx_prev != hw_sta_idx)
    00943         {
    00944             nxmac_encr_mac_addr_low_set(0xFFFFFFFF);
    00945             nxmac_encr_mac_addr_high_set(0xFFFFFFFF);
    00946             KEY_RAM_WR(hw_sta_idx_prev, 0, 0, 0, 0, 0);
    00947             nxmac_encr_mac_addr_low_set(sta->mac_addr.array[0] | (((uint32_t)sta->mac_addr.array[1]) << 16));
    00948             nxmac_encr_mac_addr_high_set(sta->mac_addr.array[2]);
    00949         }
    00950     }
    00951
    00952     // Write control field
    00953     // keyIdx, cType, vlanIdx, spp, usedefkey, cLen
    00954     KEY_RAM_WR(hw_sta_idx, 0, inst_nbr, 0, 1, 0);
    00955
    00956     return (hw_sta_idx);
    00957 }
    00958
    00959 uint8_t mm_sec_machwkey_wr(struct mm_key_add_req const *param)
    00960 {
    00961     uint8_t clen = 1;
    00962     uint8_t ctype = MM_SEC_CTYPE_NULL;
    00963     uint8_t key_idx_hw;
    00964     uint8_t sta_idx = param->sta_idx;
    00965     struct mac_sec_key const *key = &param->key;
    00966     uint8_t vlan_idx = param->inst_nbr;
    00967
    00968     // Get index to be written in the HW table
    00969     if (sta_idx == INVALID_STA_IDX)
    00970     {
    00971         #if NX_MFP
    00972         // For now Keys for MFP are not installed in hw
    00973         if (param->cipher_suite == MAC_CIPHER_BIP_CMAC_128)
    00974         {
    00975             key_idx_hw = MM_VIF_TO_MFP_KEY(param->key_idx, param->inst_nbr);
    00976             vif_mgmt_add_key(param, key_idx_hw);
    00977             return key_idx_hw;
    00978         }
    00979         #endif
    00980
    00981         // Default key index
    00982         key_idx_hw = MM_VIF_TO_KEY(param->key_idx, param->inst_nbr);
    00983
    00984         // Put an invalid MAC addr
    00985         nxmac_encr_mac_addr_low_set(0xFFFFFFFF);
    00986         nxmac_encr_mac_addr_high_set(0xFFFFFFFF);
    00987
    00988         #if (NX_UMAC_PRESENT)
    00989         // Set the key parameters to the VIF
    00990         vif_mgmt_add_key(param, key_idx_hw);
    00991         #endif
    00992     }
    00993     else
    00994     {
    00995         #if (RW_MESH_EN)
    00996         // Get VIF Information
    00997         struct vif_info_tag *vif = &vif_info_tab[param->inst_nbr];
    00998         #endif //(RW_MESH_EN)
    00999         struct sta_info_tag *sta = &sta_info_tab[sta_idx];
    01000
    01001         // Sanity check
    01002         ASSERT_ERR(sta_idx < STA_MAX);
    01003
    01004         // Pairwise key index
    01005         key_idx_hw = MM_STA_TO_KEY(sta_idx);
    01006
    01007         #if (RW_MESH_EN)
    01008         if (vif->type == VIF_MESH_POINT)
    01009         {
    01010             vlan_idx = sta->mlink_idx + NX_VIRT_DEV_MAX;
    01011
    01012             if (!param->pairwise)
    01013             {
    01014                 if (param->cipher_suite == MAC_CIPHER_CCMP)
    01015                 {
    01016                     // Peer Mesh Group Key Index
    01017                     key_idx_hw = MM_MLINK_TO_KEY(param->key_idx + 1, sta->mlink_idx);
    01018
    01019                     // Put an invalid MAC addr
    01020                     nxmac_encr_mac_addr_low_set(0xFFFFFFFF);
    01021                     nxmac_encr_mac_addr_high_set(0xFFFFFFFF);
    01022                 }
    01023                 #if (NX_UMAC_PRESENT)
    01024                 else
    01025                 {
    01026                     key_idx_hw = MM_STA_TO_MESH_MFP_KEY(param->key_idx, sta_idx);
    01027
    01028                     sta_mgmt_add_key(param, key_idx_hw);
    01029
    01030                     return (key_idx_hw);
    01031                 }
    01032                 #endif //(NX_UMAC_PRESENT)
    01033             }
    01034         }
    01035
    01036         if (param->pairwise)
    01037         #endif //(RW_MESH_EN)
    01038         {
    01039             #if (NX_UMAC_PRESENT)
    01040             // Set the key parameters to the STA
    01041             sta_mgmt_add_key(param, key_idx_hw);
    01042             #endif
    01043
    01044             // Copy MAC addr
    01045             nxmac_encr_mac_addr_low_set(sta->mac_addr.array[0] | (((uint32_t)sta->mac_addr.array[1]) << 16));
    01046             nxmac_encr_mac_addr_high_set(sta->mac_addr.array[2]);
    01047         }
    01048     }
    01049
    01050     // Get cType and cLen from Cipher Suite
    01051     mm_key_ram_param_get(param->cipher_suite, key, &ctype, &clen);
    01052
    01053     // Copy key data
    01054     nxmac_encr_key_0_set(key->array[0]);
    01055     nxmac_encr_key_1_set(key->array[1]);
    01056     nxmac_encr_key_2_set(key->array[2]);
    01057     nxmac_encr_key_3_set(key->array[3]);
    01058
    01059     #if RW_WAPI_EN
    01060     if (ctype == MM_SEC_CTYPE_WPI_SMS4)
    01061     {
    01062         nxmac_encr_wpi_int_key_0_set(key->array[4]);
    01063         nxmac_encr_wpi_int_key_1_set(key->array[5]);
    01064         nxmac_encr_wpi_int_key_2_set(key->array[6]);
    01065         nxmac_encr_wpi_int_key_3_set(key->array[7]);
    01066     }
    01067     #endif
    01068
    01069     // Write control field
    01070     // keyIdx, cType, vlanIdx, spp, usedefkey, cLen
    01071     KEY_RAM_WR(key_idx_hw, ctype, vlan_idx, param->spp, 0, clen);
    01072
    01073     return (key_idx_hw);
    01074 }
    01075
    01076 void mm_sec_machwkey_del(uint8_t hw_key_idx)
    01077 {
    01078
    01079     #if NX_MFP
    01080     if (hw_key_idx >= MM_SEC_MAX_KEY_NBR)
    01081     {
    01082         vif_mgmt_del_key(&vif_info_tab[MM_MFP_KEY_TO_VIF(hw_key_idx)],
    01083                          MM_MFP_KEY_TO_KEYID(hw_key_idx));
    01084         return;
    01085     }
    01086     #endif
    01087
    01088     // Get index to be written in the HW table
    01089     if (hw_key_idx >= MM_SEC_DEFAULT_KEY_COUNT)
    01090     {
    01091         // Pairwise key index
    01092         uint8_t sta_idx = MM_KEY_TO_STA(hw_key_idx);
    01093         struct sta_info_tag *sta = &sta_info_tab[sta_idx];
    01094         struct vif_info_tag *vif = &vif_info_tab[sta->inst_nbr];
    01095
    01096         #if (NX_UMAC_PRESENT)
    01097         sta_mgmt_del_key(sta);
    01098         #endif
    01099
    01100         // For AP VIF don't clear key ram so that AP is able to detect old STA still
    01101         // using the key. (If key is cleared MACHW will simply ignore frames encrypted
    01102         // with unknown key)
    01103         if (vif->type == VIF_AP)
    01104             return;
    01105
    01106         // Copy MAC addr
    01107         nxmac_encr_mac_addr_low_set(sta->mac_addr.array[0] | (((uint32_t)sta->mac_addr.array[1]) << 16));
    01108         nxmac_encr_mac_addr_high_set(sta->mac_addr.array[2]);
    01109     }
    01110     else
    01111     {
    01112         // Put an invalid MAC addr
    01113         nxmac_encr_mac_addr_low_set(0xFFFFFFFF);
    01114         nxmac_encr_mac_addr_high_set(0xFFFFFFFF);
    01115
    01116         #if (RW_MESH_EN)
    01117         if (hw_key_idx < MM_SEC_DEFAULT_VIF_KEY_COUNT)
    01118         #endif //(RW_MESH_EN)
    01119         {
    01120             #if (NX_UMAC_PRESENT)
    01121             vif_mgmt_del_key(&vif_info_tab[MM_KEY_TO_VIF(hw_key_idx)],
    01122                              MM_KEY_TO_KEYID(hw_key_idx));
    01123             #endif
    01124         }
    01125     }
    01126
    01127     // Reset the key data
    01128     nxmac_encr_key_0_set(0);
    01129     nxmac_encr_key_1_set(0);
    01130     nxmac_encr_key_2_set(0);
    01131     nxmac_encr_key_3_set(0);
    01132
    01133     // Write control field
    01134     // keyIdx, cType, vlanIdx, spp, usedefkey, cLen
    01135     KEY_RAM_WR(hw_key_idx, 0, 0, 0, 0, 0);
    01136 }
    01137
    01138 void mm_sec_machwaddr_del(uint8_t sta_idx)
    01139 {
    01140     uint8_t hw_sta_idx;
    01141
    01142     // Compute the HW STA index
    01143     hw_sta_idx = MM_SEC_DEFAULT_KEY_COUNT + sta_idx;
    01144
    01145     // Put an invalid MAC addr
    01146     nxmac_encr_mac_addr_low_set(0xFFFFFFFF);
    01147     nxmac_encr_mac_addr_high_set(0xFFFFFFFF);
    01148
    01149     // Reset the key data
    01150     nxmac_encr_key_0_set(0);
    01151     nxmac_encr_key_1_set(0);
    01152     nxmac_encr_key_2_set(0);
    01153     nxmac_encr_key_3_set(0);
    01154
    01155     // Write control field
    01156     // keyIdx, cType, vlanIdx, spp, usedefkey, cLen
    01157     KEY_RAM_WR(hw_sta_idx, 0, 0, 0, 0, 0);
    01158 }
    01159
    01160 void mm_hw_idle_evt(int dummy)
    01161 {
    01162     // Clear the event
    01163     ke_evt_clear(KE_EVT_HW_IDLE_BIT);
    01164
    01165     // Put the MM task in IDLE state
    01166     ke_state_set(TASK_MM, MM_IDLE);
    01167 }
    01168
    01169 #if NX_MULTI_ROLE
    01170 void mm_hw_info_set(struct mac_addr const *mac_addr)
    01171 {
    01172     // By default we are configured as STA
    01173     nxmac_ap_setf(0);
    01174     nxmac_bss_type_setf(1);
    01175     nxmac_mac_addr_hi_mask_set(MM_MAC_ADDR_MSK);
    01176
    01177     // Reset TSF
    01178     nxmac_tsf_lo_set(0);
    01179     nxmac_tsf_hi_set(0);
    01180
    01181     // Set the MAC address of the interface to the MAC HW
    01182     nxmac_mac_addr_low_set(mac_addr->array[0] | (((uint32_t)mac_addr->array[1]) << 16));
    01183     nxmac_mac_addr_hi_set(mac_addr->array[2]);
    01184
    01185     // Now that we have a MAC Address we are supposed to reply
    01186     nxmac_mac_cntrl_1_set(nxmac_mac_cntrl_1_get() & ~(NXMAC_DISABLE_ACK_RESP_BIT
    01187                             | NXMAC_DISABLE_CTS_RESP_BIT | NXMAC_DISABLE_BA_RESP_BIT));
    01188
    01189     // Enable reception of useful frames only
    01190     mm_rx_filter_umac_set(MM_RX_FILTER_ACTIVE);
    01191
    01192     // Configure RX path for active mode
    01193     rxl_hwdesc_monitor(false);
    01194 }
    01195
    01196 void mm_hw_ap_info_set(void)
    01197 {
    01198     // Enable the AP mode. This will trigger the beacon transmission at TBTT.
    01199     nxmac_ap_setf(1);
    01200
    01201     #if NX_UMAC_PRESENT
    01202     // Configure the RX filter to receive PS-poll and beacons from other networks
    01203     mm_rx_filter_umac_set(MM_RX_FILTER_ACTIVE | (NXMAC_ACCEPT_PS_POLL_BIT
    01204                                                | NXMAC_ACCEPT_ALL_BEACON_BIT));
    01205     #endif
    01206
    01207     // Configure RX path for active mode
    01208     rxl_hwdesc_monitor(false);
    01209
    01210     // Enable TBTT HW interrupt
    01211     nxmac_gen_int_ack_clear(MM_TBTT_IRQ_MASK);
    01212     nxmac_gen_int_enable_set(nxmac_gen_int_enable_get() | MM_TBTT_IRQ_MASK);
    01213 }
    01214
    01215 void mm_hw_ap_info_reset(void)
    01216 {
    01217     // Disable the AP mode
    01218     nxmac_ap_setf(0);
    01219
    01220     #if NX_UMAC_PRESENT
    01221     // Configure the RX filter to discard PS-poll and beacons from other networks
    01222     mm_rx_filter_umac_set(MM_RX_FILTER_ACTIVE);
    01223     #endif
    01224
    01225     // Configure RX path for active mode
    01226     rxl_hwdesc_monitor(false);
    01227
    01228     // Disable TBTT HW interrupt
    01229     nxmac_gen_int_ack_clear(MM_TBTT_IRQ_MASK);
    01230     nxmac_gen_int_enable_set(nxmac_gen_int_enable_get() & ~MM_TBTT_IRQ_MASK);
    01231 }
    01232 #else
    01233 void mm_hw_interface_info_set(uint8_t type, struct mac_addr const *mac_addr)
    01234 {
    01235     // Configure the modes according to the interface type
    01236     switch (type)
    01237     {
    01238         case VIF_AP:
    01239             nxmac_ap_setf(1);
    01240             nxmac_bss_type_setf(1);
    01241             nxmac_mac_addr_hi_mask_set(MM_MAC_ADDR_MSK);
    01242             nxmac_gen_int_ack_clear(MM_TBTT_IRQ_MASK);
    01243             nxmac_gen_int_enable_set(nxmac_gen_int_enable_get() | MM_TBTT_IRQ_MASK);
    01244             break;
    01245         case VIF_IBSS:
    01246             nxmac_ap_setf(0);
    01247             nxmac_bss_type_setf(0);
    01248             nxmac_mac_addr_hi_mask_set(0);
    01249             nxmac_gen_int_enable_set(nxmac_gen_int_enable_get() | MM_TBTT_IRQ_MASK);
    01250             break;
    01251         case VIF_MONITOR:
    01252         case VIF_STA:
    01253             nxmac_ap_setf(0);
    01254             nxmac_bss_type_setf(1);
    01255             nxmac_mac_addr_hi_mask_set(0);
    01256             #if NX_POWERSAVE || NX_CONNECTION_MONITOR || NX_UMAC_PRESENT
    01257             nxmac_gen_int_ack_clear(MM_TBTT_IRQ_MASK);
    01258             nxmac_gen_int_enable_set(nxmac_gen_int_enable_get() | MM_TBTT_IRQ_MASK);
    01259             #else
    01260             nxmac_gen_int_enable_set(nxmac_gen_int_enable_get() & ~MM_TBTT_IRQ_MASK);
    01261             #endif
    01262             break;
    01263         default:
    01264             ASSERT_ERR(0);
    01265             break;
    01266     }
    01267
    01268     // Reset TSF
    01269     nxmac_tsf_lo_set(0);
    01270     nxmac_tsf_hi_set(0);
    01271
    01272     // Set the MAC address of the interface to the MAC HW
    01273     nxmac_mac_addr_low_set(mac_addr->array[0] | (((uint32_t)mac_addr->array[1]) << 16));
    01274     nxmac_mac_addr_hi_set(mac_addr->array[2]);
    01275
    01276     // Now that we have a MAC Address we are supposed to reply
    01277     nxmac_mac_cntrl_1_set(nxmac_mac_cntrl_1_get() & ~(NXMAC_DISABLE_ACK_RESP_BIT
    01278                             | NXMAC_DISABLE_CTS_RESP_BIT | NXMAC_DISABLE_BA_RESP_BIT));
    01279
    01280     // Enable reception of useful frames only
    01281     mm_rx_filter_umac_set(MM_RX_FILTER_ACTIVE);
    01282
    01283     // Configure RX path for active mode
    01284     rxl_hwdesc_monitor(false);
    01285 }
    01286 #endif
    01287
    01288 #if (NX_AMPDU_TX)
    01289 bool mm_ba_agmt_tx_exists(uint8_t sta_idx, uint8_t tid)
    01290 {
    01291     #if (NX_UMAC_PRESENT)
    01292     return (sta_mgmt_get_tx_bam_idx(sta_idx, tid) != BAM_INVALID_TASK_IDX);
    01293     #else
    01294     // 0 buffer size -> no BA agreement has been set here
    01295     return (sta_mgmt_get_tx_buff_size(sta_idx, tid));
    01296     #endif //(NX_UMAC_PRESENT)
    01297 }
    01298 #endif //(NX_AMPDU_TX)
    01299
    01300 #if (NX_REORD || NX_UMAC_PRESENT)
    01301 bool mm_ba_agmt_rx_exists(uint8_t sta_idx, uint8_t tid)
    01302 {
    01303     #if (NX_UMAC_PRESENT)
    01304     return (sta_mgmt_get_rx_bam_idx(sta_idx, tid) != BAM_INVALID_TASK_IDX);
    01305     #else
    01306     // If the pointer to the reordering structure is NULL, does not exists
    01307     return (sta_info_tab[sta_idx].ba_agmts_rx[tid] != NULL);
    01308     #endif //(NX_UMAC_PRESENT)
    01309 }
    01310 #endif //(NX_REORD)
    01311
    01312 #if NX_BEACONING
    01313 int32_t mm_ap_tbtt_move(int32_t offset)
    01314 {
    01315     uint32_t time_to_next;
    01316     uint32_t tbtt_next;
    01317     uint32_t beacon_int = nxmac_beacon_int_getf() * TU_DURATION;
    01318     uint32_t prog_delay = beacon_int / 4;
    01319     uint32_t abs_offset = co_abs(offset);
    01320     uint32_t comp_margin = 100;  // Margin used to handle the inaccuracy in the delays
    01321
    01322     // Check if the TBTT move is possible and required
    01323     if (mm_env.tbtt_move_ongoing || (offset == 0))
    01324         return 0;
    01325
    01326     mm_env.tbtt_move_ongoing = true;
    01327
    01328     // Correct the offset, that should not be greater than half a beacon period
    01329     if ((offset > 0) && (abs_offset > (beacon_int/2)))
    01330         offset = (int32_t)(beacon_int/2);
    01331     else if ((offset < 0) && (abs_offset > (beacon_int/2)))
    01332         offset = -(int32_t)(beacon_int/2);
    01333
    01334     GLOBAL_INT_DISABLE();
    01335     time_to_next = nxmac_next_tbtt_get() * 32;
    01336     tbtt_next = hal_machw_time() + time_to_next;
    01337     // Two cases are possible, depending if the offset is positive or negative
    01338     if (offset > 0)
    01339     {
    01340         // Offset is positive so we will delay the TBTT by <abs_offset us>. In order to
    01341         // avoid getting a fake TBTT event from the HW <abs_offset us> after the previous
    01342         // TBTT, we need to modify the TSF at least <abs_offset us> after the previous TBTT,
    01343         // but not too close to the next one to ensure that the delay is done in time
    01344         uint32_t time_from_prev = beacon_int - time_to_next;
    01345
    01346         // If we don't have enough margin till the next TBTT, it is too late to apply the
    01347         // delay on it. We therefore program a timer to perform the delay one-fourth
    01348         // beacon interval before the TBTT after
    01349         if (time_to_next < prog_delay)
    01350         {
    01351             mm_env.tbtt_move_tmr.env = (void *)offset;
    01352             mm_timer_set(&mm_env.tbtt_move_tmr, tbtt_next + beacon_int - prog_delay);
    01353         }
    01354         // If we are less than abs_offset after the previous TBTT, we program a timer
    01355         // to perform the delay one-fourth beacon interval before the next TBTT
    01356         else if (time_from_prev < (abs_offset + comp_margin))
    01357         {
    01358             mm_env.tbtt_move_tmr.env = (void *)offset;
    01359             mm_timer_set(&mm_env.tbtt_move_tmr, tbtt_next - prog_delay);
    01360         }
    01361         // Otherwise we are in the window where we can request the delay immediately
    01362         else
    01363         {
    01364             mm_ap_tbtt_move_cb((void *)offset);
    01365         }
    01366     }
    01367     else
    01368     {
    01369         // Offset is negative so we will advance the TBTT by x us. In order to avoid
    01370         // missing a TBTT event from the HW, we need to modify the TSF at least x us
    01371         // before the next TBTT
    01372         // If we are early enough in the beacon period, we request the delay to be done
    01373         // immediately
    01374         if (time_to_next > (abs_offset + prog_delay))
    01375         {
    01376             mm_ap_tbtt_move_cb((void *)offset);
    01377         }
    01378         // Otherwise it might be too late to apply the delay immediately, so we program
    01379         // a timer to perform it just after the next TBTT
    01380         else
    01381         {
    01382             mm_env.tbtt_move_tmr.env = (void *)offset;
    01383             mm_timer_set(&mm_env.tbtt_move_tmr, tbtt_next + comp_margin);
    01384         }
    01385     }
    01386     GLOBAL_INT_RESTORE();
    01387
    01388     return offset;
    01389 }
    01390 #endif
    01391
    01392 void mm_back_to_host_idle(void)
    01393 {
    01394     // Sanity check - This function shall be called while HW is IDLE
    01395     ASSERT_ERR(ke_state_get(TASK_MM) == MM_HOST_BYPASSED);
    01396
    01397     // Change the state of the MM
    01398     if (mm_env.host_idle == 0)
    01399         mm_active();
    01400     else
    01401         ke_state_set(TASK_MM, MM_IDLE);
    01402 }
    01403
    01404 void mm_force_idle_req(void)
    01405 {
    01406     // Sanity check - The force IDLE procedure shall not be performed while the NO IDLE
    01407     // state is present for a beacon transmission. If this assertion is triggered it
    01408     // probably means that the scheduling of a channel switch is done at a bad time.
    01409     ASSERT_ERR(ke_state_get(TASK_MM) != MM_NO_IDLE);
    01410
    01411     // Disable interrupts
    01412     GLOBAL_INT_DISABLE();
    01413
    01414     // Reset the MAC HW (this will reset the PHY too)
    01415     hal_machw_reset();
    01416
    01417     // Reset the RX path
    01418     rxl_reset();
    01419
    01420     // Reset the TX path
    01421     txl_reset();
    01422
    01423     // Reset the MM state
    01424     ke_state_set(TASK_MM, MM_HOST_BYPASSED);
    01425     mm_env.prev_mm_state = MM_IDLE;
    01426     mm_env.prev_hw_state = HW_IDLE;
    01427
    01428     // Restore the interrupts
    01429     GLOBAL_INT_RESTORE();
    01430 }
    01431
    01432 void mm_no_idle_start(void)
    01433 {
    01434     ASSERT_ERR((ke_state_get(TASK_MM) != MM_HOST_BYPASSED) &&
    01435                (ke_state_get(TASK_MM) != MM_IDLE));
    01436
    01437     if (ke_state_get(TASK_MM) == MM_GOING_TO_IDLE)
    01438     {
    01439         nxmac_next_state_setf(HW_ACTIVE);
    01440         GLOBAL_INT_DISABLE();
    01441         ke_evt_clear(KE_EVT_HW_IDLE_BIT);
    01442         if (nxmac_status_idle_interrupt_getf())
    01443         {
    01444             nxmac_gen_int_ack_clear(NXMAC_IDLE_INTERRUPT_BIT);
    01445         }
    01446         GLOBAL_INT_RESTORE();
    01447     }
    01448     ke_state_set(TASK_MM, MM_NO_IDLE);
    01449 }
    01450
    01451 void mm_no_idle_stop(void)
    01452 {
    01453     if (ke_state_get(TASK_MM) == MM_NO_IDLE)
    01454         ke_state_set(TASK_MM, MM_ACTIVE);
    01455 }
    01456
    01457 uint8_t mm_sta_add(struct mm_sta_add_req const *param, uint8_t  *sta_idx,
    01458                    uint8_t *hw_sta_idx)
    01459 {
    01460     uint8_t status;
    01461
    01462     // Register the new station
    01463     status = sta_mgmt_register(param, sta_idx);
    01464
    01465     // Check if the registration was successful
    01466     if (status == CO_OK)
    01467     {
    01468         struct vif_info_tag *vif = &vif_info_tab[param->inst_nbr];
    01469         struct sta_info_tag *sta = &sta_info_tab[*sta_idx];
    01470
    01471         // Compute the HW STA index
    01472         *hw_sta_idx = mm_sec_machwaddr_wr(*sta_idx, param->inst_nbr);
    01473         if (sta->linked_sta)
    01474         {
    01475             mm_sec_machwaddr_wr(sta->linked_sta->staid, param->inst_nbr);
    01476         }
    01477
    01478         // Check if the VIF is of STA type
    01479         #if NX_TDLS
    01480         if ((vif->type == VIF_STA) && (!param->tdls_sta))
    01481         #else
    01482         if (vif->type == VIF_STA)
    01483         #endif
    01484         {
    01485             // We save the AP index for later use
    01486             vif->u.sta.ap_id = *sta_idx;
    01487             vif->u.sta.bssid_index = param->bssid_index;
    01488             vif->u.sta.max_bssid_ind = param->max_bssid_ind;
    01489         }
    01490         #if (RW_UMESH_EN)
    01491         else if (vif->type == VIF_MESH_POINT)
    01492         {
    01493             // Inform the Mesh Module that the STA is now registered
    01494             mesh_add_sta_cfm(param->inst_nbr, *sta_idx);
    01495         }
    01496         #endif //(RW_UMESH_EN)
    01497     }
    01498
    01499     return (status);
    01500 }
    01501
    01502 void mm_sta_del(uint8_t sta_idx)
    01503 {
    01504     struct sta_info_tag *sta = &sta_info_tab[sta_idx];
    01505     struct vif_info_tag *vif = &vif_info_tab[sta->inst_nbr];
    01506
    01507     // Check if the VIF is of STA type
    01508     if ((vif->type == VIF_STA)
    01509         #if NX_TDLS
    01510         && !sta->is_tdls
    01511         #endif
    01512        )
    01513     {
    01514         // We save the AP index for later use
    01515         vif->u.sta.ap_id = INVALID_STA_IDX;
    01516     }
    01517     #if (NX_UMAC_PRESENT || NX_P2P_GO)
    01518     else
    01519     {
    01520         #if (RW_UMESH_EN)
    01521         if (vif->type == VIF_MESH_POINT)
    01522         {
    01523             // Inform the Mesh Module that the STA has been unregistered
    01524             mesh_del_sta_cfm(sta->mlink_idx);
    01525         }
    01526         #endif //(RW_UMESH_EN)
    01527
    01528         // Check if the station is in PS or not
    01529         if (sta->ps_state == PS_MODE_ON)
    01530         {
    01531             // Update the number of PS stations
    01532             vif->u.ap.ps_sta_cnt--;
    01533
    01534             #if (NX_UMAC_PRESENT)
    01535             if (!vif->u.ap.ps_sta_cnt)
    01536             {
    01537                 PROF_PS_BCMC_STATE_SET();
    01538                 PROF_PS_STATE_VAL_SET(PS_MODE_OFF);
    01539                 mm_ps_change_ind(VIF_TO_BCMC_IDX(vif->index), PS_MODE_OFF);
    01540                 #if NX_BEACONING
    01541                 apm_tx_int_ps_clear(vif, VIF_TO_BCMC_IDX(vif->index));
    01542                 #endif // NX_BEACONING
    01543                 PROF_PS_BCMC_STATE_CLR();
    01544             }
    01545             #endif //(NX_UMAC_PRESENT)
    01546         }
    01547     }
    01548     #endif //(NX_UMAC_PRESENT || NX_P2P_GO)
    01549
    01550     // Delete the station MAC address from the key storage, except for AP vif so that
    01551     // AP can detect STA still using old key.
    01552     if (vif->type != VIF_AP)
    01553     {
    01554         mm_sec_machwaddr_del(sta_idx);
    01555         if (sta->linked_sta)
    01556         {
    01557             mm_sec_machwaddr_del(sta->linked_sta->staid);
    01558         }
    01559     }
    01560
    01561     // Unregister the station
    01562     sta_mgmt_unregister(sta_idx);
    01563 }
    01564
    01565 #if (NX_CONNECTION_MONITOR)
    01566 void mm_send_connection_loss_ind(struct vif_info_tag *vif)
    01567 {
    01568     // Otherwise, we consider that the connection is lost
    01569     struct mm_connection_loss_ind *ind =
    01570        KE_MSG_ALLOC(MM_CONNECTION_LOSS_IND, TASK_IND, TASK_MM, mm_connection_loss_ind);
    01571
    01572     // Fill-in the indication message parameters
    01573     ind->inst_nbr = vif->index;
    01574
    01575     // Send the indication to the upper layers
    01576     ke_msg_send(ind);
    01577 }
    01578 #endif //(NX_CONNECTION_MONITOR)
    01579
    01580 void mm_check_rssi(struct vif_info_tag *vif, int8_t rssi)
    01581 {
    01582     int8_t rssi_old = vif->u.sta.rssi;
    01583     int8_t rssi_thold = vif->u.sta.rssi_thold;
    01584     int8_t rssi_hyst = vif->u.sta.rssi_hyst;
    01585     bool rssi_status = vif->u.sta.rssi_status;
    01586
    01587     // Update current RSSI
    01588     vif->u.sta.rssi = rssi;
    01589
    01590     // Check if threshold is set
    01591     if (rssi_thold == 0)
    01592         return;
    01593
    01594     // Check RSSI
    01595     if ((rssi_status == 0) && (rssi < rssi_old) && (rssi < (rssi_thold - rssi_hyst)))
    01596     {
    01597         rssi_status = 1;
    01598     }
    01599     else if ((rssi_status == 1) && (rssi > rssi_old) && (rssi > (rssi_thold + rssi_hyst)))
    01600     {
    01601         rssi_status = 0;
    01602     }
    01603
    01604     if (rssi_status != vif->u.sta.rssi_status)
    01605     {
    01606         // If RSSI status is changed send MM_RSSI_STATUS_IND message
    01607         struct mm_rssi_status_ind *ind =
    01608            KE_MSG_ALLOC(MM_RSSI_STATUS_IND, TASK_API, TASK_MM, mm_rssi_status_ind);
    01609
    01610         // Fill-in the indication message parameters
    01611         ind->vif_index = vif->index;
    01612         ind->rssi_status = rssi_status;
    01613         ind->rssi = rssi;
    01614
    01615         // Send the indication to the upper layers
    01616         ke_msg_send(ind);
    01617     }
    01618
    01619     // Update current RSSI status
    01620     vif->u.sta.rssi_status = rssi_status;
    01621 }
    01622
    01623 #if NX_UMAC_PRESENT
    01624 void mm_send_pktloss_ind(struct vif_info_tag *vif, uint8_t sta_idx, uint32_t num_pkts)
    01625 {
    01626
    01627     struct sta_info_tag *sta = &sta_info_tab[sta_idx];
    01628     struct mm_pktloss_ind *ind =
    01629        KE_MSG_ALLOC(MM_PKTLOSS_IND, TASK_API, TASK_MM, mm_pktloss_ind);
    01630
    01631     // Fill-in the indication message parameters
    01632     ind->vif_index = vif->index;
    01633     MAC_ADDR_CPY(&ind->mac_addr, &sta->mac_addr);
    01634     ind->num_packets = num_pkts;
    01635
    01636     // Send the indication to the upper layers
    01637     ke_msg_send(ind);
    01638 }
    01639
    01640 void mm_send_csa_traffic_ind(uint8_t vif_index, bool enable)
    01641 {
    01642     struct mm_csa_traffic_ind *ind = KE_MSG_ALLOC(MM_CSA_TRAFFIC_IND, TASK_API, TASK_MM,
    01643                                                   mm_csa_traffic_ind);
    01644     ind->vif_index = vif_index;
    01645     ind->enable = enable;
    01646     ke_msg_send(ind);
    01647 }
    01648 #endif
    01649
    01650 #if (NX_ANT_DIV)
    01651 void mm_ant_div_init(bool enable)
    01652 {
    01653     // Set enable flag
    01654     mm_env.ant_div.enable = enable;
    01655     // Set switch enable flag
    01656     mm_env.ant_div.sw_enable = enable;
    01657     // Reset number of active VIFs
    01658     mm_env.ant_div.nvif_active = 0;
    01659     // Reset RSSI values (current and initial) for both antennas
    01660     mm_ant_div_reset_rssi(0);
    01661     mm_ant_div_reset_rssi(1);
    01662 }
    01663
    01664 void mm_ant_div_switch_and_stop(void)
    01665 {
    01666     // Check if antenna diversity algorithm is enabled and
    01667     // no other connection is active
    01668     if (mm_env.ant_div.enable && (mm_env.ant_div.nvif_active == 0))
    01669     {
    01670         // Switch antenna paths before running a scan
    01671         mm_ant_div_switch_antenna();
    01672     }
    01673     // Disable switch
    01674     mm_env.ant_div.sw_enable = 0;
    01675 }
    01676
    01677 void mm_ant_div_update(void)
    01678 {
    01679     // Disable antenna switch if more than 1 connection is already active
    01680     if (!mm_env.ant_div.enable || (mm_env.ant_div.nvif_active > 1))
    01681     {
    01682         mm_env.ant_div.sw_enable = 0;
    01683         if (phy_get_nrx() == 0)
    01684         {
    01685             // Reset RSSI values (current and initial) for both antennas
    01686             mm_ant_div_reset_rssi(0);
    01687             mm_ant_div_reset_rssi(1);
    01688             // Reset update counter
    01689             mm_env.ant_div.update_cnt = 0;
    01690             // Keep in mind we need to update the initial RSSI for the current antenna
    01691             mm_env.ant_div.init_rssi_upd_req = 1;
    01692         }
    01693     }
    01694     else
    01695     {
    01696         mm_env.ant_div.sw_enable = 1;
    01697     }
    01698 }
    01699
    01700 void mm_ant_div_restore(bool active)
    01701 {
    01702     // Update number of active NVIFs
    01703     if (active)
    01704     {
    01705         mm_env.ant_div.nvif_active += 1;
    01706     }
    01707     else
    01708     {
    01709         mm_env.ant_div.nvif_active -= 1;
    01710     }
    01711     // Update antenna switch flag
    01712     mm_ant_div_update();
    01713 }
    01714
    01715 void mm_ant_div_switch_antenna(void)
    01716 {
    01717     // Check if antenna switch is enabled
    01718     if (!mm_env.ant_div.sw_enable)
    01719     {
    01720         return;
    01721     }
    01722     dbg(D_INF D_MM "Antenna diversity: switch antenna %d --> %d\n",
    01723         mm_env.ant_div.cur_ant, !mm_env.ant_div.cur_ant);
    01724     // Switch antenna
    01725     mm_env.ant_div.cur_ant = phy_switch_antenna_paths();
    01726     if (phy_get_nrx() == 0)
    01727     {
    01728         // Reset update counter
    01729         mm_env.ant_div.update_cnt = 0;
    01730         // Keep in mind we need to update the initial RSSI for the current antenna
    01731         mm_env.ant_div.init_rssi_upd_req = 1;
    01732     }
    01733 }
    01734
    01735 void mm_ant_div_reset_rssi(uint8_t ant)
    01736 {
    01737     // Reset current RSSI
    01738     mm_env.ant_div.rssi[ant] = ANT_DIV_RSSI_RESET;
    01739     // Reset initial RSSI
    01740     mm_env.ant_div.init_rssi[ant] = ANT_DIV_RSSI_RESET;
    01741 }
    01742
    01743 void mm_ant_div_update_rssi(int8_t *rx_rssi)
    01744 {
    01745     ASSERT_ERR(rx_rssi != NULL);
    01746     // Pointer to the antenna diversity structure
    01747     struct antenna_diversity *ant_div = &mm_env.ant_div;
    01748     // Update RSSI values
    01749     if (phy_get_nrx() == 0)
    01750     {
    01751         // Update current RSSI value
    01752         ant_div->rssi[ant_div->cur_ant] = rx_rssi[0];
    01753         // Update initial RSSI value if requested
    01754         if (ant_div->init_rssi_upd_req)
    01755         {
    01756             ant_div->init_rssi[ant_div->cur_ant] = rx_rssi[0];
    01757             ant_div->init_rssi_upd_req = 0;
    01758         }
    01759     }
    01760     else
    01761     {
    01762         // Update current RSSI values
    01763         ant_div->rssi[ant_div->cur_ant] = rx_rssi[0];
    01764         ant_div->rssi[!ant_div->cur_ant] = rx_rssi[1];
    01765     }
    01766 }
    01767
    01768 void mm_ant_div_check(uint8_t beacon_loss_cnt)
    01769 {
    01770     // Check if antenna switch is enabled
    01771     if (!mm_env.ant_div.sw_enable)
    01772     {
    01773         return;
    01774     }
    01775     // Pointer to the antenna diversity structure
    01776     struct antenna_diversity *ant_div = &mm_env.ant_div;
    01777     // Check if antenna switch is needed in case of 1x1 station
    01778     if (phy_get_nrx() == 0)
    01779     {
    01780         // Boolean used to request a switch of antenna
    01781         bool switch_antenna = 0;
    01782         // Distance from current antenna RSSI and the golden range
    01783         uint8_t gr_dist_cur = 0;
    01784         // Distance from the other antenna RSSI and the golden range
    01785         uint8_t gr_dist_other = 0;
    01786         // Current RSSI
    01787         int8_t cur_rssi = ant_div->rssi[ant_div->cur_ant];
    01788         // Current initial RSSI
    01789         int8_t cur_init_rssi = ant_div->init_rssi[ant_div->cur_ant];
    01790         // Other antenna RSSI
    01791         int8_t other_rssi = ant_div->rssi[!ant_div->cur_ant];
    01792
    01793         // Update counter of beacon periods without any antenna switch
    01794         ant_div->update_cnt++;
    01795
    01796         // Get distance from golden range for the current antenna RSSI
    01797         gr_dist_cur = mm_get_golden_range_distance(cur_rssi);
    01798         // Get distance from golden range for the other antenna RSSI
    01799         gr_dist_other = mm_get_golden_range_distance(other_rssi);
    01800         // Check if antenna diversity beacon loss threshold is exceeded
    01801         if (beacon_loss_cnt > ANT_DIV_BEACON_LOSS_THD)
    01802         {
    01803             // Reset current antenna RSSI values
    01804             mm_ant_div_reset_rssi(ant_div->cur_ant);
    01805             // Keep in mind that the antenna should be switched
    01806             switch_antenna = 1;
    01807         }
    01808         // Switch antenna if distance from golden range of the other RSSI is less than
    01809         // distance from golden range of the current RSSI
    01810         else if (gr_dist_other < gr_dist_cur)
    01811         {
    01812             switch_antenna = 1;
    01813         }
    01814         // Switch antenna if current antenna RSSI is changed of more than ANT_DIV_RSSI_STEP_CHANGE
    01815         // compared to its initial RSSI
    01816         else if ((cur_rssi < ANT_DIV_RSSI_GOLDEN_MIN) &&
    01817                  (cur_rssi < (cur_init_rssi - ANT_DIV_RSSI_STEP_CHANGE)))
    01818         {
    01819             switch_antenna = 1;
    01820         }
    01821         else if ((cur_rssi > ANT_DIV_RSSI_GOLDEN_MAX) &&
    01822                  (cur_rssi > (cur_init_rssi + ANT_DIV_RSSI_STEP_CHANGE)))
    01823         {
    01824             switch_antenna = 1;
    01825         }
    01826         // Check if current RSSI is ouside the golden range and the current antenna has not
    01827         // been switched for at least ANT_DIV_UPDATE_CNT_THD beacon periods
    01828         else if (((cur_rssi < ANT_DIV_RSSI_GOLDEN_MIN) ||
    01829                  (cur_rssi > ANT_DIV_RSSI_GOLDEN_MAX)) &&
    01830                  (ant_div->update_cnt > ANT_DIV_UPDATE_CNT_THD))
    01831         {
    01832             // Keep in mind that the antenna should be switched
    01833             switch_antenna = 1;
    01834         }
    01835         // Switch antenna if requested
    01836         if (switch_antenna)
    01837         {
    01838             dbg(D_INF D_MM "Antenna diversity: "
    01839                 "Ant%d=%d(%d) Ant%d=%d(%d) / Gold_range=[%d:%d] / Upd_cnt=%d\n",
    01840                 ant_div->cur_ant, cur_rssi, cur_init_rssi,
    01841                 !ant_div->cur_ant, other_rssi, ant_div->init_rssi[!ant_div->cur_ant],
    01842                 ANT_DIV_RSSI_GOLDEN_MIN, ANT_DIV_RSSI_GOLDEN_MAX, mm_env.ant_div.update_cnt);
    01843             // Request an antenna switch
    01844             ke_msg_send_basic(MM_SWITCH_ANTENNA_REQ, TASK_MM, TASK_NONE);
    01845         }
    01846     }
    01847     // Check if antenna switch is needed in case of 2x2 station
    01848     else
    01849     {
    01850         // Check RSSI on both antennas and select the best one as primary antenna
    01851         int8_t rssi_0 = ant_div->rssi[ant_div->cur_ant];
    01852         int8_t rssi_1 = ant_div->rssi[!ant_div->cur_ant];
    01853         if (rssi_1 > (rssi_0 + ANT_DIV_RSSI_THD))
    01854         {
    01855             dbg(D_INF D_MM "Antenna diversity: Ant%d=%d Ant%d=%d\n",
    01856                 ant_div->cur_ant, rssi_0, !ant_div->cur_ant, rssi_1);
    01857             // Switch antenna
    01858             mm_ant_div_switch_antenna();
    01859         }
    01860     }
    01861 }
    01862 #endif //(NX_ANT_DIV)
    01863