- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# /space/home/slher/rel/Beken/v6_4_5/macsw/ip/umac/src/me/me_mgmtframe.c

Go to the documentation of this file.

    00001
    00013 #include "me_mgmtframe.h"
    00014 #include "mac_frame.h"
    00015 #include "mac_ie.h"
    00016 #include "mac.h"
    00017 #include "me.h"
    00018 #include "sm_task.h"
    00019 #include "ps.h"
    00020 // for endian functions
    00021 #include "co_endian.h"
    00022 // for read/writes
    00023 #include "co_utils.h"
    00024 #include "me_utils.h"
    00025 #include "sta_mgmt.h"
    00026
    00027
    00029 #define ME_DEFAULT_LISTEN_INTERVAL   5
    00030
    00039 static void me_add_baparamset_frame(uint32_t addr, struct bam_env_tag *bam_env)
    00040 {
    00041     uint16_t value = 0;
    00042
    00043     /* The Block Ack Parameter Set field
    00044      *
    00045      *******************************************************************
    00046      *  B0              *  B1               * (B2 -> B5)*  (B6->B15)   *
    00047      *  A-MSD Supported *  Block Ack Policy * TID       *  Buffer Size *
    00048      *******************************************************************
    00049      *
    00050      */
    00051
    00052     // Fill the A-MSDU Supported bit
    00053     // TODO[LT] - Set A-MSDU Supported bit
    00054 //    value = mib_AggregationConfigTable.AllowAMsduWithBA[tid_info_tab[bam_env->tid].access_category];
    00055     value |= 0;
    00056     // Fill the Block Ack Policy bit
    00057     value |= (bam_env->ba_policy << MAC_BA_PARAMSET_POLICY_OFT);
    00058     // Fill the TID bits
    00059     value |= (bam_env->tid << MAC_BA_PARAMSET_TID_OFT);
    00060     // Fill the Buffer Size bits
    00061     value |= (bam_env->buffer_size << MAC_BA_PARAMSET_BUFFER_OFT);
    00062
    00063     co_write16p(addr, co_htows(value));
    00064 }
    00065
    00074 static void me_add_ba_ssc_frame(uint32_t addr, struct bam_env_tag *bam_env)
    00075 {
    00076     co_write16p(addr, co_htows(bam_env->ssn << MAC_BA_BARINFO_SEQ_STARTSEQ_OFT));
    00077 }
    00078
    00087 static void me_del_baparamset_frame(uint32_t addr, struct bam_env_tag *bam_env)
    00088 {
    00089     /* The DELBA Parameter Set field
    00090      *
    00091      ******************************************
    00092      *  B0->B10   *   B11       * (B12 -> B15)*
    00093      *  Reserved  *  Initiator  * TID         *
    00094      ******************************************
    00095      *
    00096      */
    00097     uint16_t value = 0;
    00098
    00099     // Set the value of the TID
    00100     value |= bam_env->tid << BAM_DELBA_PARAM_TID_OFFSET;
    00101
    00102     if (bam_env->dev_type == BA_ORIGINATOR)
    00103     {
    00104         value |= BAM_DELBA_PARAM_INITIATOR_MASK;
    00105     }
    00106
    00107     co_write16p(addr, co_htows(value));
    00108 }
    00109
    00110 /*
    00111  * Information Element Management
    00112  ****************************************************************************************
    00113  */
    00114
    00115 uint32_t me_add_ie_ssid(uint32_t *frame_addr, uint8_t ssid_len, uint8_t *ssid)
    00116 {
    00117     // Element length
    00118     uint32_t ie_len = MAC_INFOELT_INFO_OFT + ssid_len;
    00119
    00120     // Tag Number - SSID
    00121     co_write8p(*frame_addr + MAC_INFOELT_ID_OFT, MAC_ELTID_SSID);
    00122     // Tag Length
    00123     co_write8p(*frame_addr + MAC_INFOELT_LEN_OFT, ssid_len);
    00124
    00125     if (ssid_len != 0)
    00126     {
    00127         // Copy the SSID
    00128         co_pack8p(*frame_addr + MAC_INFOELT_INFO_OFT, (uint8_t *)ssid, ssid_len);
    00129     }
    00130
    00131     // Update the position in the frame
    00132     *frame_addr += ie_len;
    00133
    00134     // And the written length
    00135     return (ie_len);
    00136 }
    00137
    00138 uint32_t me_add_ie_supp_rates(uint32_t *frame_addr, struct mac_rateset *rateset)
    00139 {
    00140     // Length for Supported Rates - Only up to 8 rates can be added in the supported rate element
    00141     uint32_t supp_len = co_min(rateset->length, MAC_RATES_ELMT_MAX_LEN);
    00142     // Element length
    00143     uint32_t ie_len = MAC_INFOELT_INFO_OFT + supp_len;
    00144
    00145     // Tag Number - Supported Rates
    00146     co_write8p(*frame_addr + MAC_INFOELT_ID_OFT, MAC_ELTID_RATES);
    00147     // Tag Length
    00148     co_write8p(*frame_addr + MAC_INFOELT_LEN_OFT, supp_len);
    00149
    00150     // Copy the rates
    00151     co_pack8p(*frame_addr + MAC_INFOELT_INFO_OFT, rateset->array, supp_len);
    00152
    00153     // Update the frame pointer
    00154     *frame_addr += ie_len;
    00155
    00156     // And the written length
    00157     return (ie_len);
    00158 }
    00159
    00160 uint32_t me_add_ie_ext_supp_rates(uint32_t *frame_addr, struct mac_rateset *rateset)
    00161 {
    00162     // Length for Extended Supported Rates
    00163     uint32_t ext_supp_len = rateset->length - MAC_RATES_ELMT_MAX_LEN;
    00164     // Element length
    00165     uint32_t ie_len = MAC_INFOELT_INFO_OFT + ext_supp_len;
    00166
    00167     // Tag Number - Extended Supported Rates
    00168     co_write8p(*frame_addr + MAC_INFOELT_ID_OFT, MAC_ELTID_EXT_RATES);
    00169     // Tag Length
    00170     co_write8p(*frame_addr + MAC_INFOELT_LEN_OFT, ext_supp_len);
    00171
    00172     // Copy the rates
    00173     co_pack8p(*frame_addr + MAC_INFOELT_INFO_OFT, &rateset->array[MAC_RATES_ELMT_MAX_LEN],
    00174               ext_supp_len);
    00175
    00176     // Update the frame pointer
    00177     *frame_addr += ie_len;
    00178
    00179     // And the written length
    00180     return (ie_len);
    00181 }
    00182
    00183 #if (RW_MESH_EN)
    00184 uint32_t me_add_ie_tim(uint32_t *frame_addr, uint8_t dtim_period)
    00185 {
    00186     // Element length
    00187     uint32_t ie_len = MAC_INFOELT_INFO_OFT + 4;
    00188
    00189     // Tag Number - TIM
    00190     co_write8p(*frame_addr + MAC_INFOELT_ID_OFT, MAC_ELTID_TIM);
    00191     // Tag Length
    00192     co_write8p(*frame_addr + MAC_INFOELT_LEN_OFT, 4);
    00193
    00194     // Write DTIM Period
    00195     co_write8p(*frame_addr + MAC_TIM_PERIOD_OFT, dtim_period);
    00196     // Other parameters will be updated in mm_bcn module before beacon transmission
    00197
    00198     // Update the position in the frame
    00199     *frame_addr += ie_len;
    00200
    00201     // And the written length
    00202     return (ie_len);
    00203 }
    00204
    00205 uint32_t me_add_ie_dsss_param(uint32_t *frame_addr, uint8_t chan)
    00206 {
    00207     // Element length
    00208     uint32_t ie_len = MAC_INFOELT_INFO_OFT + 1;
    00209
    00210     // Tag Number - DS Parameter Set
    00211     co_write8p(*frame_addr + MAC_INFOELT_ID_OFT, MAC_ELTID_DS);
    00212     // Tag Length
    00213     co_write8p(*frame_addr + MAC_INFOELT_LEN_OFT, 1);
    00214
    00215     // Copy the Channel
    00216     co_write8p(*frame_addr + MAC_INFOELT_INFO_OFT, chan);
    00217
    00218     // Update the position in the frame
    00219     *frame_addr += ie_len;
    00220
    00221     // And return the written length
    00222     return (ie_len);
    00223 }
    00224 #endif //(RW_MESH_EN)
    00225
    00226 uint32_t me_add_ie_ht_capa(uint32_t *frame_addr)
    00227 {
    00228     // Element length
    00229     uint32_t ie_len = MAC_INFOELT_INFO_OFT + MAC_HT_CAPA_ELMT_LEN;
    00230     // Get Local HT Capabilities
    00231     struct mac_htcapability *ht_cap = &me_env.ht_cap;
    00232     uint16_t ht_capa_info = ht_cap->ht_capa_info & ~MAC_HTCAPA_SMPS_MSK;
    00233
    00234     // Tag Number - HT Capabilities
    00235     co_write8p(*frame_addr + MAC_HT_CAPA_ID_OFT, MAC_ELTID_HT_CAPA);
    00236     // Tag Length
    00237     co_write8p(*frame_addr + MAC_HT_CAPA_LEN_OFT, MAC_HT_CAPA_ELMT_LEN);
    00238
    00239     ht_capa_info |= MAC_HTCAPA_SMPS_DISABLE;
    00240     co_write16p(*frame_addr + MAC_HT_CAPA_INFO_OFT, co_htows(ht_capa_info));
    00241     co_write8p(*frame_addr + MAC_HT_CAPA_AMPDU_PARAM_OFT, ht_cap->a_mpdu_param);
    00242     co_pack8p(*frame_addr + MAC_HT_CAPA_SUPPORTED_MCS_SET_OFT, ht_cap->mcs_rate,
    00243               MAX_MCS_LEN);
    00244     co_write16p(*frame_addr + MAC_HT_CAPA_EXTENDED_CAPA_OFT, co_htows(ht_cap->ht_extended_capa));
    00245     co_pack8p(*frame_addr + MAC_HT_CAPA_TX_BEAM_FORMING_CAPA_OFT,
    00246               (uint8_t *)&ht_cap->tx_beamforming_capa, 4);
    00247     co_write8p(*frame_addr + MAC_HT_CAPA_ASEL_CAPA_OFT, ht_cap->asel_capa);
    00248
    00249     *frame_addr += ie_len;
    00250
    00251     // And return the written length
    00252     return (ie_len);
    00253 }
    00254
    00255 #if (RW_MESH_EN)
    00256 uint32_t me_add_ie_ht_oper(uint32_t *frame_addr, struct vif_info_tag *vif)
    00257 {
    00258     // Element length
    00259     uint32_t ie_len = MAC_INFOELT_INFO_OFT + MAC_HT_OPER_ELMT_LEN;
    00260     // Get Channel Context used by the VIF
    00261     struct chan_ctxt_tag *chan_ctxt = vif->chan_ctxt;
    00262     // HT Information Subset (1 of 3)
    00263     uint8_t ht_info1 = 0x00;
    00264
    00265     // Tag Number - HT Information
    00266     co_write8p(*frame_addr + MAC_HT_OPER_ID_OFT, MAC_ELTID_HT_OPERATION);
    00267     // Tag Length
    00268     co_write8p(*frame_addr + MAC_HT_OPER_LEN_OFT, MAC_HT_OPER_ELMT_LEN);
    00269
    00270     co_write8p(*frame_addr + MAC_HT_OPER_PRIM_CH_OFT,
    00271                (uint8_t)phy_freq_to_channel(chan_ctxt->channel.band,
    00272                                             chan_ctxt->channel.prim20_freq));
    00273
    00274     if (chan_ctxt->channel.type > BW_20MHZ)
    00275     {
    00276         // Allow use of any channel width
    00277         ht_info1 |= 0x04;
    00278
    00279         if (chan_ctxt->channel.prim20_freq > chan_ctxt->channel.center1_freq)
    00280         {
    00281             // Secondary channel is below the primary channel
    00282             ht_info1 |= 0x03;
    00283         }
    00284         else
    00285         {
    00286             // Secondary channel is above the primary channel
    00287             ht_info1 |= 0x01;
    00288         }
    00289     }
    00290
    00291     co_write8p(*frame_addr + MAC_HT_OPER_INFO_OFT, ht_info1);
    00292     co_write16p(*frame_addr + MAC_HT_OPER_INFO_SUBSET2_OFT, MAC_HT_OPER_OP_MODE_MASK);
    00293     co_write16p(*frame_addr + MAC_HT_OPER_INFO_SUBSET3_OFT, 0);
    00294     co_write8p(*frame_addr + MAC_HT_OPER_BASIC_MSC_SET_OFT, 0xFF);
    00295
    00296     *frame_addr += ie_len;
    00297
    00298     // And return the written length
    00299     return (ie_len);
    00300 }
    00301 #endif //(RW_MESH_EN)
    00302
    00303 #if NX_HE
    00304 uint32_t me_add_ie_he_capa(uint32_t *frame_addr)
    00305 {
    00306     // Element length
    00307     uint32_t ie_len;
    00308     // Get Local VHT Capabilities
    00309     struct mac_hecapability *he_cap = &me_env.he_cap;
    00310     int i;
    00311     uint8_t chan_width_set;
    00312     uint32_t copy_addr;
    00313
    00314     // Tag Number - Extended element ID
    00315     co_write8p(*frame_addr + MAC_HE_CAPA_ID_OFT, MAC_ELTID_EXT);
    00316     // Extension element - HE capa
    00317     co_write8p(*frame_addr + MAC_HE_CAPA_EXT_ID_OFT, MAC_ELTID_EXT_HE_CAPA);
    00318
    00319     // Add MAC and PHY capabilities
    00320     copy_addr = *frame_addr + MAC_HE_MAC_CAPA_INFO_OFT;
    00321     for (i = 0; i < MAC_HE_CAPA_IE_MAC_CAPA_LEN; i++)
    00322     {
    00323         co_write8p(copy_addr++, he_cap->mac_cap_info[i]);
    00324     }
    00325     for (i = 0; i < MAC_HE_CAPA_IE_PHY_CAPA_LEN; i++)
    00326     {
    00327         co_write8p(copy_addr++, he_cap->phy_cap_info[i]);
    00328     }
    00329
    00330     // Add supported MCS
    00331     chan_width_set = HE_PHY_CAPA_VAL_GET(he_cap, CHAN_WIDTH_SET);
    00332     co_write16p(copy_addr, co_htows(he_cap->mcs_supp.rx_mcs_80));
    00333     copy_addr += 2;
    00334     co_write16p(copy_addr, co_htows(he_cap->mcs_supp.tx_mcs_80));
    00335     copy_addr += 2;
    00336     if (chan_width_set & HE_PHY_CAPA_CHAN_WIDTH_SET_160MHZ_IN_5G)
    00337     {
    00338         co_write16p(copy_addr, co_htows(he_cap->mcs_supp.rx_mcs_160));
    00339         copy_addr += 2;
    00340         co_write16p(copy_addr, co_htows(he_cap->mcs_supp.tx_mcs_160));
    00341         copy_addr += 2;
    00342     }
    00343     if (chan_width_set & HE_PHY_CAPA_CHAN_WIDTH_SET_80PLUS80_MHZ_IN_5G)
    00344     {
    00345         co_write16p(copy_addr, co_htows(he_cap->mcs_supp.rx_mcs_80p80));
    00346         copy_addr += 2;
    00347         co_write16p(copy_addr, co_htows(he_cap->mcs_supp.rx_mcs_80p80));
    00348         copy_addr += 2;
    00349     }
    00350
    00351     // Add PPE thresholds
    00352     for (i = 0; i < (2 + me_env.phy_bw_max); i++)
    00353     {
    00354         co_write8p(copy_addr++, he_cap->ppe_thres[i]);
    00355     }
    00356
    00357     ie_len = copy_addr - *frame_addr;
    00358     // Tag Length
    00359     co_write8p(*frame_addr + MAC_HE_CAPA_LEN_OFT, ie_len - 2);
    00360     *frame_addr += ie_len;
    00361
    00362     // And return the written length
    00363     return (ie_len);
    00364 }
    00365 #endif
    00366
    00367 #if (NX_VHT)
    00368 uint32_t me_add_ie_vht_capa(uint32_t *frame_addr)
    00369 {
    00370     // Element length
    00371     uint32_t ie_len = MAC_INFOELT_INFO_OFT + MAC_VHT_CAPA_ELMT_LEN;
    00372     // Get Local VHT Capabilities
    00373     struct mac_vhtcapability *vht_cap = &me_env.vht_cap;
    00374
    00375     // Tag Number - VHT Capabilities
    00376     co_write8p(*frame_addr + MAC_VHT_CAPA_ID_OFT, MAC_ELTID_VHT_CAPA);
    00377     // Tag Length
    00378     co_write8p(*frame_addr + MAC_VHT_CAPA_LEN_OFT, MAC_VHT_CAPA_ELMT_LEN);
    00379
    00380     co_write32p(*frame_addr + MAC_VHT_CAPA_INFO_OFT, co_htowl(vht_cap->vht_capa_info));
    00381     co_write16p(*frame_addr + MAC_VHT_RX_MCS_MAP_OFT, co_htows(vht_cap->rx_mcs_map));
    00382     co_write16p(*frame_addr + MAC_VHT_RX_HIGHEST_RATE_OFT, co_htows(vht_cap->rx_highest));
    00383     co_write16p(*frame_addr + MAC_VHT_TX_MCS_MAP_OFT, co_htows(vht_cap->tx_mcs_map));
    00384     co_write16p(*frame_addr + MAC_VHT_TX_HIGHEST_RATE_OFT, co_htows(vht_cap->tx_highest));
    00385
    00386     *frame_addr += ie_len;
    00387
    00388     // And return the written length
    00389     return (ie_len);
    00390 }
    00391
    00392 #if (RW_MESH_EN)
    00393 uint32_t me_add_ie_vht_oper(uint32_t *frame_addr, struct vif_info_tag *vif)
    00394 {
    00395     // Element length
    00396     uint32_t ie_len = MAC_INFOELT_INFO_OFT + MAC_VHT_OPER_ELMT_LEN;
    00397     // Get Channel Context used by the VIF
    00398     struct chan_ctxt_tag *chan_ctxt = vif->chan_ctxt;
    00399
    00400     // Tag Number - VHT Operation
    00401     co_write8p(*frame_addr + MAC_VHT_OPER_ID_OFT, MAC_ELTID_VHT_OPERATION);
    00402     // Tag Length
    00403     co_write8p(*frame_addr + MAC_VHT_OPER_LEN_OFT, MAC_VHT_OPER_ELMT_LEN);
    00404
    00405     if (chan_ctxt->channel.type == BW_80MHZ)
    00406     {
    00407         co_write8p(*frame_addr + MAC_VHT_CHAN_WIDTH_OFT, 1);
    00408         co_write8p(*frame_addr + MAC_VHT_CENTER_FREQ0_OFT,
    00409                 (uint8_t)phy_freq_to_channel(chan_ctxt->channel.band,
    00410                                              chan_ctxt->channel.center1_freq));
    00411     }
    00412     else
    00413     {
    00414         co_write8p(*frame_addr + MAC_VHT_CHAN_WIDTH_OFT, 0);
    00415         co_write8p(*frame_addr + MAC_VHT_CENTER_FREQ0_OFT, 0);
    00416     }
    00417
    00418     co_write8p(*frame_addr + MAC_VHT_CENTER_FREQ1_OFT, 0);
    00419     co_write16p(*frame_addr + MAC_VHT_BASIC_MCS_OFT, 0);
    00420
    00421     *frame_addr += ie_len;
    00422
    00423     // And return the written length
    00424     return (ie_len);
    00425 }
    00426 #endif //(RW_MESH_EN)
    00427
    00428 uint32_t me_add_ie_op_mode(uint32_t *frame_addr, uint8_t nss, uint8_t bw)
    00429 {
    00430     // Element length
    00431     uint32_t ie_len = MAC_INFOELT_INFO_OFT + MAC_OP_MODE_NOTIF_PARAM_LEN;
    00432     uint8_t op_mode = (bw << MAC_OPMODE_BW_OFT) | (nss << MAC_OPMODE_RXNSS_OFT);
    00433
    00434     // Tag Number - VHT Capabilities
    00435     co_write8p(*frame_addr + MAC_INFOELT_ID_OFT, MAC_ELTID_OP_MODE_NOTIF);
    00436     // Tag Length
    00437     co_write8p(*frame_addr + MAC_INFOELT_LEN_OFT, MAC_OP_MODE_NOTIF_PARAM_LEN);
    00438     // Parameter
    00439     co_write8p(*frame_addr + MAC_INFOELT_INFO_OFT, op_mode);
    00440
    00441     *frame_addr += ie_len;
    00442
    00443     // And return the written length
    00444     return (ie_len);
    00445 }
    00446 #endif //(NX_VHT)
    00447
    00448 //static void me_add_barinfo_frame(uint16_t *barinfo, struct bam_env_tag *bam_env)
    00449 //{
    00450 //    uint16_t sub_frame;
    00451 //    uint16_t seq;
    00452 //    uint8_t frag;
    00453 //
    00454 //    /* The BAR Information field
    00455 //     *
    00456 //     ************************************************
    00457 //     *  Octets: *    2     *            2           *
    00458 //     *  *********************************************
    00459 //     *          *  Per TID *     Block Ack Starting *
    00460 //     *          *   Info   *      Sequence Control  *
    00461 //     ************************************************
    00462 //     *
    00463 //     */
    00464 //
    00465 //    // Write the BARINFO  field
    00466 //
    00467 //    /* Per TID Info field
    00468 //     *
    00469 //     ****************************
    00470 //     *  B0->B11   * (B12 -> B15)*
    00471 //     *  Reserved  *  TID Value  *
    00472 //     ****************************
    00473 //     *
    00474 //     */
    00475 //
    00476 //    // Write the Per TID Info field
    00477 //    frame[MAC_BARINFO_PERTIDINFO_OFT] = 0;
    00478 //    frame[MAC_BARINFO_PERTIDINFO_OFT + MAC_BARINFO_PERTIDINFO_STEP] =
    00479 //        tsid << MAC_BARINFO_PERTIDINFO_TID_STEP;
    00480 //
    00481 //    /* Block Ack Starting Sequence Control field
    00482 //     *
    00483 //     ************************************************
    00484 //     *  B0->B3          *  (B12 -> B15)             *
    00485 //     *  Fragment Number *  Starting Sequence Number *
    00486 //     ************************************************
    00487 //     *
    00488 //     */
    00489 //    // Wirte the Block Ack Starting Sequence Control
    00490 //    frag= MAC_BARINFO_SEQ_FRAG;
    00491 //
    00492 //    seq = ba_param_ptr->ssn;
    00493 //
    00494 //    sub_frame = frag | (seq << MAC_BA_BARINFO_SEQ_STARTSEQ_OFT);
    00495 //
    00496 //    co_write16(&(frame[MAC_BARINFO_SEQ_OFT]), co_htows(sub_frame));
    00497 //}
    00498
    00499 // Functions used in the APM and SM
    00500 uint16_t me_build_authenticate(uint32_t frame,
    00501                                uint16_t algo_type,
    00502                                uint16_t seq_nbr,
    00503                                uint16_t status_code,
    00504                                uint32_t *challenge_array_ptr)
    00505 {
    00506
    00507     uint16_t mac_frame_len;
    00508
    00509     co_write16p(frame + MAC_AUTH_ALGONBR_OFT, co_htows(algo_type));
    00510     co_write16p(frame + MAC_AUTH_SEQNBR_OFT, co_htows(seq_nbr));
    00511     co_write16p(frame + MAC_AUTH_STATUS_OFT, co_htows(status_code));
    00512     mac_frame_len = MAC_AUTH_CHALLENGE_OFT;
    00513
    00514     if (challenge_array_ptr != NULL)
    00515     {
    00516         frame += MAC_AUTH_CHALLENGE_OFT;
    00517         co_write8p(frame + MAC_CHALLENGE_ID_OFT, MAC_ELTID_CHALLENGE);
    00518         co_write8p(frame + MAC_CHALLENGE_LEN_OFT, MAC_AUTH_CHALLENGE_LEN);
    00519         co_copy8p(frame + MAC_CHALLENGE_TEXT_OFT, CPU2HW(challenge_array_ptr),
    00520                                                                  MAC_AUTH_CHALLENGE_LEN);
    00521         mac_frame_len += CHALLENGE_TEXT_SIZE;
    00522     }
    00523     return mac_frame_len;
    00524 }
    00525
    00526 uint16_t me_build_deauthenticate(uint32_t frame, uint16_t reason_code)
    00527 {
    00528     uint16_t mac_frame_len;
    00529
    00530     co_write16p(frame + MAC_DISASSOC_REASON_OFT, co_htows(reason_code));
    00531     mac_frame_len = MAC_DISASSOC_REASON_LEN;
    00532
    00533     return(mac_frame_len);
    00534 }
    00535
    00536 // Functions used in the SM
    00537 uint16_t me_build_associate_req(uint32_t frame,
    00538                                 struct me_bss_info *bss,
    00539                                 struct mac_addr *old_ap_addr_ptr,
    00540                                 uint8_t vif_idx,
    00541                                 uint32_t *ie_addr,
    00542                                 uint16_t *ie_len,
    00543                                 struct sm_connect_req const *con_par)
    00544 {
    00545     uint16_t mac_frame_len;
    00546     uint16_t capainfo = 0;
    00547     uint32_t add_ie_addr = CPU2HW(con_par->ie_buf);
    00548     uint16_t add_ie_len = con_par->ie_len;
    00549     uint16_t listen;
    00550     #if NX_UAPSD
    00551     uint8_t uapsd_info = con_par->uapsd_queues;
    00552     #endif
    00553
    00554     // Set the listen interval based on the parameter from the host
    00555     listen = con_par->listen_interval?con_par->listen_interval:ME_DEFAULT_LISTEN_INTERVAL;
    00556
    00557     // build the capability information
    00558     capainfo = me_build_capability(vif_idx);
    00559
    00560     // build the frame body
    00561     co_write16p(frame + MAC_ASSO_REQ_CAPA_OFT, co_htows(capainfo));
    00562     co_write16p(frame + MAC_ASSO_REQ_LISTEN_OFT, co_htows(listen));
    00563
    00564     if (old_ap_addr_ptr)
    00565     {
    00566         // Add current AP if this is a re-association request
    00567         MAC_ADDR_CPY(HW2CPU(frame + MAC_REASSO_REQ_AP_ADDR_OFT), old_ap_addr_ptr);
    00568
    00569         // update frame length
    00570         mac_frame_len = MAC_REASSO_REQ_SSID_OFT;
    00571     }
    00572     else
    00573     {
    00574         // update frame length
    00575         mac_frame_len = MAC_ASSO_REQ_SSID_OFT;
    00576     }
    00577
    00578     frame += mac_frame_len;
    00579
    00580     *ie_addr = frame;
    00581
    00582     // Update the SSID
    00583     mac_frame_len += me_add_ie_ssid(&frame, bss->ssid.length, (uint8_t *)&bss->ssid.array);
    00584     // Add supported rates
    00585     mac_frame_len += me_add_ie_supp_rates(&frame, &bss->rate_set);
    00586     if (bss->rate_set.length > MAC_RATES_ELMT_MAX_LEN)
    00587     {
    00588         mac_frame_len += me_add_ie_ext_supp_rates(&frame, &bss->rate_set);
    00589     }
    00590
    00591     if (capainfo & MAC_CAPA_SPECTRUM)
    00592     {
    00593         int8_t min, max;
    00594
    00595         // Add Power capability
    00596         co_write8p(frame++, MAC_ELTID_POWER_CAPABILITY);
    00597         co_write8p(frame++, MAC_POWER_CAPABILITY_IE_LEN);
    00598         phy_get_rf_gain_capab(&max, &min);
    00599         if (max > bss->chan.tx_power)
    00600             max = bss->chan.tx_power;
    00601
    00602         co_write8p(frame++, (uint8_t)min);
    00603         co_write8p(frame++, (uint8_t)max);
    00604         mac_frame_len += MAC_POWER_CAPABILITY_IE_LEN + 2;
    00605     }
    00606
    00607     if (capainfo & MAC_CAPA_SPECTRUM)
    00608     {
    00609         uint8_t start, prev, i, nb, ch_incr, ch_idx, len, cnt;
    00610         struct mac_chan_def *chan;
    00611         uint32_t tmp;
    00612
    00613         // Add Supported Channels
    00614         co_write8p(frame++, MAC_ELTID_SUPPORTED_CHANNELS);
    00615         tmp = frame++; // skip len
    00616         if (bss->chan.band == PHY_BAND_2G4) {
    00617             ch_incr = 1;
    00618             chan = me_env.chan.chan2G4;
    00619             cnt = me_env.chan.chan2G4_cnt;
    00620         }
    00621         else
    00622         {
    00623             ch_incr = 4;
    00624             chan = me_env.chan.chan5G;
    00625             cnt =  me_env.chan.chan5G_cnt;
    00626         }
    00627
    00628         nb = len = start = prev = 0;
    00629         for (i = 0; i < cnt; i++)
    00630         {
    00631             if (chan->flags & CHAN_DISABLED)
    00632                 continue;
    00633
    00634             ch_idx = phy_freq_to_channel(chan->band, chan->freq);
    00635             if (nb && (ch_idx - prev) != ch_incr)
    00636             {
    00637                 co_write8p(frame++, start);
    00638                 co_write8p(frame++, nb);
    00639                 nb++;
    00640                 len += 2;
    00641             }
    00642             else if (!nb)
    00643             {
    00644                 start = ch_idx;
    00645             }
    00646
    00647             prev = ch_idx;
    00648             nb++;
    00649             chan++;
    00650         }
    00651         co_write8p(frame++, start);
    00652         co_write8p(frame++, nb);
    00653         len += 2;
    00654         co_write8p(tmp, len);
    00655         mac_frame_len += len + 2;
    00656     }
    00657
    00658     // Copy the additional information elements
    00659     co_copy8p(frame, add_ie_addr, add_ie_len);
    00660     mac_frame_len += add_ie_len;
    00661     frame += add_ie_len;
    00662
    00663     if (BSS_CAPA(bss, QOS))
    00664     {
    00665         uint8_t wme_ie[MAC_WME_PARAM_LEN] =  MAC_RAW_WME_INFO_ELMT_DEFAULT;
    00666
    00667         #if NX_UAPSD
    00668         // adjust the U-APSD flags as requested by the QSTA
    00669         if (ps_uapsd_enabled() &&
    00670             (bss->edca_param.qos_info & MAC_QOS_INFO_AP_UAPSD_ENABLED))
    00671         {
    00672             wme_ie[8] = uapsd_info;
    00673         }
    00674         else
    00675         #endif
    00676         {
    00677             wme_ie[8] = 0;
    00678         }
    00679         co_pack8p(frame, (uint8_t *)&wme_ie,
    00680                   wme_ie[MAC_INFOELT_LEN_OFT] + MAC_INFOELT_INFO_OFT);
    00681
    00682         // update the frame pointer
    00683         mac_frame_len += wme_ie[MAC_INFOELT_LEN_OFT] + MAC_INFOELT_INFO_OFT;
    00684         frame += wme_ie[MAC_INFOELT_LEN_OFT] + MAC_INFOELT_INFO_OFT;
    00685     }
    00686
    00687     // build the HT capabilities field
    00688     if (BSS_CAPA(bss, HT) && LOCAL_CAPA(HT))
    00689     {
    00690         mac_frame_len += me_add_ie_ht_capa(&frame);
    00691     }
    00692
    00693     // add Mobility Domain field
    00694     if (sm_env.ft_over_ds == 1)
    00695     {
    00696         struct mobility_domain *mde = &bss->mde;
    00697         if (mde->mdid != 0)
    00698         {
    00699             co_write8p(frame + MAC_INFOELT_MDE_ID_OFT, MAC_ELTID_MDE);
    00700             co_write8p(frame + MAC_INFOELT_MDE_LEN_OFT, MAC_INFOELT_MDE_ELMT_LEN);
    00701
    00702             co_write16p(frame + MAC_INFOELT_MDE_MDID_OFT, co_htows(mde->mdid));
    00703             co_write8p(frame + MAC_INFOELT_MDE_FT_CAPA_POL_OFT, mde->ft_capability_policy);
    00704
    00705             mac_frame_len += MAC_INFOELT_MDE_LEN;
    00706             frame += MAC_INFOELT_MDE_LEN;
    00707         }
    00708     }
    00709
    00710     #if NX_HE
    00711     // build the HE capabilities field
    00712     if (BSS_CAPA(bss, HE) && LOCAL_CAPA(HE))
    00713     {
    00714         mac_frame_len += me_add_ie_he_capa(&frame);
    00715     }
    00716     #endif //(NX_VHT)
    00717
    00718     #if NX_VHT
    00719     // build the VHT capabilities field
    00720     if (BSS_CAPA(bss, VHT) && LOCAL_CAPA(VHT))
    00721     {
    00722         mac_frame_len += me_add_ie_vht_capa(&frame);
    00723         mac_frame_len += me_add_ie_op_mode(&frame, me_11ac_nss_max(me_env.vht_cap.tx_mcs_map),
    00724                                            me_phy2mac_bw(me_env.phy_bw_max));
    00725     }
    00726     #endif //(NX_VHT)
    00727
    00728     *ie_len = frame - *ie_addr;
    00729
    00730     return mac_frame_len;
    00731
    00732 }
    00733
    00734 uint16_t me_build_add_ba_req(uint32_t frame, struct bam_env_tag *bam_env)
    00735 {
    00736     co_write8p(frame, MAC_BA_ACTION_CATEGORY);
    00737     co_write8p(frame + MAC_ACTION_ACTION_OFT, MAC_BA_ACTION_ADDBA_REQ);
    00738     co_write8p(frame + MAC_ACTION_TOKEN_OFT, bam_env->dialog_token);
    00739
    00740     // Fill the BA Parameter field
    00741     me_add_baparamset_frame(frame + BAM_ADDBAREQ_BA_PARAM_OFFSET, bam_env);
    00742
    00743     co_write16p(frame + BAM_ADDBAREQ_BA_TIMEOUT_OFFSET, co_htows(bam_env->ba_timeout));
    00744
    00745     // Add Block Ack Starting Sequence Control
    00746     me_add_ba_ssc_frame(frame + BAM_ADDBAREQ_BA_SSC_OFFSET, bam_env);
    00747
    00748     return (BAM_ADDBAREQ_LENGTH);
    00749 }
    00750
    00751 uint16_t me_build_add_ba_rsp(uint32_t frame, struct bam_env_tag *bam_env,
    00752                              uint16_t param,
    00753                              uint8_t dialog_token,
    00754                              uint16_t status_code)
    00755 {
    00756     co_write8p(frame, MAC_BA_ACTION_CATEGORY);
    00757     co_write8p(frame + MAC_ACTION_ACTION_OFT, MAC_BA_ACTION_ADDBA_RSP);
    00758     co_write8p(frame + MAC_ACTION_TOKEN_OFT, dialog_token);
    00759     co_write16p(frame + BAM_ADDBARSP_STATUS_OFFSET, co_htows(status_code));
    00760
    00761     // Fill the BA Parameter field
    00762     co_write16p(frame + BAM_ADDBARSP_BA_PARAM_OFFSET, co_htows(param));
    00763
    00764     if (status_code != MAC_BA_ST_SUCCESS)
    00765         co_write16p(frame + BAM_ADDBARSP_BA_TIMEOUT_OFFSET, co_htows(0));
    00766     else
    00767         co_write16p(frame + BAM_ADDBARSP_BA_TIMEOUT_OFFSET, co_htows(bam_env->ba_timeout));
    00768
    00769     return (BAM_ADDBARSP_LENGTH);
    00770 }
    00771
    00772 uint16_t me_build_del_ba(uint32_t frame, struct bam_env_tag *bam_env, uint16_t reason_code)
    00773 {
    00774     co_write8p(frame, MAC_BA_ACTION_CATEGORY);
    00775     co_write8p(frame + MAC_ACTION_ACTION_OFT, MAC_BA_ACTION_DELBA);
    00776
    00777     // Add the Status
    00778     me_del_baparamset_frame(frame + BAM_DELBA_PARAM_OFFSET, bam_env);
    00779
    00780     // Add Reason Code value
    00781     co_write16p(frame + BAM_DELBA_REASON_OFFSET, co_htows(reason_code));
    00782
    00783     return (BAM_DELBA_LENGTH);
    00784 }
    00785
    00786
    00787 void me_extract_rate_set(uint32_t buffer,
    00788                          uint16_t buflen,
    00789                          struct mac_rateset* mac_rate_set_ptr)
    00790 {
    00791     uint32_t addr;
    00792     uint8_t elmt_length, rate_cnt = 0;
    00793     int i;
    00794
    00795     do
    00796     {
    00797         // Search the rate set IE in the frame
    00798         addr = mac_ie_rates_find(buffer, buflen, &elmt_length);
    00799         if (addr == 0)
    00800             break;
    00801
    00802         // Copy the rate set from the frame
    00803         addr += MAC_RATES_RATES_OFT;
    00804         for (i = 0; i < elmt_length; i++)
    00805         {
    00806             uint8_t rate = co_read8p(addr + i);
    00807
    00808             // Discard BSS Membership Selectors if any
    00809             if (((rate & ~MAC_BASIC_RATE) == MAC_BSS_MEMBERSHIP_HT_PHY) ||
    00810                 ((rate & ~MAC_BASIC_RATE) == MAC_BSS_MEMBERSHIP_VHT_PHY))
    00811                 continue;
    00812
    00813             mac_rate_set_ptr->array[rate_cnt++] = rate;
    00814         }
    00815
    00816         // Search for extended rates if any
    00817         addr = mac_ie_ext_rates_find(buffer, buflen, &elmt_length);
    00818         if(addr == 0)
    00819             break;
    00820
    00821         // Add the extended rates to the rate array
    00822         addr += MAC_RATES_RATES_OFT;
    00823         for (i = 0; i < elmt_length; i++)
    00824         {
    00825             uint8_t rate = co_read8p(addr + i);
    00826
    00827             // Discard BSS Membership Selectors if any
    00828             if (((rate & ~MAC_BASIC_RATE) == MAC_BSS_MEMBERSHIP_HT_PHY) ||
    00829                 ((rate & ~MAC_BASIC_RATE) == MAC_BSS_MEMBERSHIP_VHT_PHY))
    00830                 continue;
    00831
    00832             mac_rate_set_ptr->array[rate_cnt++] = rate;
    00833
    00834             // Stop looping if our rate array is full
    00835             if (rate_cnt >= MAC_RATESET_LEN)
    00836                 break;
    00837         }
    00838     } while(0);
    00839
    00840     // Save the rate count
    00841     mac_rate_set_ptr->length = rate_cnt;
    00842 }
    00843
    00844
    00845 void me_extract_power_constraint(uint32_t buffer, uint16_t buflen,
    00846                                  struct me_bss_info *bss)
    00847 {
    00848    uint32_t addr = mac_ie_power_constraint_find(buffer, buflen);
    00849
    00850    if (addr == 0)
    00851    {
    00852        bss->power_constraint = 0;
    00853        return;
    00854    }
    00855
    00856    bss->power_constraint = co_read8p(addr + MAC_INFOELT_POWER_CONSTRAINT_OFT);
    00857 }
    00858
    00859 void me_extract_country_reg(uint32_t buffer, uint16_t buflen,
    00860                             struct me_bss_info *bss)
    00861 {
    00862     uint32_t addr;
    00863     uint8_t bss_ch_idx, ch_incr, ch_idx, ch_nb, i;
    00864     uint8_t elmt_length, oft;
    00865
    00866     addr = mac_ie_country_find(buffer, buflen, &elmt_length);
    00867
    00868     if (addr == 0)
    00869         return;
    00870
    00871     /* Only update tx power of the bss channel (required to set power
    00872        capability in (re)assoc resp). Other channels will be updated by driver */
    00873     if (bss->chan.band == PHY_BAND_2G4)
    00874         ch_incr = 1;
    00875     else
    00876         ch_incr = 4;
    00877
    00878     bss_ch_idx = phy_freq_to_channel(bss->chan.band, bss->chan.prim20_freq);
    00879     elmt_length += MAC_COUNTRY_STRING_OFT;
    00880     oft = MAC_COUNTRY_STRING_OFT + MAC_COUNTRY_STRING_LEN;
    00881     while ((oft + MAC_COUNTRY_TRIPLET_LEN) <= elmt_length)
    00882     {
    00883         ch_idx = co_read8p(addr + oft + MAC_COUNTRY_FIRST_CHAN_OFT);
    00884         ch_nb  = co_read8p(addr + oft + MAC_COUNTRY_NB_CHAN_OFT);
    00885
    00886         for (i = 0 ; i < ch_nb; i++)
    00887         {
    00888             if (bss_ch_idx == ch_idx)
    00889             {
    00890                 bss->chan.tx_power = (int8_t)co_read8p(addr + oft + MAC_COUNTRY_PWR_LEVEL_OFT);
    00891                 return;
    00892             }
    00893             ch_idx += ch_incr;
    00894         }
    00895
    00896         oft += MAC_COUNTRY_TRIPLET_LEN;
    00897     }
    00898 }
    00899
    00900 void me_extract_mobility_domain(uint32_t buffer, uint16_t buflen,
    00901                                      struct me_bss_info *bss)
    00902 {
    00903     uint32_t addr = mac_ie_mde_find(buffer, buflen);
    00904
    00905     if (addr == 0)
    00906     {
    00907         bss->mde.mdid = 0;
    00908         bss->mde.ft_capability_policy = 0;
    00909         return;
    00910     }
    00911
    00912     bss->mde.mdid = co_read16p(addr + MAC_INFOELT_MDE_MDID_OFT);
    00913     bss->mde.ft_capability_policy = co_read8p(addr + MAC_INFOELT_MDE_FT_CAPA_POL_OFT);
    00914 }
    00915
    00916 int me_extract_csa(uint32_t buffer, uint16_t buflen, uint8_t *mode,
    00917                    struct mac_chan_op *chan_desc)
    00918 {
    00919     uint32_t csa, ecsa, sec_chan, wide_bw_cs;
    00920     uint8_t count, prim20;
    00921     bool valid_length;
    00922
    00923     csa = mac_ie_csa_find(buffer, buflen);
    00924     ecsa = mac_ie_ecsa_find(buffer, buflen);
    00925
    00926     if (csa == 0 && ecsa == 0)
    00927     {
    00928         return 0;
    00929     }
    00930
    00931     sec_chan = mac_ie_sec_chnl_offset_find(buffer, buflen, &valid_length);
    00932     if (sec_chan && !valid_length)
    00933         return 0;
    00934
    00935     wide_bw_cs = mac_ie_wide_bw_chnl_find(buffer, buflen, &valid_length);
    00936     if (wide_bw_cs && !valid_length)
    00937         return 0;
    00938
    00939     if (csa)
    00940     {
    00941         count = co_read8p(csa + MAC_INFOELT_SWITCH_COUNT_OFT);
    00942         *mode  = co_read8p(csa + MAC_INFOELT_SWITCH_MODE_OFT);
    00943         prim20 = co_read8p(csa + MAC_INFOELT_SWITCH_NEW_CHAN_OFT);
    00944     }
    00945     else
    00946     {
    00947         count = co_read8p(ecsa + MAC_INFOELT_EXT_SWITCH_COUNT_OFT);
    00948         *mode  = co_read8p(ecsa + MAC_INFOELT_EXT_SWITCH_MODE_OFT);
    00949         prim20 = co_read8p(ecsa + MAC_INFOELT_EXT_SWITCH_NEW_CHAN_OFT);
    00950     }
    00951
    00952     if (count == 0)
    00953         count = 2;
    00954
    00955     chan_desc->band = (prim20 > 14) ? PHY_BAND_5G : PHY_BAND_2G4;
    00956     chan_desc->prim20_freq = phy_channel_to_freq(chan_desc->band, prim20);
    00957     chan_desc->type = PHY_CHNL_BW_20;
    00958     chan_desc->center1_freq = chan_desc->prim20_freq;
    00959     chan_desc->center2_freq = 0;
    00960
    00961     if (sec_chan)
    00962     {
    00963         uint8_t ofst = co_read8p(sec_chan + MAC_INFOELT_SEC_CH_OFFSET_OFT);
    00964         if (ofst == 1)
    00965         {
    00966             chan_desc->center1_freq += 10;
    00967             chan_desc->type = PHY_CHNL_BW_40;
    00968         }
    00969         else if (ofst == 3)
    00970         {
    00971             chan_desc->center1_freq -= 10;
    00972             chan_desc->type = PHY_CHNL_BW_40;
    00973         }
    00974     }
    00975
    00976     if (wide_bw_cs)
    00977     {
    00978         uint8_t width = co_read8p(wide_bw_cs + MAC_INFOELT_WIDE_BW_CHAN_SWITCH_NEW_CW_OFT);
    00979         uint8_t center1 = co_read8p(wide_bw_cs + MAC_INFOELT_WIDE_BW_CHAN_SWITCH_NEW_CENTER1_OFT);
    00980         uint8_t center2 = co_read8p(wide_bw_cs + MAC_INFOELT_WIDE_BW_CHAN_SWITCH_NEW_CENTER2_OFT);
    00981         me_vht_bandwidth_parse(width, center1, center2, chan_desc);
    00982     }
    00983
    00984     me_init_chan(chan_desc);
    00985
    00986     return count;
    00987 }
    00988
    00989 bool me_extract_edca_params(uint32_t buffer, uint16_t buflen,
    00990                             struct mac_edca_param_set *edca_param,
    00991                             bool *changed)
    00992 {
    00993     uint32_t addr = mac_ie_wmm_param_find(buffer, buflen);
    00994     uint32_t edca_temp;
    00995     uint8_t qos_info;
    00996
    00997     *changed = false;
    00998     if (addr == 0)
    00999     {
    01000         // AP is not WMM compatible - Put default EDCA values (all BE)
    01001         edca_param->ac_param[AC_BK] = NXMAC_EDCA_AC_1_RESET;
    01002         edca_param->ac_param[AC_BE] = NXMAC_EDCA_AC_1_RESET;
    01003         edca_param->ac_param[AC_VI] = NXMAC_EDCA_AC_1_RESET;
    01004         edca_param->ac_param[AC_VO] = NXMAC_EDCA_AC_1_RESET;
    01005         return false;
    01006     }
    01007
    01008     // First extract the QoS Info to get the parameter set counter
    01009     qos_info = co_read8p(addr + MAC_WMM_PARAM_QOS_INFO_OFT);
    01010
    01011     // Check if the parameters changed since last time we got them
    01012     if ((qos_info & MAC_WMM_PARAM_SET_CNT_MSK) == edca_param->param_set_cnt)
    01013         return true;
    01014
    01015     // The parameters are advertised as different by the AP, so read completely the
    01016     // element
    01017     *changed = true;
    01018
    01019     edca_param->qos_info = qos_info;
    01020     edca_param->param_set_cnt = qos_info & MAC_WMM_PARAM_SET_CNT_MSK;
    01021
    01022     // EDCA Parameter Read from frame is 0xTTTTCCAA
    01023     // TTTT = TXOP
    01024     // CC = Contention Window Parameters
    01025     // AA = AIFSN Parameter.
    01026     // This has to re-arranged as 0xAACCTTTT to as per spec. for EDCA Param
    01027     // So to extract and display in report will be correct
    01028     edca_temp = co_htowl(co_read32p(addr + MAC_WMM_PARAM_BE_PARAM_OFT));
    01029     // ACM bit information
    01030     edca_param->acm = ((edca_temp & CO_BIT(4)) != 0) << AC_BE;
    01031     // AIFSN BYTE alignment
    01032     edca_param->ac_param[AC_BE] = edca_temp & 0x0F;
    01033     // CW BYTE alignment
    01034     edca_param->ac_param[AC_BE] |= ((edca_temp >> 8) & 0xFFFFFFF) << 4;
    01035
    01036     edca_temp = co_htowl(co_read32p(addr + MAC_WMM_PARAM_BK_PARAM_OFT));
    01037     // ACM bit information
    01038     edca_param->acm |= ((edca_temp & CO_BIT(4)) != 0) << AC_BK;
    01039     // AIFSN BYTE alignment
    01040     edca_param->ac_param[AC_BK] = edca_temp & 0x0F;
    01041     // CW BYTE alignment.
    01042     edca_param->ac_param[AC_BK] |= ((edca_temp >> 8) & 0xFFFFFFF) << 4;
    01043
    01044     edca_temp = co_htowl(co_read32p(addr + MAC_WMM_PARAM_VI_PARAM_OFT));
    01045     // ACM bit information
    01046     edca_param->acm |= ((edca_temp & CO_BIT(4)) != 0) << AC_VI;
    01047     // AIFSN BYTE alignment
    01048     edca_param->ac_param[AC_VI] = edca_temp & 0x0F;
    01049     // CW BYTE alignment
    01050     edca_param->ac_param[AC_VI] |= ((edca_temp >> 8) & 0xFFFFFFF) << 4;
    01051
    01052     edca_temp = co_htowl(co_read32p(addr + MAC_WMM_PARAM_VO_PARAM_OFT));
    01053     // ACM bit information
    01054     edca_param->acm |= ((edca_temp & CO_BIT(4)) != 0) << AC_VO;
    01055     // AIFSN BYTE alignment
    01056     edca_param->ac_param[AC_VO] = edca_temp & 0x0F;
    01057     // CW BYTE alignment
    01058     edca_param->ac_param[AC_VO] |= ((edca_temp >> 8) & 0xFFFFFFF) << 4;
    01059
    01060     return true;
    01061 }
    01062
    01063 bool me_extract_ht_capa(uint32_t buffer, uint16_t buflen, struct mac_htcapability *ht_cap)
    01064 {
    01065     uint32_t addr = mac_ie_ht_capa_find(buffer, buflen);
    01066
    01067     if (addr == 0)
    01068         return false;
    01069
    01070     ht_cap->ht_capa_info = co_wtohs(co_read16p(addr + MAC_HT_CAPA_INFO_OFT));
    01071     ht_cap->a_mpdu_param = co_read8p(addr + MAC_HT_CAPA_AMPDU_PARAM_OFT);
    01072     co_unpack8p(ht_cap->mcs_rate, addr + MAC_HT_CAPA_SUPPORTED_MCS_SET_OFT, MAX_MCS_LEN);
    01073     ht_cap->ht_extended_capa = co_wtohs(co_read16p(addr + MAC_HT_CAPA_EXTENDED_CAPA_OFT));
    01074     ht_cap->tx_beamforming_capa =
    01075                    co_wtohs(co_read16p(addr + MAC_HT_CAPA_TX_BEAM_FORMING_CAPA_OFT));
    01076     ht_cap->asel_capa = co_read8p(addr + MAC_HT_CAPA_ASEL_CAPA_OFT);
    01077
    01078     return true;
    01079 }
    01080
    01081 bool me_extract_vht_capa(uint32_t buffer, uint16_t buflen, struct mac_vhtcapability *vht_cap)
    01082 {
    01083     uint32_t addr = mac_ie_vht_capa_find(buffer, buflen);
    01084
    01085     if (addr == 0)
    01086         return false;
    01087
    01088     vht_cap->vht_capa_info = co_wtohl(co_read32p(addr + MAC_VHT_CAPA_INFO_OFT));
    01089     vht_cap->rx_mcs_map = co_wtohs(co_read16p(addr + MAC_VHT_RX_MCS_MAP_OFT));
    01090     vht_cap->tx_mcs_map = co_wtohs(co_read16p(addr + MAC_VHT_TX_MCS_MAP_OFT));
    01091     vht_cap->rx_highest = co_wtohs(co_read16p(addr + MAC_VHT_RX_HIGHEST_RATE_OFT));
    01092     vht_cap->tx_highest = co_wtohs(co_read16p(addr + MAC_VHT_TX_HIGHEST_RATE_OFT));
    01093
    01094     return true;
    01095 }
    01096
    01097 #if NX_HE
    01098 bool me_extract_he_capa(uint32_t buffer, uint16_t buflen, struct mac_hecapability *he_cap)
    01099 {
    01100     uint32_t copy_addr;
    01101     uint32_t end_addr;
    01102     uint8_t elmt_length;
    01103     uint8_t chan_width_set;
    01104     int i;
    01105     uint32_t addr = mac_ie_he_capa_find(buffer, buflen, &elmt_length);
    01106
    01107     if (addr == 0)
    01108         return false;
    01109
    01110     copy_addr = addr + MAC_HE_MAC_CAPA_INFO_OFT;
    01111     end_addr = copy_addr + elmt_length;
    01112
    01113     for (i = 0; i < MAC_HE_CAPA_IE_MAC_CAPA_LEN; i++)
    01114     {
    01115         he_cap->mac_cap_info[i] = co_read8p(copy_addr++);
    01116     }
    01117     for (i = 0; i < MAC_HE_CAPA_IE_PHY_CAPA_LEN; i++)
    01118     {
    01119         he_cap->phy_cap_info[i] = co_read8p(copy_addr++);
    01120     }
    01121     chan_width_set = HE_PHY_CAPA_VAL_GET(he_cap, CHAN_WIDTH_SET);
    01122     he_cap->mcs_supp.rx_mcs_80 = co_wtohs(co_read16p(copy_addr));
    01123     copy_addr += 2;
    01124     he_cap->mcs_supp.tx_mcs_80 = co_wtohs(co_read16p(copy_addr));
    01125     copy_addr += 2;
    01126     if (chan_width_set & HE_PHY_CAPA_CHAN_WIDTH_SET_160MHZ_IN_5G)
    01127     {
    01128         if ((copy_addr + MAC_HE_MCS_INFO_PER_BW_LEN) > end_addr)
    01129             return false;
    01130         he_cap->mcs_supp.rx_mcs_160 = co_wtohs(co_read16p(copy_addr));
    01131         copy_addr += 2;
    01132         he_cap->mcs_supp.tx_mcs_160 = co_wtohs(co_read16p(copy_addr));
    01133         copy_addr += 2;
    01134     }
    01135     if (chan_width_set & HE_PHY_CAPA_CHAN_WIDTH_SET_80PLUS80_MHZ_IN_5G)
    01136     {
    01137         if ((copy_addr + MAC_HE_MCS_INFO_PER_BW_LEN) > end_addr)
    01138             return false;
    01139         he_cap->mcs_supp.rx_mcs_80p80 = co_wtohs(co_read16p(copy_addr));
    01140         copy_addr += 2;
    01141         he_cap->mcs_supp.tx_mcs_80p80 = co_wtohs(co_read16p(copy_addr));
    01142         copy_addr += 2;
    01143     }
    01144
    01145     return true;
    01146 }
    01147
    01148 bool me_extract_he_oper(uint32_t buffer, uint16_t buflen,
    01149                         struct me_bss_info *bss)
    01150 {
    01151     uint32_t he_op_addr;
    01152     uint8_t elmt_length;
    01153
    01154     // retrieve the HE operation field
    01155     he_op_addr = mac_ie_he_oper_find(buffer, buflen, &elmt_length);
    01156     if (he_op_addr)
    01157         bss->he_oper = co_read32p(he_op_addr + MAC_HE_OPER_PARAM_OFT);
    01158     else
    01159         bss->he_oper = MAC_HE_OPER_BSS_COLOR_DISABLED_BIT;
    01160
    01161     return (he_op_addr != 0);
    01162 }
    01163
    01164 bool me_extract_mu_edca_params(uint32_t buffer, uint16_t buflen,
    01165                                struct mac_mu_edca_param_set *mu_edca_param,
    01166                                bool *changed)
    01167 {
    01168     uint32_t addr = mac_ie_mu_edca_find(buffer, buflen);
    01169     uint8_t qos_info;
    01170
    01171     *changed = false;
    01172
    01173     if (addr == 0)
    01174     {
    01175         return false;
    01176     }
    01177
    01178     // First extract the QoS Info to get the parameter set counter
    01179     qos_info = co_read8p(addr + MAC_MU_EDCA_QOS_INFO_OFT);
    01180
    01181     // Check if the parameters changed this last time we got them
    01182     if ((qos_info & MAC_MU_EDCA_PARAM_SET_CNT_MSK) == mu_edca_param->param_set_cnt)
    01183         return true;
    01184
    01185     // The parameters are advertised as different by the AP, so read completely the
    01186     // element
    01187     *changed = true;
    01188
    01189     mu_edca_param->qos_info = qos_info;
    01190     mu_edca_param->param_set_cnt = qos_info & MAC_MU_EDCA_PARAM_SET_CNT_MSK;
    01191     mu_edca_param->ac_param[AC_BE] = co_htowl(co_read24p(addr + MAC_MU_EDCA_AC_BE_OFT));
    01192     mu_edca_param->ac_param[AC_BK] = co_htowl(co_read24p(addr + MAC_MU_EDCA_AC_BK_OFT));
    01193     mu_edca_param->ac_param[AC_VI] = co_htowl(co_read24p(addr + MAC_MU_EDCA_AC_VI_OFT));
    01194     mu_edca_param->ac_param[AC_VO] = co_htowl(co_read24p(addr + MAC_MU_EDCA_AC_VO_OFT));
    01195
    01196     return true;
    01197 }
    01198
    01199 bool me_extract_uora_params(uint32_t buffer, uint16_t buflen, struct mm_set_uora_req *uora_param)
    01200 {
    01201     uint8_t ocw_range;
    01202     uint32_t addr = mac_ie_uora_find(buffer, buflen);
    01203
    01204     if (!addr)
    01205     {
    01206         // Use the default values of OCWmin and OCWmax
    01207         uora_param->eocw_min = MAC_UORA_EOCW_DEFAULT_MIN;
    01208         uora_param->eocw_max = MAC_UORA_EOCW_DEFAULT_MAX;
    01209         return false;
    01210     }
    01211     // Extract OCW Range field
    01212     ocw_range = co_read8p(addr + MAC_UORA_OCW_RANGE);
    01213
    01214     uora_param->eocw_min = (ocw_range & MAC_UORA_EOCW_MIN_MASK) >> MAC_UORA_EOCW_MIN_OFT;
    01215     uora_param->eocw_max = (ocw_range & MAC_UORA_EOCW_MAX_MASK) >> MAC_UORA_EOCW_MAX_OFT;
    01216
    01217     return true;
    01218 }
    01219
    01220 #endif // NX_HE
    01221