/* *************************************************************************** * Ralink Tech Inc. * 4F, No. 2 Technology 5th Rd. * Science-based Industrial Park * Hsin-chu, Taiwan, R.O.C. * * (c) Copyright 2002-2004, Ralink Technology, Inc. * * All rights reserved. Ralink's source code is an unpublished work and the * use of a copyright notice does not imply otherwise. This source code * contains confidential trade secret material of Ralink Tech. Any attemp * or participation in deciphering, decoding, reverse engineering or in any * way altering the source code is stricitly prohibited, unless the prior * written consent of Ralink Technology, Inc. is obtained. *************************************************************************** Module Name: Abstract: Revision History: Who When What -------- ---------- ---------------------------------------------- */ #include "rt_config.h" #ifdef RELEASE_EXCLUDE /* IEEE 802.11AC D2.0 sec 22.3.14 Channelization, Table 22-21 A VHT channel is specified by the four PLME MIB fields (Fields to specify VHT channels). dot11CurrentChannelBandwidth: Channel bandwidth. Possible values are cbw20, cbw40, cbw80, cbw160 and cbw80p80. dot11CurrentChannelCenterFrequencyIndex1: In 20 MHz, 40 MHz, 80 MHz and 160 MHz channels, denotes the channel center frequency. In 80+80 MHz channels, denotes the center frequency of the frequency segment 1, which is the frequency segment containing the primary channel.. Valid range = 1, ..., 200. dot11CurrentChannelCenterFrequencyIndex2: In 80+80 MHz channels, denotes the center frequency of the frequency segment 2, which is the frequency segment that does not contain the primary channel. Valid range = 1, ..., 200. Undefined for 20 MHz, 40 MHz, 80 MHz and 160 MHz channels. dot11CurrentPrimaryChannel: Denotes the location of the primary 20 MHz channel. Valid range = 1, ..., 200. Formula: A channel center frequency of 5.000 GHz shall be indicated by dot11ChannelStartingFactor = 8000, and dot11CurrentPrimaryChannel = 200. Channel starting frequency = dot11ChannelStartingFactor * 0500 kHz. Channel center frequency [MHz] = Channel starting frequency + 5 * dot11CurrentChannelCenterFrequencyIndex Primary 20 MHz channel center frequency [MHz] = Channel starting frequency + 5 * dot11CurrentPrimaryChannel ex: a channel specified by: dot11CurrentChannelBandwidth = 80 MHz dot11CurrentChannelCenterFrequencyIndex1 = 42 dot11CurrentPrimaryChannel = 36 =>is an 80 MHz channel with a center frequency of 5210 MHz and the primary 20 MHz channel centered at 5180 MHz. */ #endif /* RELEASE_EXCLUDE */ struct vht_ch_layout{ UCHAR ch_low_bnd; UCHAR ch_up_bnd; UCHAR cent_freq_idx; }; static struct vht_ch_layout vht_ch_80M[]={ {36, 48, 42}, {52, 64, 58}, {100,112, 106}, {116, 128, 122}, {132, 144, 138}, {149, 161, 155}, {0, 0 ,0}, }; #if 0 static struct vht_ch_layout vht_ch_160M[]={ {36, 64, 50}, {100, 128, 114}, {0, 0 ,0}, }; #endif VOID dump_vht_cap(RTMP_ADAPTER *pAd, VHT_CAP_IE *vht_ie) { VHT_CAP_INFO *vht_cap = &vht_ie->vht_cap; VHT_MCS_SET *vht_mcs = &vht_ie->mcs_set; DBGPRINT(RT_DEBUG_OFF, ("Dump VHT_CAP IE\n")); hex_dump("VHT CAP IE Raw Data", (UCHAR *)vht_ie, sizeof(VHT_CAP_IE)); DBGPRINT(RT_DEBUG_OFF, ("VHT Capabilities Info Field\n")); DBGPRINT(RT_DEBUG_OFF, ("\tMaximum MPDU Length=%d\n", vht_cap->max_mpdu_len)); DBGPRINT(RT_DEBUG_OFF, ("\tSupported Channel Width=%d\n", vht_cap->ch_width)); DBGPRINT(RT_DEBUG_OFF, ("\tRxLDPC=%d\n", vht_cap->rx_ldpc)); DBGPRINT(RT_DEBUG_OFF, ("\tShortGI_80M=%d\n", vht_cap->sgi_80M)); DBGPRINT(RT_DEBUG_OFF, ("\tShortGI_160M=%d\n", vht_cap->sgi_160M)); DBGPRINT(RT_DEBUG_OFF, ("\tTxSTBC=%d\n", vht_cap->tx_stbc)); DBGPRINT(RT_DEBUG_OFF, ("\tRxSTBC=%d\n", vht_cap->rx_stbc)); DBGPRINT(RT_DEBUG_OFF, ("\tSU BeamformerCap=%d\n", vht_cap->bfer_cap_su)); DBGPRINT(RT_DEBUG_OFF, ("\tSU BeamformeeCap=%d\n", vht_cap->bfee_cap_su)); DBGPRINT(RT_DEBUG_OFF, ("\tCompressedSteeringNumOfBeamformerAnt=%d\n", vht_cap->cmp_st_num_bfer)); DBGPRINT(RT_DEBUG_OFF, ("\tNumber of Sounding Dimensions=%d\n", vht_cap->num_snd_dimension)); DBGPRINT(RT_DEBUG_OFF, ("\tMU BeamformerCap=%d\n", vht_cap->bfer_cap_mu)); DBGPRINT(RT_DEBUG_OFF, ("\tMU BeamformeeCap=%d\n", vht_cap->bfee_cap_mu)); DBGPRINT(RT_DEBUG_OFF, ("\tVHT TXOP PS=%d\n", vht_cap->vht_txop_ps)); DBGPRINT(RT_DEBUG_OFF, ("\t+HTC-VHT Capable=%d\n", vht_cap->htc_vht_cap)); DBGPRINT(RT_DEBUG_OFF, ("\tMaximum A-MPDU Length Exponent=%d\n", vht_cap->max_ampdu_exp)); DBGPRINT(RT_DEBUG_OFF, ("\tVHT LinkAdaptation Capable=%d\n", vht_cap->vht_link_adapt)); DBGPRINT(RT_DEBUG_OFF, ("VHT Supported MCS Set Field\n")); DBGPRINT(RT_DEBUG_OFF, ("\tRx Highest SupDataRate=%d\n", vht_mcs->rx_high_rate)); DBGPRINT(RT_DEBUG_OFF, ("\tRxMCS Map_1SS=%d\n", vht_mcs->rx_mcs_map.mcs_ss1)); DBGPRINT(RT_DEBUG_OFF, ("\tRxMCS Map_2SS=%d\n", vht_mcs->rx_mcs_map.mcs_ss2)); DBGPRINT(RT_DEBUG_OFF, ("\tTx Highest SupDataRate=%d\n", vht_mcs->tx_high_rate)); DBGPRINT(RT_DEBUG_OFF, ("\tTxMCS Map_1SS=%d\n", vht_mcs->tx_mcs_map.mcs_ss1)); DBGPRINT(RT_DEBUG_OFF, ("\tTxMCS Map_2SS=%d\n", vht_mcs->tx_mcs_map.mcs_ss2)); } VOID dump_vht_op(RTMP_ADAPTER *pAd, VHT_OP_IE *vht_ie) { VHT_OP_INFO *vht_op = &vht_ie->vht_op_info; VHT_MCS_MAP *vht_mcs = &vht_ie->basic_mcs_set; DBGPRINT(RT_DEBUG_OFF, ("Dump VHT_OP IE\n")); hex_dump("VHT OP IE Raw Data", (UCHAR *)vht_ie, sizeof(VHT_OP_IE)); DBGPRINT(RT_DEBUG_OFF, ("VHT Operation Info Field\n")); DBGPRINT(RT_DEBUG_OFF, ("\tChannelWidth=%d\n", vht_op->ch_width)); DBGPRINT(RT_DEBUG_OFF, ("\tChannelCenterFrequency Seg 1=%d\n", vht_op->center_freq_1)); DBGPRINT(RT_DEBUG_OFF, ("\tChannelCenterFrequency Seg 1=%d\n", vht_op->center_freq_2)); DBGPRINT(RT_DEBUG_OFF, ("VHT Basic MCS Set Field\n")); DBGPRINT(RT_DEBUG_OFF, ("\tRxMCS Map_1SS=%d\n", vht_mcs->mcs_ss1)); DBGPRINT(RT_DEBUG_OFF, ("\tRxMCS Map_2SS=%d\n", vht_mcs->mcs_ss2)); } #ifdef VHT_TXBF_SUPPORT VOID trigger_vht_ndpa(RTMP_ADAPTER *pAd, MAC_TABLE_ENTRY *entry) { UCHAR *buf; VHT_NDPA_FRAME *vht_ndpa; struct wifi_dev *wdev = entry->wdev; UINT frm_len, sta_cnt; SNDING_STA_INFO *sta_info; if (MlmeAllocateMemory(pAd, &buf) != NDIS_STATUS_SUCCESS) return; NdisZeroMemory(buf, MGMT_DMA_BUFFER_SIZE); vht_ndpa = (VHT_NDPA_FRAME *)buf; frm_len = sizeof(VHT_NDPA_FRAME); vht_ndpa->fc.Type = FC_TYPE_CNTL; vht_ndpa->fc.SubType = SUBTYPE_VHT_NDPA; COPY_MAC_ADDR(vht_ndpa->ra, entry->Addr); COPY_MAC_ADDR(vht_ndpa->ta, wdev->if_addr); /* Currnetly we only support 1 STA for a VHT DNPA */ sta_info = vht_ndpa->sta_info; for (sta_cnt = 0; sta_cnt < 1; sta_cnt++) { sta_info->aid12 = entry->Aid; sta_info->fb_type = SNDING_FB_SU; sta_info->nc_idx = 0; vht_ndpa->token.token_num = entry->snd_dialog_token; frm_len += sizeof(SNDING_STA_INFO); sta_info++; if (frm_len >= (MGMT_DMA_BUFFER_SIZE - sizeof(SNDING_STA_INFO))) { DBGPRINT(RT_DEBUG_ERROR, ("%s(): len(%d) too large!cnt=%d\n", __FUNCTION__, frm_len, sta_cnt)); break; } } if (entry->snd_dialog_token & 0xc0) entry->snd_dialog_token = 0; else entry->snd_dialog_token++; vht_ndpa->duration = pAd->CommonCfg.Dsifs + RTMPCalcDuration(pAd, pAd->CommonCfg.MlmeRate, frm_len); DBGPRINT(RT_DEBUG_OFF, ("Send VHT NDPA Frame to STA(%02x:%02x:%02x:%02x:%02x:%02x)\n", PRINT_MAC(entry->Addr))); hex_dump("VHT NDPA Frame", buf, frm_len); MiniportMMRequest(pAd, 0, buf, frm_len); MlmeFreeMemory(pAd, buf); #ifdef SOFT_SOUNDING if (1) { HEADER_802_11 *pNullFr; UCHAR *qos_p; UCHAR NullFrame[48]; NdisZeroMemory(NullFrame, 48); pNullFr = (PHEADER_802_11)&NullFrame[0]; frm_len = sizeof(HEADER_802_11); pNullFr->FC.Type = FC_TYPE_DATA; pNullFr->FC.SubType = SUBTYPE_QOS_NULL; pNullFr->FC.FrDs = 1; pNullFr->FC.ToDs = 0; COPY_MAC_ADDR(pNullFr->Addr1, entry->Addr); COPY_MAC_ADDR(pNullFr->Addr2, wdev->if_addr); COPY_MAC_ADDR(pNullFr->Addr3, wdev->bssid); qos_p = ((UCHAR *)pNullFr) + frm_len; qos_p[0] = 0; qos_p[1] = 0; frm_len += 2; entry->snd_reqired = TRUE; DBGPRINT(RT_DEBUG_OFF, ("Send sounding QoSNULL Frame to STA(%02x:%02x:%02x:%02x:%02x:%02x)\n", PRINT_MAC(entry->Addr))); hex_dump("VHT NDP Frame(QoSNull)", NullFrame, frm_len); HAL_KickOutNullFrameTx(pAd, 0, NullFrame, frm_len); } #endif /* SOFT_SOUNDING */ } #endif /* VHT_TXBF_SUPPORT */ /* Get BBP Channel Index by RF channel info return value: 0~3 */ UCHAR vht_prim_ch_idx(UCHAR vht_cent_ch, UCHAR prim_ch) { INT idx = 0; UCHAR bbp_idx = 0; if (vht_cent_ch == prim_ch) goto done; while (vht_ch_80M[idx].ch_up_bnd != 0) { if (vht_cent_ch == vht_ch_80M[idx].cent_freq_idx) { if (prim_ch == vht_ch_80M[idx].ch_up_bnd) bbp_idx = 3; else if (prim_ch == vht_ch_80M[idx].ch_low_bnd) bbp_idx = 0; else { bbp_idx = prim_ch > vht_cent_ch ? 2 : 1; } break; } idx++; } done: DBGPRINT(RT_DEBUG_INFO, ("%s():(VhtCentCh=%d, PrimCh=%d) =>BbpChIdx=%d\n", __FUNCTION__, vht_cent_ch, prim_ch, bbp_idx)); return bbp_idx; } /* Currently we only consider about VHT 80MHz! */ UCHAR vht_cent_ch_freq(RTMP_ADAPTER *pAd, UCHAR prim_ch) { INT idx = 0; if (pAd->CommonCfg.vht_bw < VHT_BW_80 || prim_ch < 36) { //pAd->CommonCfg.vht_cent_ch = 0; //pAd->CommonCfg.vht_cent_ch2 = 0; return prim_ch; } while (vht_ch_80M[idx].ch_up_bnd != 0) { if (prim_ch >= vht_ch_80M[idx].ch_low_bnd && prim_ch <= vht_ch_80M[idx].ch_up_bnd) { //pAd->CommonCfg.vht_cent_ch = vht_ch_80M[idx].cent_freq_idx; return vht_ch_80M[idx].cent_freq_idx; } idx++; } return prim_ch; } INT vht_mode_adjust(RTMP_ADAPTER *pAd, MAC_TABLE_ENTRY *pEntry, VHT_CAP_IE *cap, VHT_OP_IE *op) { pEntry->MaxHTPhyMode.field.MODE = MODE_VHT; pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; pAd->MacTab.fAnyStationNonGF = TRUE; if (op->vht_op_info.ch_width >= 1 && pEntry->MaxHTPhyMode.field.BW == BW_40) { pEntry->MaxHTPhyMode.field.BW= BW_80; pEntry->MaxHTPhyMode.field.ShortGI = (cap->vht_cap.sgi_80M); pEntry->MaxHTPhyMode.field.STBC = (cap->vht_cap.rx_stbc > 1 ? 1 : 0); } return TRUE; } INT get_vht_op_ch_width(RTMP_ADAPTER *pAd) { return TRUE; } /******************************************************************** Procedures for 802.11 AC Information elements ********************************************************************/ /* Defined in IEEE 802.11AC Appeared in Beacon, ProbResp frames */ INT build_quiet_channel(RTMP_ADAPTER *pAd, UCHAR *buf) { INT len = 0; return len; } /* Defined in IEEE 802.11AC Appeared in Beacon, ProbResp frames */ INT build_ext_bss_load(RTMP_ADAPTER *pAd, UCHAR *buf) { INT len = 0; return len; } #if 0 INT build_wide_bw_ch_switch(RTMP_ADAPTER *pAd, UCHAR *buf) { if (WMODE_CAP_AC(PhyMode)) { WIDE_BW_CH_SWITCH_IE wide_bw_switch_ie; wide_bw_switch_ie.e_id = IE_WIDE_BW_CH_SWITCH; wide_bw_switch_ie.len = 3; wide_bw_switch_ie.new_ch_width = ; wide_bw_switch_ie.center_freq_1 = ; wide_bw_switch_ie.center_freq_2 = ; } } #endif /* Defined in IEEE 802.11AC Appeared in Beacon, ProbResp frames */ INT build_ext_pwr_constraint(RTMP_ADAPTER *pAd, UCHAR *buf) { INT len = 0; return len; } /* Defined in IEEE 802.11AC Appeared in Beacon, ProbResp frames */ INT build_vht_txpwr_envelope(RTMP_ADAPTER *pAd, UCHAR *buf) { INT len = 0, pwr_cnt; VHT_TXPWR_ENV_IE txpwr_env; NdisZeroMemory(&txpwr_env, sizeof(txpwr_env)); if (pAd->CommonCfg.vht_bw == VHT_BW_80) { pwr_cnt = 2; } else { if (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 1) pwr_cnt = 1; else pwr_cnt = 0; } txpwr_env.tx_pwr_info.max_tx_pwr_cnt = pwr_cnt; txpwr_env.tx_pwr_info.max_tx_pwr_interpretation = TX_PWR_INTERPRET_EIRP; // TODO: fixme, we need the real tx_pwr value for each port. for (len = 0; len < pwr_cnt; len++) txpwr_env.tx_pwr_bw[len] = 15; len = 2 + pwr_cnt; NdisMoveMemory(buf, &txpwr_env, len); return len; } /* Defined in IEEE 802.11AC Appeared in Beacon, (Re)AssocResp, ProbResp frames */ INT build_vht_op_ie(RTMP_ADAPTER *pAd, UCHAR *buf) { VHT_OP_IE vht_op; UCHAR cent_ch; #ifdef RT_BIG_ENDIAN UINT16 tmp; #endif /* RT_BIG_ENDIAN */ NdisZeroMemory((UCHAR *)&vht_op, sizeof(VHT_OP_IE)); vht_op.vht_op_info.ch_width = (pAd->CommonCfg.vht_bw == VHT_BW_80 ? 1: 0); #ifdef CONFIG_AP_SUPPORT if (pAd->CommonCfg.Channel > 14 && (pAd->CommonCfg.bIEEE80211H == 1) && (pAd->Dot11_H.RDMode == RD_SWITCHING_MODE)) cent_ch = vht_cent_ch_freq(pAd, pAd->Dot11_H.org_ch); else #endif /* CONFIG_AP_SUPPORT */ cent_ch = vht_cent_ch_freq(pAd, pAd->CommonCfg.Channel); switch (vht_op.vht_op_info.ch_width) { case 0: vht_op.vht_op_info.center_freq_1 = 0; vht_op.vht_op_info.center_freq_2 = 0; break; case 1: case 2: vht_op.vht_op_info.center_freq_1 = cent_ch; vht_op.vht_op_info.center_freq_2 = 0; break; case 3: vht_op.vht_op_info.center_freq_1 = cent_ch; vht_op.vht_op_info.center_freq_2 = pAd->CommonCfg.vht_cent_ch2; break; } vht_op.basic_mcs_set.mcs_ss1 = VHT_MCS_CAP_NA; vht_op.basic_mcs_set.mcs_ss2 = VHT_MCS_CAP_NA; vht_op.basic_mcs_set.mcs_ss3 = VHT_MCS_CAP_NA; vht_op.basic_mcs_set.mcs_ss4 = VHT_MCS_CAP_NA; vht_op.basic_mcs_set.mcs_ss5 = VHT_MCS_CAP_NA; vht_op.basic_mcs_set.mcs_ss6 = VHT_MCS_CAP_NA; vht_op.basic_mcs_set.mcs_ss7 = VHT_MCS_CAP_NA; vht_op.basic_mcs_set.mcs_ss8 = VHT_MCS_CAP_NA; switch (pAd->CommonCfg.RxStream) { case 2: vht_op.basic_mcs_set.mcs_ss2 = VHT_MCS_CAP_7; #ifdef MT76x2 if (IS_MT76x2(pAd)) { vht_op.basic_mcs_set.mcs_ss2 = VHT_MCS_CAP_9; } #endif /* MT76x2 */ case 1: #if defined(MT76x0) || defined(MT76x2) if (IS_MT76x0(pAd) || IS_MT76x2(pAd)) vht_op.basic_mcs_set.mcs_ss1 = VHT_MCS_CAP_9; else #endif vht_op.basic_mcs_set.mcs_ss1 = VHT_MCS_CAP_7; break; } #ifdef RT_BIG_ENDIAN //SWAP16((UINT16)vht_op.basic_mcs_set); NdisCopyMemory(&tmp,&vht_op.basic_mcs_set, 2); tmp=SWAP16(tmp); NdisCopyMemory(&vht_op.basic_mcs_set,&tmp, 2); #endif /* RT_BIG_ENDIAN */ NdisMoveMemory((UCHAR *)buf, (UCHAR *)&vht_op, sizeof(VHT_OP_IE)); return sizeof(VHT_OP_IE); } /* Defined in IEEE 802.11AC Appeared in Beacon, (Re)AssocReq, (Re)AssocResp, ProbReq/Resp frames */ INT build_vht_cap_ie(RTMP_ADAPTER *pAd, UCHAR *buf) { VHT_CAP_IE vht_cap_ie; INT rx_nss, tx_nss, mcs_cap; #ifdef RT_BIG_ENDIAN UINT32 tmp_1; UINT64 tmp_2; #endif /*RT_BIG_ENDIAN*/ NdisZeroMemory((UCHAR *)&vht_cap_ie, sizeof(VHT_CAP_IE)); vht_cap_ie.vht_cap.max_mpdu_len = 0; // TODO: Ask Jerry about hardware limitation. vht_cap_ie.vht_cap.ch_width = 0; /* not support 160 or 80 + 80 MHz */ if (pAd->CommonCfg.vht_ldpc && (pAd->chipCap.phy_caps & fPHY_CAP_LDPC)) vht_cap_ie.vht_cap.rx_ldpc = 1; else vht_cap_ie.vht_cap.rx_ldpc = 0; vht_cap_ie.vht_cap.sgi_80M = pAd->CommonCfg.vht_sgi_80; vht_cap_ie.vht_cap.htc_vht_cap = 1; vht_cap_ie.vht_cap.max_ampdu_exp = 3; // TODO: Ask Jerry about the hardware limitation, currently set as 64K vht_cap_ie.vht_cap.tx_stbc = 0; vht_cap_ie.vht_cap.rx_stbc = 0; if (pAd->CommonCfg.vht_stbc) { if (pAd->CommonCfg.TxStream >= 2) vht_cap_ie.vht_cap.tx_stbc = 1; else vht_cap_ie.vht_cap.tx_stbc = 0; if (pAd->CommonCfg.RxStream >= 1) vht_cap_ie.vht_cap.rx_stbc = 1; // TODO: is it depends on the number of our antennas? else vht_cap_ie.vht_cap.rx_stbc = 0; } vht_cap_ie.vht_cap.tx_ant_consistency = 1; vht_cap_ie.vht_cap.rx_ant_consistency = 1; vht_cap_ie.mcs_set.rx_mcs_map.mcs_ss1 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.rx_mcs_map.mcs_ss2 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.rx_mcs_map.mcs_ss3 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.rx_mcs_map.mcs_ss4 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.rx_mcs_map.mcs_ss5 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.rx_mcs_map.mcs_ss6 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.rx_mcs_map.mcs_ss7 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.rx_mcs_map.mcs_ss8 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.tx_mcs_map.mcs_ss1 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.tx_mcs_map.mcs_ss2 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.tx_mcs_map.mcs_ss3 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.tx_mcs_map.mcs_ss4 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.tx_mcs_map.mcs_ss5 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.tx_mcs_map.mcs_ss6 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.tx_mcs_map.mcs_ss7 = VHT_MCS_CAP_NA; vht_cap_ie.mcs_set.tx_mcs_map.mcs_ss8 = VHT_MCS_CAP_NA; mcs_cap = pAd->chipCap.max_vht_mcs; rx_nss = pAd->CommonCfg.RxStream; tx_nss = pAd->CommonCfg.TxStream; #ifdef WFA_VHT_PF if ((pAd->CommonCfg.vht_nss_cap > 0) && (pAd->CommonCfg.vht_nss_cap < pAd->CommonCfg.RxStream)) rx_nss = pAd->CommonCfg.vht_nss_cap; if ((pAd->CommonCfg.vht_nss_cap > 0) && (pAd->CommonCfg.vht_nss_cap < pAd->CommonCfg.TxStream)) tx_nss = pAd->CommonCfg.vht_nss_cap; if (pAd->CommonCfg.vht_mcs_cap chipCap.max_vht_mcs) mcs_cap = pAd->CommonCfg.vht_mcs_cap; #endif /* WFA_VHT_PF */ switch (rx_nss) { case 1: vht_cap_ie.mcs_set.rx_high_rate = 292; vht_cap_ie.mcs_set.rx_mcs_map.mcs_ss1 = mcs_cap; break; case 2: if (mcs_cap == VHT_MCS_CAP_9) vht_cap_ie.mcs_set.rx_high_rate = 780; else vht_cap_ie.mcs_set.rx_high_rate = 585; vht_cap_ie.mcs_set.rx_mcs_map.mcs_ss1 = mcs_cap; vht_cap_ie.mcs_set.rx_mcs_map.mcs_ss2 = mcs_cap; break; default: vht_cap_ie.mcs_set.rx_high_rate = 0; break; } switch (tx_nss) { case 1: vht_cap_ie.mcs_set.tx_high_rate = 292; vht_cap_ie.mcs_set.tx_mcs_map.mcs_ss1 = mcs_cap; break; case 2: if (mcs_cap == VHT_MCS_CAP_9) vht_cap_ie.mcs_set.tx_high_rate = 780; else vht_cap_ie.mcs_set.tx_high_rate = 585; vht_cap_ie.mcs_set.tx_mcs_map.mcs_ss1 = mcs_cap; vht_cap_ie.mcs_set.tx_mcs_map.mcs_ss2 = mcs_cap; break; default: vht_cap_ie.mcs_set.tx_high_rate = 0; break; } #ifdef RT_BIG_ENDIAN NdisCopyMemory(&tmp_1,&vht_cap_ie.vht_cap, 4); tmp_1 = SWAP32(tmp_1); NdisCopyMemory(&vht_cap_ie.vht_cap,&tmp_1, 4); NdisCopyMemory(&tmp_2,&vht_cap_ie.mcs_set, 8); tmp_2=SWAP64(tmp_2); NdisCopyMemory(&vht_cap_ie.mcs_set,&tmp_2, 8); //hex_dump("&vht_cap_ie", &vht_cap_ie, sizeof(VHT_CAP_IE)); //SWAP32((UINT32)vht_cap_ie.vht_cap); //SWAP32((UINT32)vht_cap_ie.mcs_set); #endif /* RT_BIG_ENDIAN */ #ifdef VHT_TXBF_SUPPORT if (pAd->chipCap.FlgHwTxBfCap) { vht_cap_ie.vht_cap.num_snd_dimension = pAd->CommonCfg.vht_cap_ie.vht_cap.num_snd_dimension; vht_cap_ie.vht_cap.cmp_st_num_bfer= pAd->CommonCfg.vht_cap_ie.vht_cap.cmp_st_num_bfer; vht_cap_ie.vht_cap.bfee_cap_su=pAd->CommonCfg.vht_cap_ie.vht_cap.bfee_cap_su; vht_cap_ie.vht_cap.bfer_cap_su=pAd->CommonCfg.vht_cap_ie.vht_cap.bfer_cap_su; } #endif NdisMoveMemory(buf, (UCHAR *)&vht_cap_ie, sizeof(VHT_CAP_IE)); return sizeof(VHT_CAP_IE); } INT build_vht_ies(RTMP_ADAPTER *pAd, UCHAR *buf, UCHAR frm) { INT len = 0; EID_STRUCT eid_hdr; eid_hdr.Eid = IE_VHT_CAP; eid_hdr.Len = sizeof(VHT_CAP_IE); NdisMoveMemory(buf, (UCHAR *)&eid_hdr, 2); len = 2; len += build_vht_cap_ie(pAd, (UCHAR *)(buf + len)); if (frm == SUBTYPE_BEACON || frm == SUBTYPE_PROBE_RSP || frm == SUBTYPE_ASSOC_RSP || frm == SUBTYPE_REASSOC_RSP) { eid_hdr.Eid = IE_VHT_OP; eid_hdr.Len = sizeof(VHT_OP_IE); NdisMoveMemory((UCHAR *)(buf + len), (UCHAR *)&eid_hdr, 2); len +=2; len += build_vht_op_ie(pAd, (UCHAR *)(buf + len)); } return len; } BOOLEAN vht80_channel_group( RTMP_ADAPTER *pAd, UCHAR channel) { INT idx = 0; if (channel <= 14) return FALSE; while (vht_ch_80M[idx].ch_up_bnd != 0) { if (channel >= vht_ch_80M[idx].ch_low_bnd && channel <= vht_ch_80M[idx].ch_up_bnd) { if ( (pAd->CommonCfg.RDDurRegion == JAP || pAd->CommonCfg.RDDurRegion == JAP_W53 || pAd->CommonCfg.RDDurRegion == JAP_W56) && vht_ch_80M[idx].cent_freq_idx == 138) { idx++; continue; } return TRUE; } idx++; } return FALSE; }