Example #1
0
/*
 * This function sets up the CFG802.11 specific HT capability fields
 * with default values.
 *
 * The following default values are set -
 *      - HT Supported = True
 *      - Maximum AMPDU length factor = IEEE80211_HT_MAX_AMPDU_64K
 *      - Minimum AMPDU spacing = IEEE80211_HT_MPDU_DENSITY_NONE
 *      - HT Capabilities supported by firmware
 *      - MCS information, Rx mask = 0xff
 *      - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01)
 */
static void
mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
		      struct mwifiex_private *priv)
{
	int rx_mcs_supp;
	struct ieee80211_mcs_info mcs_set;
	u8 *mcs = (u8 *)&mcs_set;
	struct mwifiex_adapter *adapter = priv->adapter;

	ht_info->ht_supported = true;
	ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
	ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;

	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));

	/* Fill HT capability information */
	if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap))
		ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
	else
		ht_info->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;

	if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap))
		ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
	else
		ht_info->cap &= ~IEEE80211_HT_CAP_SGI_20;

	if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap))
		ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
	else
		ht_info->cap &= ~IEEE80211_HT_CAP_SGI_40;

	if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap))
		ht_info->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT;
	else
		ht_info->cap &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT);

	if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap))
		ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
	else
		ht_info->cap &= ~IEEE80211_HT_CAP_TX_STBC;

	ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU;
	ht_info->cap |= IEEE80211_HT_CAP_SM_PS;

	rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support);
	/* Set MCS for 1x1 */
	memset(mcs, 0xff, rx_mcs_supp);
	/* Clear all the other values */
	memset(&mcs[rx_mcs_supp], 0,
	       sizeof(struct ieee80211_mcs_info) - rx_mcs_supp);
	if (priv->bss_mode == NL80211_IFTYPE_STATION ||
	    ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap))
		/* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
		SETHT_MCS32(mcs_set.rx_mask);

	memcpy((u8 *) &ht_info->mcs, mcs, sizeof(struct ieee80211_mcs_info));

	ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
}
/** 
 *  @brief This function prints the 802.11n device capability
 *  
 *  @param pmadapter     A pointer to mlan_adapter structure
 *  @param cap           Capability value
 *
 *  @return        N/A
 */
void
wlan_show_dot11ndevcap(pmlan_adapter pmadapter, t_u32 cap)
{
    ENTER();

    PRINTM(MINFO, "GET_HW_SPEC: Maximum MSDU length = %s octets\n",
           (ISSUPP_MAXAMSDU(cap) ? "7935" : "3839"));
    PRINTM(MINFO, "GET_HW_SPEC: Beam forming %s\n",
           (ISSUPP_BEAMFORMING(cap) ? "supported" : "not supported"));
    PRINTM(MINFO, "GET_HW_SPEC: Greenfield preamble %s\n",
           (ISSUPP_GREENFIELD(cap) ? "supported" : "not supported"));
    PRINTM(MINFO, "GET_HW_SPEC: AMPDU %s\n",
           (ISSUPP_AMPDU(cap) ? "supported" : "not supported"));
    PRINTM(MINFO, "GET_HW_SPEC: MIMO Power Save %s\n",
           (ISSUPP_MIMOPS(cap) ? "supported" : "not supported"));
    PRINTM(MINFO, "GET_HW_SPEC: Rx STBC %s\n",
           (ISSUPP_RXSTBC(cap) ? "supported" : "not supported"));
    PRINTM(MINFO, "GET_HW_SPEC: Tx STBC %s\n",
           (ISSUPP_TXSTBC(cap) ? "supported" : "not supported"));
    PRINTM(MINFO, "GET_HW_SPEC: Short GI for 40 Mhz %s\n",
           (ISSUPP_SHORTGI40(cap) ? "supported" : "not supported"));
    PRINTM(MINFO, "GET_HW_SPEC: Short GI for 20 Mhz %s\n",
           (ISSUPP_SHORTGI20(cap) ? "supported" : "not supported"));
    PRINTM(MINFO, "GET_HW_SPEC: LDPC coded packet receive %s\n",
           (ISSUPP_RXLDPC(cap) ? "supported" : "not supported"));
    PRINTM(MINFO, "GET_HW_SPEC: Number of Delayed Block Ack streams = %d\n",
           GET_DELAYEDBACK(cap));
    PRINTM(MINFO, "GET_HW_SPEC: Number of Immediate Block Ack streams = %d\n",
           GET_IMMEDIATEBACK(cap));
    PRINTM(MINFO, "GET_HW_SPEC: 40 Mhz channel width %s\n",
           (ISSUPP_CHANWIDTH40(cap) ? "supported" : "not supported"));
    PRINTM(MINFO, "GET_HW_SPEC: 20 Mhz channel width %s\n",
           (ISSUPP_CHANWIDTH20(cap) ? "supported" : "not supported"));
    PRINTM(MINFO, "GET_HW_SPEC: 10 Mhz channel width %s\n",
           (ISSUPP_CHANWIDTH10(cap) ? "supported" : "not supported"));

    if (ISSUPP_RXANTENNAA(cap)) {
        PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna A\n");
    }
    if (ISSUPP_RXANTENNAB(cap)) {
        PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna B\n");
    }
    if (ISSUPP_RXANTENNAC(cap)) {
        PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna C\n");
    }
    if (ISSUPP_RXANTENNAD(cap)) {
        PRINTM(MINFO, "GET_HW_SPEC: Presence of Rx antenna D\n");
    }
    if (ISSUPP_TXANTENNAA(cap)) {
        PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna A\n");
    }
    if (ISSUPP_TXANTENNAB(cap)) {
        PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna B\n");
    }
    if (ISSUPP_TXANTENNAC(cap)) {
        PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna C\n");
    }
    if (ISSUPP_TXANTENNAD(cap)) {
        PRINTM(MINFO, "GET_HW_SPEC: Presence of Tx antenna D\n");
    }

    LEAVE();
    return;
}
/**
 *  @brief This function append the 802_11N tlv
 *
 *  @param pmpriv       A pointer to mlan_private structure
 *  @param pbss_desc    A pointer to BSSDescriptor_t structure
 *  @param ppbuffer     A Pointer to command buffer pointer
 *
 *  @return bytes added to the buffer       
 */
int
wlan_cmd_append_11n_tlv(IN mlan_private * pmpriv,
                        IN BSSDescriptor_t * pbss_desc, OUT t_u8 ** ppbuffer)
{
    pmlan_adapter pmadapter = pmpriv->adapter;
    MrvlIETypes_HTCap_t *pht_cap;
    MrvlIETypes_HTInfo_t *pht_info;
    MrvlIEtypes_ChanListParamSet_t *pchan_list;
    MrvlIETypes_2040BSSCo_t *p2040_bss_co;
    MrvlIETypes_ExtCap_t *pext_cap;
    int ret_len = 0;

    ENTER();

    /* Null Checks */
    if (ppbuffer == 0) {
        LEAVE();
        return 0;
    }
    if (*ppbuffer == 0) {
        LEAVE();
        return 0;
    }

    if (pbss_desc->pht_cap) {
        pht_cap = (MrvlIETypes_HTCap_t *) * ppbuffer;
        memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
        pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
        pht_cap->header.len = sizeof(HTCap_t);
        memcpy(pmadapter, (t_u8 *) pht_cap + sizeof(MrvlIEtypesHeader_t),
               (t_u8 *) pbss_desc->pht_cap + sizeof(IEEEtypes_Header_t),
               pht_cap->header.len);

        pht_cap->ht_cap.ht_cap_info =
            wlan_le16_to_cpu(pht_cap->ht_cap.ht_cap_info);
        wlan_fill_cap_info(pmpriv, pht_cap);
        pht_cap->ht_cap.ht_cap_info =
            wlan_cpu_to_le16(pht_cap->ht_cap.ht_cap_info);

        HEXDUMP("HT_CAPABILITIES IE", (t_u8 *) pht_cap,
                sizeof(MrvlIETypes_HTCap_t));
        *ppbuffer += sizeof(MrvlIETypes_HTCap_t);
        ret_len += sizeof(MrvlIETypes_HTCap_t);
        pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
    }

    if (pbss_desc->pht_info) {
        if (pmpriv->bss_mode == MLAN_BSS_MODE_IBSS) {
            pht_info = (MrvlIETypes_HTInfo_t *) * ppbuffer;
            memset(pmadapter, pht_info, 0, sizeof(MrvlIETypes_HTInfo_t));
            pht_info->header.type = wlan_cpu_to_le16(HT_OPERATION);
            pht_info->header.len = sizeof(HTInfo_t);

            memcpy(pmadapter, (t_u8 *) pht_info + sizeof(MrvlIEtypesHeader_t),
                   (t_u8 *) pbss_desc->pht_info + sizeof(IEEEtypes_Header_t),
                   pht_info->header.len);

            if (!ISSUPP_CHANWIDTH40(pmadapter->hw_dot_11n_dev_cap) ||
                !ISSUPP_CHANWIDTH40(pmadapter->usr_dot_11n_dev_cap)) {
                RESET_CHANWIDTH40(pht_info->ht_info.field2);
            }

            *ppbuffer += sizeof(MrvlIETypes_HTInfo_t);
            ret_len += sizeof(MrvlIETypes_HTInfo_t);
            pht_info->header.len = wlan_cpu_to_le16(pht_info->header.len);
        }

        pchan_list = (MrvlIEtypes_ChanListParamSet_t *) * ppbuffer;
        memset(pmadapter, pchan_list, 0,
               sizeof(MrvlIEtypes_ChanListParamSet_t));
        pchan_list->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
        pchan_list->header.len = sizeof(MrvlIEtypes_ChanListParamSet_t) -
            sizeof(MrvlIEtypesHeader_t);
        pchan_list->chan_scan_param[0].chan_number =
            pbss_desc->pht_info->ht_info.pri_chan;
        pchan_list->chan_scan_param[0].radio_type =
            wlan_band_to_radio_type((t_u8) pbss_desc->bss_band);

        if ((ISSUPP_CHANWIDTH40(pmadapter->hw_dot_11n_dev_cap) &&
             ISSUPP_CHANWIDTH40(pmadapter->usr_dot_11n_dev_cap)) &&
            ISALLOWED_CHANWIDTH40(pbss_desc->pht_info->ht_info.field2))
            SET_SECONDARYCHAN(pchan_list->chan_scan_param[0].radio_type,
                              GET_SECONDARYCHAN(pbss_desc->pht_info->ht_info.
                                                field2));

        HEXDUMP("ChanList", (t_u8 *) pchan_list,
                sizeof(MrvlIEtypes_ChanListParamSet_t));
        HEXDUMP("pht_info", (t_u8 *) pbss_desc->pht_info,
                sizeof(MrvlIETypes_HTInfo_t) - 2);
        *ppbuffer += sizeof(MrvlIEtypes_ChanListParamSet_t);
        ret_len += sizeof(MrvlIEtypes_ChanListParamSet_t);
        pchan_list->header.len = wlan_cpu_to_le16(pchan_list->header.len);
    }

    if (pbss_desc->pbss_co_2040) {
        p2040_bss_co = (MrvlIETypes_2040BSSCo_t *) * ppbuffer;
        memset(pmadapter, p2040_bss_co, 0, sizeof(MrvlIETypes_2040BSSCo_t));
        p2040_bss_co->header.type = wlan_cpu_to_le16(BSSCO_2040);
        p2040_bss_co->header.len = sizeof(BSSCo2040_t);

        memcpy(pmadapter, (t_u8 *) p2040_bss_co + sizeof(MrvlIEtypesHeader_t),
               (t_u8 *) pbss_desc->pbss_co_2040 + sizeof(IEEEtypes_Header_t),
               p2040_bss_co->header.len);

        HEXDUMP("20/40 BSS Coexistence IE", (t_u8 *) p2040_bss_co,
                sizeof(MrvlIETypes_2040BSSCo_t));
        *ppbuffer += sizeof(MrvlIETypes_2040BSSCo_t);
        ret_len += sizeof(MrvlIETypes_2040BSSCo_t);
        p2040_bss_co->header.len = wlan_cpu_to_le16(p2040_bss_co->header.len);
    }

    if (pbss_desc->pext_cap) {
        pext_cap = (MrvlIETypes_ExtCap_t *) * ppbuffer;
        memset(pmadapter, pext_cap, 0, sizeof(MrvlIETypes_ExtCap_t));
        pext_cap->header.type = wlan_cpu_to_le16(EXT_CAPABILITY);
        pext_cap->header.len = sizeof(ExtCap_t);

        memcpy(pmadapter, (t_u8 *) pext_cap + sizeof(MrvlIEtypesHeader_t),
               (t_u8 *) pbss_desc->pext_cap + sizeof(IEEEtypes_Header_t),
               pext_cap->header.len);

        HEXDUMP("Extended Capabilities IE", (t_u8 *) pext_cap,
                sizeof(MrvlIETypes_ExtCap_t));
        *ppbuffer += sizeof(MrvlIETypes_ExtCap_t);
        ret_len += sizeof(MrvlIETypes_ExtCap_t);
        pext_cap->header.len = wlan_cpu_to_le16(pext_cap->header.len);
    }

    LEAVE();
    return ret_len;
}
/**
 *  @brief This function fills the cap info
 *
 *  @param priv         A pointer to mlan_private structure
 *  @param pht_cap      A pointer to MrvlIETypes_HTCap_t structure
 *
 *  @return             N/A
 */
void
wlan_fill_cap_info(mlan_private * priv, MrvlIETypes_HTCap_t * pht_cap)
{
    mlan_adapter *pmadapter = priv->adapter;
    int rx_mcs_supp;

    ENTER();

    if (ISSUPP_CHANWIDTH40(pmadapter->hw_dot_11n_dev_cap) &&
        ISSUPP_CHANWIDTH40(pmadapter->usr_dot_11n_dev_cap))
        SETHT_SUPPCHANWIDTH(pht_cap->ht_cap.ht_cap_info);
    else
        RESETHT_SUPPCHANWIDTH(pht_cap->ht_cap.ht_cap_info);

    if (ISSUPP_GREENFIELD(pmadapter->hw_dot_11n_dev_cap) &&
        ISSUPP_GREENFIELD(pmadapter->usr_dot_11n_dev_cap))
        SETHT_GREENFIELD(pht_cap->ht_cap.ht_cap_info);
    else
        RESETHT_GREENFIELD(pht_cap->ht_cap.ht_cap_info);

    if (ISSUPP_SHORTGI20(pmadapter->hw_dot_11n_dev_cap) &&
        ISSUPP_SHORTGI20(pmadapter->usr_dot_11n_dev_cap))
        SETHT_SHORTGI20(pht_cap->ht_cap.ht_cap_info);
    else
        RESETHT_SHORTGI20(pht_cap->ht_cap.ht_cap_info);

    if (ISSUPP_SHORTGI40(pmadapter->hw_dot_11n_dev_cap) &&
        ISSUPP_SHORTGI40(pmadapter->usr_dot_11n_dev_cap))
        SETHT_SHORTGI40(pht_cap->ht_cap.ht_cap_info);
    else
        RESETHT_SHORTGI40(pht_cap->ht_cap.ht_cap_info);

    /* No user config for RX STBC yet */
    if (ISSUPP_RXSTBC(pmadapter->hw_dot_11n_dev_cap)
        && ISSUPP_RXSTBC(pmadapter->usr_dot_11n_dev_cap))
        SETHT_RXSTBC(pht_cap->ht_cap.ht_cap_info, 1);
    else
        RESETHT_RXSTBC(pht_cap->ht_cap.ht_cap_info);

    /* No user config for TX STBC yet */
    if (ISSUPP_TXSTBC(pmadapter->hw_dot_11n_dev_cap))
        SETHT_TXSTBC(pht_cap->ht_cap.ht_cap_info);
    else
        RESETHT_TXSTBC(pht_cap->ht_cap.ht_cap_info);

    /* No user config for Delayed BACK yet */
    if (GET_DELAYEDBACK(pmadapter->hw_dot_11n_dev_cap))
        SETHT_DELAYEDBACK(pht_cap->ht_cap.ht_cap_info);
    else
        RESETHT_DELAYEDBACK(pht_cap->ht_cap.ht_cap_info);

    if (ISENABLED_40MHZ_INTOLARENT(pmadapter->usr_dot_11n_dev_cap))
        SETHT_40MHZ_INTOLARANT(pht_cap->ht_cap.ht_cap_info);
    else
        RESETHT_40MHZ_INTOLARANT(pht_cap->ht_cap.ht_cap_info);

    SETAMPDU_SIZE(pht_cap->ht_cap.ampdu_param, AMPDU_FACTOR_64K);
    SETAMPDU_SPACING(pht_cap->ht_cap.ampdu_param, 0);

    /* Need change to support 8k AMSDU receive */
    RESETHT_MAXAMSDU(pht_cap->ht_cap.ht_cap_info);

    rx_mcs_supp = GET_RXMCSSUPP(pmadapter->hw_dev_mcs_support);
/** Maximum MCS */
#define NUM_MCS_FIELD      16

    /* Set MCS for 1x1 */
    memset(pmadapter, (t_u8 *) pht_cap->ht_cap.supported_mcs_set, 0xff,
           rx_mcs_supp);
    /* Clear all the other values */
    memset(pmadapter, (t_u8 *) & pht_cap->ht_cap.supported_mcs_set[rx_mcs_supp],
           0, NUM_MCS_FIELD - rx_mcs_supp);
    if (priv->bss_mode == MLAN_BSS_MODE_INFRA ||
        (ISSUPP_CHANWIDTH40(pmadapter->hw_dot_11n_dev_cap) &&
         ISSUPP_CHANWIDTH40(pmadapter->usr_dot_11n_dev_cap)))
        /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
        SETHT_MCS32(pht_cap->ht_cap.supported_mcs_set);

    /* Clear RD responder bit */
    RESETHT_EXTCAP_RDG(pht_cap->ht_cap.ht_ext_cap);

    LEAVE();
}