diff --git a/core/hdd/inc/wlan_hdd_assoc.h b/core/hdd/inc/wlan_hdd_assoc.h index e4b48f8f14b2..8b51e3b1adac 100644 --- a/core/hdd/inc/wlan_hdd_assoc.h +++ b/core/hdd/inc/wlan_hdd_assoc.h @@ -52,6 +52,9 @@ /* Timeout (in ms) for Link to Up before Registering Station */ #define ASSOC_LINKUP_TIMEOUT 60 +/* Timeout in ms for peer info request commpletion */ +#define IBSS_PEER_INFO_REQ_TIMOEUT 1000 + /* Type Declarations */ /** * typedef eConnectionState - Connection states diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 29b424fa1183..4ffb7a650b5b 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -637,6 +637,29 @@ typedef struct hdd_cfg80211_state_s { eP2PActionFrameState actionFrmState; } hdd_cfg80211_state_t; + +/*--------------------------------------------------------------------------- + hdd_ibss_peer_info_params_t + ---------------------------------------------------------------------------*/ +typedef struct { + uint8_t staIdx; /* StaIdx */ + uint32_t txRate; /* Current Tx Rate */ + uint32_t mcsIndex; /* MCS Index */ + uint32_t txRateFlags; /* TxRate Flags */ + int8_t rssi; /* RSSI */ +} hdd_ibss_peer_info_params_t; + +typedef struct { + /** Request status */ + uint32_t status; + + /** Number of peers */ + uint8_t numIBSSPeers; + + /** Peer Info parameters */ + hdd_ibss_peer_info_params_t ibssPeerList[MAX_IBSS_PEERS]; +} hdd_ibss_peer_info_t; + struct hdd_station_ctx { /** Handle to the Wireless Extension State */ hdd_wext_state_t WextState; @@ -663,6 +686,7 @@ struct hdd_station_ctx { /*Save the wep/wpa-none keys */ tCsrRoamSetKey ibss_enc_key; + hdd_ibss_peer_info_t ibss_peer_info; bool hdd_ReassocScenario; @@ -906,6 +930,8 @@ struct hdd_adapter_s { QDF_STATUS tdlsAddStaStatus; #endif + struct completion ibss_peer_info_comp; + /* Track whether the linkup handling is needed */ bool isLinkUpSvcNeeded; @@ -1415,6 +1441,9 @@ int wlan_hdd_validate_context(hdd_context_t *pHddCtx); bool hdd_is_valid_mac_address(const uint8_t *pMacAddr); QDF_STATUS hdd_issta_p2p_clientconnected(hdd_context_t *pHddCtx); +struct qdf_mac_addr * +hdd_wlan_get_ibss_mac_addr_from_staid(hdd_adapter_t *pAdapter, + uint8_t staIdx); void hdd_checkandupdate_phymode(hdd_context_t *pHddCtx); #ifdef MSM_PLATFORM diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 0cf30ce47739..3f329fce1d18 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -9546,6 +9546,7 @@ static int __wlan_hdd_cfg80211_leave_ibss(struct wiphy *wiphy, int status; QDF_STATUS hal_status; unsigned long rc; + tSirUpdateIE updateIE; ENTER(); @@ -9578,6 +9579,22 @@ static int __wlan_hdd_cfg80211_leave_ibss(struct wiphy *wiphy, FL("BSS Type is not set to IBSS")); return -EINVAL; } + /* Clearing add IE of beacon */ + qdf_mem_copy(updateIE.bssid.bytes, pAdapter->macAddressCurrent.bytes, + sizeof(tSirMacAddr)); + updateIE.smeSessionId = pAdapter->sessionId; + updateIE.ieBufferlength = 0; + updateIE.pAdditionIEBuffer = NULL; + updateIE.append = true; + updateIE.notify = true; + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(pAdapter), + &updateIE, + eUPDATE_IE_PROBE_BCN) == QDF_STATUS_E_FAILURE) { + hddLog(LOGE, FL("Could not pass on PROBE_RSP_BCN data to PE")); + } + + /* Reset WNI_CFG_PROBE_RSP Flags */ + wlan_hdd_reset_prob_rspies(pAdapter); /* Issue Disconnect request */ INIT_COMPLETION(pAdapter->disconnect_comp_var); diff --git a/core/hdd/src/wlan_hdd_ioctl.c b/core/hdd/src/wlan_hdd_ioctl.c index e8d80bb0da8d..07667d51ce93 100644 --- a/core/hdd/src/wlan_hdd_ioctl.c +++ b/core/hdd/src/wlan_hdd_ioctl.c @@ -57,6 +57,12 @@ #define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */ #define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */ +/* + * Ibss prop IE from command will be of size: + * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length) + * OUI_DATA should be at least 3 bytes long + */ +#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3) #if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) #define TID_MIN_VALUE 0 @@ -119,6 +125,9 @@ typedef struct { #define WLAN_HDD_MAX_TCP_PORT 65535 #endif +static uint16_t cesium_pid; +extern struct sock *cesium_nl_srv_sock; + #if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics, const uint32_t staId, void *context) @@ -261,6 +270,334 @@ QDF_STATUS hdd_get_tsm_stats(hdd_adapter_t *adapter, } #endif /*FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ +/* Function header is left blank intentionally */ +static int hdd_parse_setrmcenable_command(uint8_t *pValue, + uint8_t *pRmcEnable) +{ + uint8_t *inPtr = pValue; + int tempInt; + int v = 0; + char buf[32]; + *pRmcEnable = 0; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + + if (NULL == inPtr) { + return 0; + } + + else if (SPACE_ASCII_VALUE != *inPtr) { + return 0; + } + + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + if ('\0' == *inPtr) { + return 0; + } + + sscanf(inPtr, "%32s ", buf); + v = kstrtos32(buf, 10, &tempInt); + if (v < 0) { + return -EINVAL; + } + + *pRmcEnable = tempInt; + + hddLog(LOG1, FL("ucRmcEnable: %d"), *pRmcEnable); + + return 0; +} + +/* Function header is left blank intentionally */ +static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue, + uint32_t *pActionPeriod) +{ + uint8_t *inPtr = pValue; + int tempInt; + int v = 0; + char buf[32]; + *pActionPeriod = 0; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + + if (NULL == inPtr) { + return -EINVAL; + } + + else if (SPACE_ASCII_VALUE != *inPtr) { + return -EINVAL; + } + + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + if ('\0' == *inPtr) { + return 0; + } + + sscanf(inPtr, "%32s ", buf); + v = kstrtos32(buf, 10, &tempInt); + if (v < 0) { + return -EINVAL; + } + + if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) || + (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX)) { + return -EINVAL; + } + + *pActionPeriod = tempInt; + + hddLog(LOG1, FL("uActionPeriod: %d"), *pActionPeriod); + + return 0; +} + +/* Function header is left blank intentionally */ +static int hdd_parse_setrmcrate_command(uint8_t *pValue, + uint32_t *pRate, + tTxrateinfoflags *pTxFlags) +{ + uint8_t *inPtr = pValue; + int tempInt; + int v = 0; + char buf[32]; + *pRate = 0; + *pTxFlags = 0; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + + if (NULL == inPtr) { + return -EINVAL; + } + + else if (SPACE_ASCII_VALUE != *inPtr) { + return -EINVAL; + } + + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + if ('\0' == *inPtr) { + return 0; + } + + sscanf(inPtr, "%32s ", buf); + v = kstrtos32(buf, 10, &tempInt); + if (v < 0) { + return -EINVAL; + } + + switch (tempInt) { + default: + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + "Unsupported rate: %d", tempInt); + return -EINVAL; + case 0: + case 6: + case 9: + case 12: + case 18: + case 24: + case 36: + case 48: + case 54: + *pTxFlags = eHAL_TX_RATE_LEGACY; + *pRate = tempInt * 10; + break; + case 65: + *pTxFlags = eHAL_TX_RATE_HT20; + *pRate = tempInt * 10; + break; + case 72: + *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI; + *pRate = 722; + break; + } + + hddLog(LOG1, FL("Rate: %d"), *pRate); + + return 0; +} + +/** + * hdd_cfg80211_get_ibss_peer_info_cb() - Callback function for IBSS + * Peer Info request + * @pUserData: Adapter private data + * @pPeerInfoRsp: Peer info response + * + * This is an asynchronous callback function from SME when the peer info + * is received + * + * Return: 0 for success non-zero for failure + */ +static void +hdd_cfg80211_get_ibss_peer_info_cb(void *pUserData, void *pPeerInfoRsp) +{ + hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData; + hdd_ibss_peer_info_t *pPeerInfo = (hdd_ibss_peer_info_t *)pPeerInfoRsp; + hdd_station_ctx_t *pStaCtx; + uint8_t i; + + /* Sanity check */ + if ((NULL == adapter) || + (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_FATAL, + "invalid adapter or adapter has invalid magic"); + return; + } + + pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) { + pStaCtx->ibss_peer_info.status = pPeerInfo->status; + pStaCtx->ibss_peer_info.numIBSSPeers = pPeerInfo->numIBSSPeers; + + /* Paranoia check */ + if (pPeerInfo->numIBSSPeers < MAX_IBSS_PEERS) { + for (i = 0; i < pPeerInfo->numIBSSPeers; i++) { + memcpy(&pStaCtx->ibss_peer_info.ibssPeerList[i], + &pPeerInfo->ibssPeerList[i], + sizeof(hdd_ibss_peer_info_params_t)); + } + hddLog(LOG1, FL("Peer Info copied in HDD")); + } else { + hddLog(LOG1, + FL("Number of peers %d returned is more than limit %d"), + pPeerInfo->numIBSSPeers, MAX_IBSS_PEERS); + } + } else { + hddLog(LOG1, FL("peerInfo returned is NULL")); + } + + complete(&adapter->ibss_peer_info_comp); +} + +/** + * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info + * @adapter: Adapter context + * + * Request function to get IBSS peer info from lower layers + * + * Return: 0 for success non-zero for failure + */ +static +QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter) +{ + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter); + QDF_STATUS retStatus = QDF_STATUS_E_FAILURE; + unsigned long rc; + + INIT_COMPLETION(adapter->ibss_peer_info_comp); + + retStatus = sme_request_ibss_peer_info(hHal, adapter, + hdd_cfg80211_get_ibss_peer_info_cb, + true, 0xFF); + + if (QDF_STATUS_SUCCESS == retStatus) { + rc = wait_for_completion_timeout + (&adapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); + + /* status will be 0 if timed out */ + if (!rc) { + hddLog(QDF_TRACE_LEVEL_WARN, + "%s: Warning: IBSS_PEER_INFO_TIMEOUT", + __func__); + retStatus = QDF_STATUS_E_FAILURE; + return retStatus; + } + } else { + hddLog(QDF_TRACE_LEVEL_WARN, + "%s: Warning: sme_request_ibss_peer_info Request failed", + __func__); + } + + return retStatus; +} + +/** + * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info + * @adapter: Adapter context + * @staIdx: Sta index for which the peer info is requested + * + * Request function to get IBSS peer info from lower layers + * + * Return: 0 for success non-zero for failure + */ +static QDF_STATUS +hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx) +{ + unsigned long rc; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter); + QDF_STATUS retStatus = QDF_STATUS_E_FAILURE; + + INIT_COMPLETION(adapter->ibss_peer_info_comp); + + retStatus = sme_request_ibss_peer_info(hHal, adapter, + hdd_cfg80211_get_ibss_peer_info_cb, + false, staIdx); + + if (QDF_STATUS_SUCCESS == retStatus) { + rc = wait_for_completion_timeout( + &adapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); + + /* status = 0 on timeout */ + if (!rc) { + hddLog(QDF_TRACE_LEVEL_WARN, + "%s: Warning: IBSS_PEER_INFO_TIMEOUT", + __func__); + retStatus = QDF_STATUS_E_FAILURE; + return retStatus; + } + } else { + hddLog(QDF_TRACE_LEVEL_WARN, + "%s: Warning: sme_request_ibss_peer_info Request failed", + __func__); + } + + return retStatus; +} + +/* Function header is left blank intentionally */ +QDF_STATUS +hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr) +{ + uint8_t *inPtr = pValue; + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + + if (NULL == inPtr) { + return QDF_STATUS_E_FAILURE;; + } + + else if (SPACE_ASCII_VALUE != *inPtr) { + return QDF_STATUS_E_FAILURE;; + } + + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + if ('\0' == *inPtr) { + return QDF_STATUS_E_FAILURE;; + } + + if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' || + inPtr[11] != ':' || inPtr[14] != ':') { + return QDF_STATUS_E_FAILURE;; + } + sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x", + (unsigned int *)&pPeerMacAddr->bytes[0], + (unsigned int *)&pPeerMacAddr->bytes[1], + (unsigned int *)&pPeerMacAddr->bytes[2], + (unsigned int *)&pPeerMacAddr->bytes[3], + (unsigned int *)&pPeerMacAddr->bytes[4], + (unsigned int *)&pPeerMacAddr->bytes[5]); + + return QDF_STATUS_SUCCESS; +} + static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand) { eCsrBand band = -1; @@ -2158,6 +2495,144 @@ static int wlan_hdd_get_link_status(hdd_adapter_t *adapter) return adapter->linkStatus; } +static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo) +{ + int payload_len; + struct sk_buff *skb; + struct nlmsghdr *nlh; + uint8_t *data; + + payload_len = ETH_ALEN; + + if (0 == cesium_pid) { + hddLog(QDF_TRACE_LEVEL_ERROR, + "%s: cesium process not registered", __func__); + return; + } + + skb = nlmsg_new(payload_len, GFP_ATOMIC); + if (skb == NULL) { + hddLog(LOGE, + FL("nlmsg_new() failed for msg size[%d]"), + NLMSG_SPACE(payload_len)); + return; + } + + nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST); + + if (NULL == nlh) { + hddLog(QDF_TRACE_LEVEL_ERROR, + "%s: nlmsg_put() failed for msg size[%d]", + __func__, NLMSG_SPACE(payload_len)); + + kfree_skb(skb); + return; + } + + data = nlmsg_data(nlh); + memcpy(data, MacAddr, ETH_ALEN); + + if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) { + hddLog(QDF_TRACE_LEVEL_ERROR, + "%s: nlmsg_unicast() failed for msg size[%d]", + __func__, NLMSG_SPACE(payload_len)); + } + + return; +} + + +/** + * hdd_ParseuserParams - return a pointer to the next argument + * @pValue: Input argument string + * @ppArg: Output pointer to the next argument + * + * This function parses argument stream and finds the pointer + * to the next argument + * + * Return: 0 if the next argument found; -EINVAL otherwise + */ +static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg) +{ + uint8_t *pVal; + + pVal = strnchr(pValue, strlen(pValue), ' '); + + if (NULL == pVal) { + /* no argument remains */ + return -EINVAL; + } else if (SPACE_ASCII_VALUE != *pVal) { + /* no space after the current argument */ + return -EINVAL; + } + + pVal++; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) { + pVal++; + } + + /* no argument followed by spaces */ + if ('\0' == *pVal) { + return -EINVAL; + } + + *ppArg = pVal; + + return 0; +} + +/** + * hdd_parse_ibsstx_fail_event_params - Parse params + * for SETIBSSTXFAILEVENT + * @pValue: Input ibss tx fail event argument + * @tx_fail_count: (Output parameter) Tx fail counter + * @pid: (Output parameter) PID + * + * Return: 0 if the parsing succeeds; -EINVAL otherwise + */ +static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue, + uint8_t *tx_fail_count, + uint16_t *pid) +{ + uint8_t *param = NULL; + int ret; + + ret = hdd_parse_user_params(pValue, ¶m); + + if (0 == ret && NULL != param) { + if (1 != sscanf(param, "%hhu", tx_fail_count)) { + ret = -EINVAL; + goto done; + } + } else { + goto done; + } + + if (0 == *tx_fail_count) { + *pid = 0; + goto done; + } + + pValue = param; + pValue++; + + ret = hdd_parse_user_params(pValue, ¶m); + + if (0 == ret) { + if (1 != sscanf(param, "%hu", pid)) { + ret = -EINVAL; + goto done; + } + } else { + goto done; + } + +done: + return ret; +} + #if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) /** * hdd_parse_ese_beacon_req() - Parse ese beacon request @@ -4658,6 +5133,683 @@ exit: return ret; } +/* Function header is left blank intentionally */ +static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie, + int32_t *oui_length, int32_t limit) +{ + uint8_t len; + uint8_t data; + + while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) { + command++; + limit--; + } + + len = 2; + + while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) && + (limit > 1)) { + sscanf(command, "%02x", (unsigned int *)&data); + ie[len++] = data; + command += 2; + limit -= 2; + } + + *oui_length = len - 2; + + while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) { + command++; + limit--; + } + + while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) && + (limit > 1)) { + sscanf(command, "%02x", (unsigned int *)&data); + ie[len++] = data; + command += 2; + limit -= 2; + } + + ie[0] = IE_EID_VENDOR; + ie[1] = len - 2; + + return len; +} + +/** + * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command + * @adapter: Pointer to adapter + * @hdd_ctx: Pointer to HDD context + * @command: Pointer to command string + * @command_len : Command length + * @priv_data : Pointer to priv data + * + * Return: + * int status code + */ +static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int i = 0; + int status; + int ret = 0; + uint8_t *ibss_ie; + int32_t oui_length = 0; + uint32_t ibss_ie_length; + uint8_t *value = command; + tSirModifyIE ibssModifyIE; + tCsrRoamProfile *pRoamProfile; + hdd_wext_state_t *pWextState; + + + if (WLAN_HDD_IBSS != adapter->device_mode) { + hddLog(LOG1, FL("Device_mode %s(%d) not IBSS"), + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return ret; + } + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter); + + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s: received command %s", __func__, + ((char *)value)); + + + /* validate argument of command */ + if (strlen(value) <= command_len) { + hddLog(LOGE, + FL("No arguements in command length %zu"), + strlen(value)); + ret = -EFAULT; + goto exit; + } + + /* moving to arguments of commands */ + value = value + command_len; + command_len = strlen(value); + + /* oui_data can't be less than 3 bytes */ + if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) { + hddLog(LOGE, + FL("Invalid SETIBSSBEACONOUIDATA command length %d"), + command_len); + ret = -EFAULT; + goto exit; + } + + ibss_ie = qdf_mem_malloc(command_len); + if (!ibss_ie) { + hddLog(LOGE, + FL("Could not allocate memory for command length %d"), + command_len); + ret = -ENOMEM; + goto exit; + } + qdf_mem_zero(ibss_ie, command_len); + + ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie, + &oui_length, + command_len); + if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) { + hddLog(LOGE, FL("Could not parse command %s return length %d"), + value, ibss_ie_length); + ret = -EFAULT; + qdf_mem_free(ibss_ie); + goto exit; + } + + pRoamProfile = &pWextState->roamProfile; + + qdf_copy_macaddr(&ibssModifyIE.bssid, + pRoamProfile->BSSIDs.bssid); + + ibssModifyIE.smeSessionId = adapter->sessionId; + ibssModifyIE.notify = true; + ibssModifyIE.ieID = IE_EID_VENDOR; + ibssModifyIE.ieIDLen = ibss_ie_length; + ibssModifyIE.ieBufferlength = ibss_ie_length; + ibssModifyIE.pIEBuffer = ibss_ie; + ibssModifyIE.oui_length = oui_length; + + hddLog(LOGW, FL("ibss_ie length %d oui_length %d ibss_ie:"), + ibss_ie_length, oui_length); + while (i < ibssModifyIE.ieBufferlength) + hddLog(LOGW, FL("0x%x"), ibss_ie[i++]); + + /* Probe Bcn modification */ + sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter), + &ibssModifyIE, eUPDATE_IE_PROBE_BCN); + + /* Populating probe resp frame */ + sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter), + &ibssModifyIE, eUPDATE_IE_PROBE_RESP); + + qdf_mem_free(ibss_ie); + + status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal), + adapter->sessionId); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "Could not send cesium enable indication %d", + status); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t ucRmcEnable = 0; + int status; + + if ((WLAN_HDD_IBSS != adapter->device_mode) && + (WLAN_HDD_SOFTAP != adapter->device_mode)) { + hddLog(LOGE, + "Received SETRMCENABLE cmd in invalid mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + hddLog(LOGE, + "SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode"); + ret = -EINVAL; + goto exit; + } + + status = hdd_parse_setrmcenable_command(value, &ucRmcEnable); + if (status) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "Invalid SETRMCENABLE command "); + ret = -EINVAL; + goto exit; + } + + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s: ucRmcEnable %d ", __func__, ucRmcEnable); + + if (true == ucRmcEnable) { + status = sme_enable_rmc((tHalHandle) + (hdd_ctx->hHal), + adapter->sessionId); + } else if (false == ucRmcEnable) { + status = sme_disable_rmc((tHalHandle) + (hdd_ctx->hHal), + adapter->sessionId); + } else { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "Invalid SETRMCENABLE command %d", + ucRmcEnable); + ret = -EINVAL; + goto exit; + } + + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: SETRMC %d failed status %d", + __func__, ucRmcEnable, status); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint32_t uActionPeriod = 0; + int status; + + if ((WLAN_HDD_IBSS != adapter->device_mode) && + (WLAN_HDD_SOFTAP != adapter->device_mode)) { + hddLog(LOGE, "Received SETRMC cmd in invalid mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + hddLog(LOGE, + "SETRMC cmd is allowed only in IBSS/SOFTAP mode"); + ret = -EINVAL; + goto exit; + } + + status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod); + if (status) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "Invalid SETRMCACTIONPERIOD command "); + ret = -EINVAL; + goto exit; + } + + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s: uActionPeriod %d ", __func__, + uActionPeriod); + + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + uActionPeriod)) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: Could not set SETRMCACTIONPERIOD %d", + __func__, uActionPeriod); + ret = -EINVAL; + goto exit; + } + + status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal), + adapter->sessionId); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "Could not send cesium enable indication %d", + status); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + int status = QDF_STATUS_SUCCESS; + hdd_station_ctx_t *pHddStaCtx = NULL; + char *extra = NULL; + int idx = 0; + int length = 0; + struct qdf_mac_addr *macAddr; + uint32_t txRateMbps = 0; + uint32_t numOfBytestoPrint = 0; + + if (WLAN_HDD_IBSS != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s: Received GETIBSSPEERINFOALL Command", + __func__); + + /* Handle the command */ + status = hdd_cfg80211_get_ibss_peer_info_all(adapter); + if (QDF_STATUS_SUCCESS == status) { + /* + * The variable extra needed to be allocated on the heap since + * amount of memory required to copy the data for 32 devices + * exceeds the size of 1024 bytes of default stack size. On + * 64 bit devices, the default max stack size of 2048 bytes + */ + extra = kmalloc(WLAN_MAX_BUF_SIZE, GFP_KERNEL); + + if (NULL == extra) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s:kmalloc failed", + __func__); + ret = -EINVAL; + goto exit; + } + + /* Copy number of stations */ + length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ", + pHddStaCtx->ibss_peer_info. + numIBSSPeers); + numOfBytestoPrint = length; + for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numIBSSPeers; + idx++) { + macAddr = hdd_wlan_get_ibss_mac_addr_from_staid + (adapter, + pHddStaCtx->ibss_peer_info. + ibssPeerList[idx].staIdx); + if (NULL != macAddr) { + txRateMbps = ((pHddStaCtx-> + ibss_peer_info. + ibssPeerList[idx].txRate) + * 500 * 1000) / 1000000; + length += scnprintf((extra + length), + WLAN_MAX_BUF_SIZE - length, + "%02x:%02x:%02x:%02x:%02x:%02x %d %d ", + macAddr->bytes[0], + macAddr->bytes[1], + macAddr->bytes[2], + macAddr->bytes[3], + macAddr->bytes[4], + macAddr->bytes[5], + (int)txRateMbps, + (int)pHddStaCtx-> + ibss_peer_info. + ibssPeerList[idx]. + rssi); + } else { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: MAC ADDR is NULL for staIdx: %d", + __func__, + pHddStaCtx-> + ibss_peer_info. + ibssPeerList[idx]. + staIdx); + } + + /* + * QDF_TRACE() macro has limitation of 512 bytes + * for the print buffer. Hence printing the data + * in two chunks. The first chunk will have the data + * for 16 devices and the second chunk will + * have the rest. + */ + if (idx < NUM_OF_STA_DATA_TO_PRINT) + numOfBytestoPrint = length; + } + + /* + * Copy the data back into buffer, if the data to copy is + * more than 512 bytes than we will split the data and do + * it in two shots + */ + if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: Copy into user data buffer failed ", + __func__); + ret = -EFAULT; + goto exit; + } + + priv_data->buf[numOfBytestoPrint] = '\0'; + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_INFO_MED, "%s", + priv_data->buf); + + if (length > numOfBytestoPrint) { + if (copy_to_user + (priv_data->buf + numOfBytestoPrint, + extra + numOfBytestoPrint, + length - numOfBytestoPrint + 1)) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: Copy into user data buffer failed ", + __func__); + ret = -EFAULT; + goto exit; + } + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_INFO_MED, + "%s", + &priv_data->buf[numOfBytestoPrint]); + } + + /* Free temporary buffer */ + kfree(extra); + } else { + /* Command failed, log error */ + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: GETIBSSPEERINFOALL command failed with status code %d", + __func__, status); + ret = -EINVAL; + goto exit; + } + ret = 0; + +exit: + return ret; +} + +/* Peer Info command */ +static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + QDF_STATUS status; + hdd_station_ctx_t *pHddStaCtx = NULL; + char extra[128] = { 0 }; + uint32_t length = 0; + uint8_t staIdx = 0; + uint32_t txRateMbps = 0; + uint32_t txRate; + struct qdf_mac_addr peerMacAddr; + + if (WLAN_HDD_IBSS != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s: Received GETIBSSPEERINFO Command", + __func__); + + /* if there are no peers, no need to continue with the command */ + if (eConnectionState_IbssConnected != + pHddStaCtx->conn_info.connState) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_INFO, + "%s:No IBSS Peers coalesced", + __func__); + ret = -EINVAL; + goto exit; + } + + /* Parse the incoming command buffer */ + status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: Invalid GETIBSSPEERINFO command", + __func__); + ret = -EINVAL; + goto exit; + } + + /* Get station index for the peer mac address */ + hdd_ibss_get_sta_id(pHddStaCtx, &peerMacAddr, &staIdx); + + if (staIdx > MAX_IBSS_PEERS) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: Invalid StaIdx %d returned", + __func__, staIdx); + ret = -EINVAL; + goto exit; + } + + /* Handle the command */ + status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx); + if (QDF_STATUS_SUCCESS == status) { + txRate = pHddStaCtx->ibss_peer_info.ibssPeerList[0].txRate; + txRateMbps = (txRate * 500 * 1000) / 1000000; + + length = scnprintf(extra, sizeof(extra), "%d %d", + (int)txRateMbps, + (int)pHddStaCtx->ibss_peer_info. + ibssPeerList[0].rssi); + + /* Copy the data back into buffer */ + if (copy_to_user(priv_data->buf, &extra, length + 1)) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: copy data to user buffer failed GETIBSSPEERINFO command", + __func__); + ret = -EFAULT; + goto exit; + } + } else { + /* Command failed, log error */ + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: GETIBSSPEERINFO command failed with status code %d", + __func__, status); + ret = -EINVAL; + goto exit; + } + + /* Success ! */ + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_MED, + "%s", priv_data->buf); + ret = 0; + +exit: + return ret; +} + +static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint32_t uRate = 0; + tTxrateinfoflags txFlags = 0; + tSirRateUpdateInd rateUpdateParams = {0}; + int status; + struct hdd_config *pConfig = hdd_ctx->config; + + if ((WLAN_HDD_IBSS != adapter->device_mode) && + (WLAN_HDD_SOFTAP != adapter->device_mode)) { + hddLog(LOGE, + "Received SETRMCTXRATE cmd in invalid mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + hddLog(LOGE, + "SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode"); + ret = -EINVAL; + goto exit; + } + + status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags); + if (status) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "Invalid SETRMCTXRATE command "); + ret = -EINVAL; + goto exit; + } + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s: uRate %d ", __func__, uRate); + /* -1 implies ignore this param */ + rateUpdateParams.ucastDataRate = -1; + + /* + * Fill the user specifieed RMC rate param + * and the derived tx flags. + */ + rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1; + rateUpdateParams.reliableMcastDataRate = uRate; + rateUpdateParams.reliableMcastDataRateTxFlag = txFlags; + rateUpdateParams.dev_mode = adapter->device_mode; + rateUpdateParams.bcastDataRate = -1; + memcpy(rateUpdateParams.bssid.bytes, + adapter->macAddressCurrent.bytes, + sizeof(rateUpdateParams.bssid)); + status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal), + &rateUpdateParams); + +exit: + return ret; +} + +static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + char *value; + uint8_t tx_fail_count = 0; + uint16_t pid = 0; + + value = command; + + ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid); + + if (0 != ret) { + hddLog(QDF_TRACE_LEVEL_INFO, + "%s: Failed to parse SETIBSSTXFAILEVENT arguments", + __func__); + goto exit; + } + + hddLog(QDF_TRACE_LEVEL_INFO, + "%s: tx_fail_cnt=%hhu, pid=%hu", __func__, + tx_fail_count, pid); + + if (0 == tx_fail_count) { + /* Disable TX Fail Indication */ + if (QDF_STATUS_SUCCESS == + sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal, + tx_fail_count, + NULL)) { + cesium_pid = 0; + } else { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: failed to disable TX Fail Event ", + __func__); + ret = -EINVAL; + } + } else { + if (QDF_STATUS_SUCCESS == + sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal, + tx_fail_count, + (void *)hdd_tx_fail_ind_callback)) { + cesium_pid = pid; + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_INFO, + "%s: Registered Cesium pid %u", + __func__, cesium_pid); + } else { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: Failed to enable TX Fail Monitoring", + __func__); + ret = -EINVAL; + } + } + +exit: + return ret; +} + #if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx, @@ -6133,6 +7285,13 @@ static const hdd_drv_cmd_t hdd_drv_cmds[] = { {"GETDWELLTIME", drv_cmd_get_dwell_time}, {"SETDWELLTIME", drv_cmd_set_dwell_time}, {"MIRACAST", drv_cmd_miracast}, + {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data}, + {"SETRMCENABLE", drv_cmd_set_rmc_enable}, + {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period}, + {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all}, + {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info}, + {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate}, + {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event}, #if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels}, {"GETTSMSTATS", drv_cmd_get_tsm_stats}, diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 96d4a81e02c4..e77dba13e1b8 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -146,6 +146,8 @@ static int wlan_hdd_inited; */ DEFINE_SPINLOCK(hdd_context_lock); +#define WLAN_NLINK_CESIUM 30 + static qdf_wake_lock_t wlan_wake_lock; #define WOW_MAX_FILTER_LISTS 1 @@ -1619,6 +1621,45 @@ static void hdd_uninit(struct net_device *dev) cds_ssr_unprotect(__func__); } +static int hdd_open_cesium_nl_sock(void) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct netlink_kernel_cfg cfg = { + .groups = WLAN_NLINK_MCAST_GRP_ID, + .input = NULL + }; +#endif + int ret = 0; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + cesium_nl_srv_sock = netlink_kernel_create(&init_net, WLAN_NLINK_CESIUM, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + THIS_MODULE, +#endif + &cfg); +#else + cesium_nl_srv_sock = netlink_kernel_create(&init_net, WLAN_NLINK_CESIUM, + WLAN_NLINK_MCAST_GRP_ID, + NULL, NULL, THIS_MODULE); +#endif + + if (cesium_nl_srv_sock == NULL) { + hddLog(QDF_TRACE_LEVEL_ERROR, + FL("NLINK: cesium netlink_kernel_create failed")); + ret = -ECONNREFUSED; + } + + return ret; +} + +static void hdd_close_cesium_nl_sock(void) +{ + if (NULL != cesium_nl_srv_sock) { + netlink_kernel_release(cesium_nl_srv_sock); + cesium_nl_srv_sock = NULL; + } +} + /** * __hdd_set_mac_address() - set the user specified mac address * @dev: Pointer to the net device. @@ -1889,6 +1930,7 @@ static hdd_adapter_t *hdd_alloc_station_adapter(hdd_context_t *hdd_ctx, init_completion(&adapter->tdls_mgmt_comp); init_completion(&adapter->tdls_link_establish_req_comp); #endif + init_completion(&adapter->ibss_peer_info_comp); init_completion(&adapter->change_country_code); @@ -3832,6 +3874,8 @@ void hdd_wlan_exit(hdd_context_t *hdd_ctx) hdd_close_all_adapters(hdd_ctx, false); + hdd_close_cesium_nl_sock(); + hdd_ipa_cleanup(hdd_ctx); /* Free up RoC request queue and flush workqueue */ @@ -5680,6 +5724,11 @@ int hdd_wlan_startup(struct device *dev, void *hif_sc) goto err_nl_srv; } + if (hdd_open_cesium_nl_sock() < 0) { + hdd_alert("hdd_open_cesium_nl_sock failed"); + goto err_nl_srv; + } + /* * Action frame registered in one adapter which will * applicable to all interfaces @@ -5832,6 +5881,8 @@ err_nl_srv: /* Proceed and complete the clean up */ } + hdd_close_cesium_nl_sock(); + err_close_adapter: hdd_release_rtnl_lock(); diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index 3c3fd4a2fe75..e5df3242fb1e 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -307,7 +307,7 @@ static const hdd_freq_chan_map_t freq_chan_map[] = { #define WE_GET_11W_INFO 9 #endif #define WE_GET_STATES 10 - +#define WE_GET_IBSS_STA_INFO 11 #define WE_GET_PHYMODE 12 #ifdef FEATURE_OEM_DATA_SUPPORT #define WE_GET_OEM_DATA_CAP 13 @@ -318,7 +318,7 @@ static const hdd_freq_chan_map_t freq_chan_map[] = { /* Private ioctls and their sub-ioctls */ #define WLAN_PRIV_SET_NONE_GET_NONE (SIOCIWFIRSTPRIV + 6) #define WE_SET_REASSOC_TRIGGER 8 - +#define WE_IBSS_GET_PEER_INFO_ALL 10 #define WE_DUMP_AGC_START 11 #define WE_DUMP_AGC 12 #define WE_DUMP_CHANINFO_START 13 @@ -341,7 +341,7 @@ static const hdd_freq_chan_map_t freq_chan_map[] = { #ifdef FEATURE_WLAN_TDLS #define WE_TDLS_CONFIG_PARAMS 5 #endif - +#define WE_IBSS_GET_PEER_INFO 6 #define WE_UNIT_TEST_CMD 7 #define WE_MTRACE_DUMP_CMD 8 @@ -766,6 +766,194 @@ error: return; } +/** + * hdd_get_ibss_peer_info_cb() - IBSS Peer Info Callback + * @pUserData: user context originally passed to SME; we pass hdd adapter + * @pPeerInfoRsp: IBSS Peer information + * + * Return: None + */ +void hdd_get_ibss_peer_info_cb(void *pUserData, void *pPeerInfoRsp) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) pUserData; + hdd_ibss_peer_info_t *pPeerInfo = (hdd_ibss_peer_info_t *) pPeerInfoRsp; + hdd_station_ctx_t *pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + uint8_t i; + + if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) { + pStaCtx->ibss_peer_info.status = pPeerInfo->status; + pStaCtx->ibss_peer_info.numIBSSPeers = pPeerInfo->numIBSSPeers; + for (i = 0; i < pPeerInfo->numIBSSPeers; i++) { + memcpy(&pStaCtx->ibss_peer_info.ibssPeerList[i], + &pPeerInfo->ibssPeerList[i], + sizeof(hdd_ibss_peer_info_params_t)); + } + } else { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s] PEER_INFO_CMD_STATUS is not SUCCESS", __func__); + } + + complete(&pAdapter->ibss_peer_info_comp); +} + +/** + * hdd_wlan_get_ibss_mac_addr_from_staid() - Get IBSS MAC address + * @pAdapter: Adapter upon which the IBSS client is active + * @staIdx: Station index of the IBSS peer + * + * Return: a pointer to the MAC address of the IBSS peer if the peer is + * found, otherwise %NULL. + */ +struct qdf_mac_addr * +hdd_wlan_get_ibss_mac_addr_from_staid(hdd_adapter_t *pAdapter, + uint8_t staIdx) +{ + uint8_t idx; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + for (idx = 0; idx < MAX_IBSS_PEERS; idx++) { + if (0 != pHddStaCtx->conn_info.staId[idx] && + staIdx == pHddStaCtx->conn_info.staId[idx]) { + return &pHddStaCtx->conn_info.peerMacAddress[idx]; + } + } + return NULL; +} + +/** + * hdd_wlan_get_ibss_peer_info() - Print IBSS peer information + * @pAdapter: Adapter upon which the IBSS client is active + * @staIdx: Station index of the IBSS peer + * + * Return: QDF_STATUS_STATUS if the peer was found and displayed, + * otherwise an appropriate QDF_STATUS_E_* failure code. + */ +QDF_STATUS hdd_wlan_get_ibss_peer_info(hdd_adapter_t *pAdapter, uint8_t staIdx) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_station_ctx_t *pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_ibss_peer_info_t *pPeerInfo = &pStaCtx->ibss_peer_info; + + status = + sme_request_ibss_peer_info(hHal, pAdapter, hdd_get_ibss_peer_info_cb, + false, staIdx); + + INIT_COMPLETION(pAdapter->ibss_peer_info_comp); + + if (QDF_STATUS_SUCCESS == status) { + unsigned long rc; + rc = wait_for_completion_timeout + (&pAdapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); + if (!rc) { + hddLog(QDF_TRACE_LEVEL_ERROR, + FL("failed wait on ibss_peer_info_comp")); + return QDF_STATUS_E_FAILURE; + } + + /** Print the peer info */ + pr_info("pPeerInfo->numIBSSPeers = %d ", + pPeerInfo->numIBSSPeers); + pr_info + ("============================================================"); + { + struct qdf_mac_addr *macAddr = + hdd_wlan_get_ibss_mac_addr_from_staid(pAdapter, + staIdx); + uint32_t txRateMbps = + ((pPeerInfo->ibssPeerList[0].txRate) * 500 * 1000) / + 1000000; + + if (NULL != macAddr) { + pr_info("PEER ADDR :" MAC_ADDRESS_STR + " TxRate: %d Mbps RSSI: %d", + MAC_ADDR_ARRAY(macAddr->bytes), + (int)txRateMbps, + (int)pPeerInfo->ibssPeerList[0].rssi); + } else { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + " ERROR: PEER MAC ADDRESS NOT FOUND "); + } + } + } else { + hddLog(QDF_TRACE_LEVEL_WARN, + "%s: Warning: sme_request_ibss_peer_info Request failed", + __func__); + } + + return status; +} + +/** + * hdd_wlan_get_ibss_peer_info_all() - Print all IBSS peers + * @pAdapter: Adapter upon which the IBSS clients are active + * + * Return: QDF_STATUS_STATUS if the peer information was retrieved and + * displayed, otherwise an appropriate QDF_STATUS_E_* failure code. + */ +QDF_STATUS hdd_wlan_get_ibss_peer_info_all(hdd_adapter_t *pAdapter) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_station_ctx_t *pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_ibss_peer_info_t *pPeerInfo = &pStaCtx->ibss_peer_info; + int i; + + status = + sme_request_ibss_peer_info(hHal, pAdapter, hdd_get_ibss_peer_info_cb, + true, 0xFF); + INIT_COMPLETION(pAdapter->ibss_peer_info_comp); + + if (QDF_STATUS_SUCCESS == status) { + unsigned long rc; + rc = wait_for_completion_timeout + (&pAdapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); + if (!rc) { + hddLog(QDF_TRACE_LEVEL_ERROR, + FL("failed wait on ibss_peer_info_comp")); + return QDF_STATUS_E_FAILURE; + } + + /** Print the peer info */ + pr_info("pPeerInfo->numIBSSPeers = %d ", + (int)pPeerInfo->numIBSSPeers); + pr_info + ("============================================================"); + for (i = 0; i < pPeerInfo->numIBSSPeers; i++) { + uint8_t staIdx = pPeerInfo->ibssPeerList[i].staIdx; + struct qdf_mac_addr *macAddr = + hdd_wlan_get_ibss_mac_addr_from_staid(pAdapter, + staIdx); + uint32_t txRateMbps = + ((pPeerInfo->ibssPeerList[0].txRate) * 500 * 1000) / + 1000000; + + pr_info("STAIDX:%d ", + (int)pPeerInfo->ibssPeerList[i].staIdx); + if (NULL != macAddr) { + pr_info(" PEER ADDR :" MAC_ADDRESS_STR + " TxRate: %d Mbps RSSI: %d", + MAC_ADDR_ARRAY(macAddr->bytes), + (int)txRateMbps, + (int)pPeerInfo->ibssPeerList[i].rssi); + } else { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + " ERROR: PEER MAC ADDRESS NOT FOUND "); + } + } + } else { + hddLog(QDF_TRACE_LEVEL_WARN, + "%s: Warning: sme_request_ibss_peer_info Request failed", + __func__); + } + + return status; +} + /** * hdd_wlan_get_rts_threshold() - Get RTS threshold * @pAdapter: adapter upon which the request was received @@ -7260,6 +7448,39 @@ static int __iw_get_char_setnone(struct net_device *dev, break; } #endif + case WE_GET_IBSS_STA_INFO: + { + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + int idx = 0; + int length = 0, buf = 0; + + for (idx = 0; idx < MAX_IBSS_PEERS; idx++) { + if (0 != pHddStaCtx->conn_info.staId[idx]) { + buf = snprintf + ((extra + length), + WE_MAX_STR_LEN - length, + "\n%d .%02x:%02x:%02x:%02x:%02x:%02x\n", + pHddStaCtx->conn_info.staId[idx], + pHddStaCtx->conn_info. + peerMacAddress[idx].bytes[0], + pHddStaCtx->conn_info. + peerMacAddress[idx].bytes[1], + pHddStaCtx->conn_info. + peerMacAddress[idx].bytes[2], + pHddStaCtx->conn_info. + peerMacAddress[idx].bytes[3], + pHddStaCtx->conn_info. + peerMacAddress[idx].bytes[4], + pHddStaCtx->conn_info. + peerMacAddress[idx].bytes[5] + ); + length += buf; + } + } + wrqu->data.length = strlen(extra) + 1; + break; + } case WE_GET_PHYMODE: { bool ch_bond24 = false, ch_bond5g = false; @@ -7470,6 +7691,12 @@ static int __iw_setnone_getnone(struct net_device *dev, 0, DBG_CMD); break; + case WE_IBSS_GET_PEER_INFO_ALL: + { + hdd_wlan_get_ibss_peer_info_all(adapter); + break; + } + case WE_SET_REASSOC_TRIGGER: { hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); @@ -7628,6 +7855,12 @@ static int __iw_set_var_ints_getnone(struct net_device *dev, hddLog(LOG1, FL("Received length %d"), wrqu->data.length); switch (sub_cmd) { + case WE_IBSS_GET_PEER_INFO: + { + pr_info("Station ID = %d\n", apps_args[0]); + hdd_wlan_get_ibss_peer_info(pAdapter, apps_args[0]); + } + break; case WE_P2P_NOA_CMD: { @@ -10424,7 +10657,12 @@ static const struct iw_priv_args we_private_args[] = { "getPMFInfo" }, #endif - + { + WE_GET_IBSS_STA_INFO, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getIbssSTAs" + }, {WE_GET_PHYMODE, 0, IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, @@ -10446,6 +10684,13 @@ static const struct iw_priv_args we_private_args[] = { 0, ""}, + /* handlers for sub-ioctl */ + { + WE_IBSS_GET_PEER_INFO_ALL, + 0, + 0, + "ibssPeerInfoAll" + }, {WE_GET_RECOVERY_STAT, 0, 0, @@ -10501,6 +10746,12 @@ static const struct iw_priv_args we_private_args[] = { 0, ""}, + /* handlers for sub-ioctl */ + {WE_IBSS_GET_PEER_INFO, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "ibssPeerInfo"}, + /* handlers for sub-ioctl */ {WE_MTRACE_SELECTIVE_MODULE_LOG_ENABLE_CMD, IW_PRIV_TYPE_INT | MAX_VAR_ARGS, diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index d6c6af0b3130..ee72d48841ca 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -1770,6 +1770,13 @@ typedef struct sAniDHCPStopInd { struct qdf_mac_addr peerMacAddr; } tAniDHCPInd, *tpAniDHCPInd; +typedef struct sAniTXFailMonitorInd { + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t tx_fail_count; + void *txFailIndCallback; +} tAniTXFailMonitorInd, *tpAniTXFailMonitorInd; + typedef enum eTxRateInfo { eHAL_TX_RATE_LEGACY = 0x1, /* Legacy rates */ eHAL_TX_RATE_HT20 = 0x2, /* HT20 rates */ @@ -3683,6 +3690,41 @@ typedef struct sSirDelPeriodicTxPtrn { uint8_t ucPtrnId; /* Pattern ID */ } tSirDelPeriodicTxPtrn, *tpSirDelPeriodicTxPtrn; +/*--------------------------------------------------------------------------- +* tSirIbssGetPeerInfoReqParams +*--------------------------------------------------------------------------*/ +typedef struct { + bool allPeerInfoReqd; /* If set, all IBSS peers stats are reported */ + uint8_t staIdx; /* If allPeerInfoReqd is not set, only stats */ + /* of peer with staIdx is reported */ +} tSirIbssGetPeerInfoReqParams, *tpSirIbssGetPeerInfoReqParams; + +/*--------------------------------------------------------------------------- +* tSirIbssGetPeerInfoParams +*--------------------------------------------------------------------------*/ +typedef struct { + uint8_t staIdx; /* StaIdx */ + uint32_t txRate; /* Tx Rate */ + uint32_t mcsIndex; /* MCS Index */ + uint32_t txRateFlags; /* TxRate Flags */ + int8_t rssi; /* RSSI */ +} tSirIbssPeerInfoParams; + +typedef struct { + uint32_t status; + uint8_t numPeers; + tSirIbssPeerInfoParams peerInfoParams[32]; +} tSirPeerInfoRspParams, *tpSirIbssPeerInfoRspParams; + +/*--------------------------------------------------------------------------- +* tSirIbssGetPeerInfoRspParams +*--------------------------------------------------------------------------*/ +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + tSirPeerInfoRspParams ibssPeerInfoRspParams; +} tSirIbssGetPeerInfoRspParams, *tpSirIbssGetPeerInfoRspParams; + typedef struct { uint16_t mesgType; uint16_t mesgLen; @@ -3817,6 +3859,7 @@ typedef struct sSirModifyIE { uint8_t ieIDLen; /*ie length as per spec */ uint16_t ieBufferlength; uint8_t *pIEBuffer; + int32_t oui_length; } tSirModifyIE, *tpSirModifyIE; diff --git a/core/mac/inc/wni_api.h b/core/mac/inc/wni_api.h index 225149cda2d0..103cb278d3f2 100644 --- a/core/mac/inc/wni_api.h +++ b/core/mac/inc/wni_api.h @@ -181,6 +181,7 @@ enum eWniMsgTypes { eWNI_SME_LPHB_IND, #endif /* FEATURE_WLAN_LPHB */ + eWNI_SME_IBSS_PEER_INFO_RSP, eWNI_SME_GET_TSM_STATS_REQ, eWNI_SME_GET_TSM_STATS_RSP, eWNI_SME_TSM_IE_IND, diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h index 0264f898f947..46e20cd29d25 100644 --- a/core/mac/src/include/sir_params.h +++ b/core/mac/src/include/sir_params.h @@ -427,6 +427,9 @@ typedef struct sSirMbMsgP2p { #define SIR_HAL_SOC_DUAL_MAC_CFG_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 154) #define SIR_HAL_SOC_DUAL_MAC_CFG_RESP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 155) +/* For IBSS peer info related messages */ +#define SIR_HAL_IBSS_PEER_INFO_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 158) + #define SIR_HAL_RATE_UPDATE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 159) #define SIR_HAL_FLUSH_LOG_TO_FW (SIR_HAL_ITC_MSG_TYPES_BEGIN + 160) @@ -449,6 +452,8 @@ typedef struct sSirMbMsgP2p { #define SIR_HAL_SET_MAX_TX_POWER_PER_BAND_REQ \ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 170) +#define SIR_HAL_TX_FAIL_MONITOR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 171) + #define SIR_HAL_UPDATE_MEMBERSHIP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 172) #define SIR_HAL_UPDATE_USERPOS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 173) @@ -464,6 +469,11 @@ typedef struct sSirMbMsgP2p { #define SIR_HAL_BEACON_TX_SUCCESS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 179) #define SIR_HAL_DFS_RADAR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 180) +#define SIR_HAL_IBSS_CESIUM_ENABLE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 181) + +#define SIR_HAL_RMC_ENABLE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 182) +#define SIR_HAL_RMC_DISABLE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 183) +#define SIR_HAL_RMC_ACTION_PERIOD_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 184) #define SIR_HAL_INIT_THERMAL_INFO_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 185) #define SIR_HAL_SET_THERMAL_LEVEL (SIR_HAL_ITC_MSG_TYPES_BEGIN + 186) diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c index 24c4f3f4e4a1..f202f26d7ec2 100644 --- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -106,7 +106,10 @@ static void lim_update_add_ie_buffer(tpAniSirGlobal pMac, uint8_t **pDstData_buff, uint16_t *pDstDataLen, uint8_t *pSrcData_buff, uint16_t srcDataLen); - +static bool lim_update_ibss_prop_add_ies(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + tSirModifyIE *pModifyIE); static void lim_process_modify_add_ies(tpAniSirGlobal pMac, uint32_t *pMsg); static void lim_process_update_add_ies(tpAniSirGlobal pMac, uint32_t *pMsg); @@ -5177,6 +5180,44 @@ lim_update_add_ie_buffer(tpAniSirGlobal pMac, } +/** + * lim_update_ibss_prop_add_ies() - update IBSS prop IE + * @pMac : Pointer to Global MAC structure + * @pDstData_buff : A pointer to pointer of dst buffer + * @pDstDataLen : A pointer to pointer of dst buffer length + * @pModifyIE : A pointer to tSirModifyIE + * + * This function replaces previous ibss prop_ie with new ibss prop_ie. + * + * Return: + * True or false depending upon whether IE is updated or not + */ +static bool +lim_update_ibss_prop_add_ies(tpAniSirGlobal pMac, uint8_t **pDstData_buff, + uint16_t *pDstDataLen, tSirModifyIE *pModifyIE) +{ + int32_t oui_length; + uint8_t *ibss_ie = NULL; + + ibss_ie = pModifyIE->pIEBuffer; + oui_length = pModifyIE->oui_length; + + if ((0 == oui_length) || (NULL == ibss_ie)) { + PELOGE(lim_log(pMac, LOGE, + FL("Invalid set IBSS vendor IE command length %d "), + oui_length);) + return false; + } + + lim_update_add_ie_buffer(pMac, + pDstData_buff, + pDstDataLen, + pModifyIE->pIEBuffer, + pModifyIE->ieBufferlength); + + return true; +} + /* * lim_process_modify_add_ies() - process modify additional IE req. * @@ -5228,6 +5269,12 @@ static void lim_process_modify_add_ies(tpAniSirGlobal mac_ctx, switch (modify_add_ies->updateType) { case eUPDATE_IE_PROBE_RESP: /* Probe resp */ + if (LIM_IS_IBSS_ROLE(session_entry)) { + lim_update_ibss_prop_add_ies(mac_ctx, + &add_ie_params->probeRespData_buff, + &add_ie_params->probeRespDataLen, + &modify_add_ies->modifyIE); + } break; case eUPDATE_IE_ASSOC_RESP: /* assoc resp IE */ @@ -5241,6 +5288,12 @@ static void lim_process_modify_add_ies(tpAniSirGlobal mac_ctx, break; case eUPDATE_IE_PROBE_BCN: /*probe beacon IE */ + if (LIM_IS_IBSS_ROLE(session_entry)) { + ret = lim_update_ibss_prop_add_ies(mac_ctx, + &add_ie_params->probeRespBCNData_buff, + &add_ie_params->probeRespBCNDataLen, + &modify_add_ies->modifyIE); + } if (ret == true && modify_add_ies->modifyIE.notify) { lim_handle_param_update(mac_ctx, modify_add_ies->updateType); diff --git a/core/mac/src/sys/legacy/src/utils/src/mac_trace.c b/core/mac/src/sys/legacy/src/utils/src/mac_trace.c index e170a11bbaa4..b249ed6d8d2a 100644 --- a/core/mac/src/sys/legacy/src/utils/src/mac_trace.c +++ b/core/mac/src/sys/legacy/src/utils/src/mac_trace.c @@ -489,6 +489,12 @@ uint8_t *mac_trace_get_wma_msg_string(uint16_t wma_msg) #ifdef FEATURE_WLAN_AUTO_SHUTDOWN CASE_RETURN_STRING(WMA_SET_AUTO_SHUTDOWN_TIMER_REQ); #endif + CASE_RETURN_STRING(WMA_IBSS_CESIUM_ENABLE_IND); + CASE_RETURN_STRING(WMA_GET_IBSS_PEER_INFO_REQ); + CASE_RETURN_STRING(WMA_TX_FAIL_MONITOR_IND); + CASE_RETURN_STRING(WMA_RMC_ENABLE_IND); + CASE_RETURN_STRING(WMA_RMC_DISABLE_IND); + CASE_RETURN_STRING(WMA_RMC_ACTION_PERIOD_IND); CASE_RETURN_STRING(WMA_INIT_THERMAL_INFO_CMD); CASE_RETURN_STRING(WMA_SET_THERMAL_LEVEL); CASE_RETURN_STRING(WMA_SET_SAP_INTRABSS_DIS); diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h index 6072d95ec379..ea13b14f25ec 100644 --- a/core/sme/inc/csr_api.h +++ b/core/sme/inc/csr_api.h @@ -479,6 +479,8 @@ typedef enum { eCSR_ROAM_UNPROT_MGMT_FRAME_IND, #endif + eCSR_ROAM_IBSS_PEER_INFO_COMPLETE, + #if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) eCSR_ROAM_TSM_IE_IND, eCSR_ROAM_CCKM_PREAUTH_NOTIFY, @@ -583,6 +585,8 @@ typedef enum { eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED, #endif + eCSR_ROAM_RESULT_IBSS_PEER_INFO_SUCCESS, + eCSR_ROAM_RESULT_IBSS_PEER_INFO_FAILED, eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND, eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS, eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE, diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index c50e837962ce..95af7d96b6c6 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -421,6 +421,9 @@ QDF_STATUS sme_change_country_code(tHalHandle hHal, tAniBool sendRegHint); QDF_STATUS sme_generic_change_country_code(tHalHandle hHal, uint8_t *pCountry); +QDF_STATUS sme_tx_fail_monitor_start_stop_ind(tHalHandle hHal, + uint8_t tx_fail_count, + void *txFailIndCallback); QDF_STATUS sme_dhcp_start_ind(tHalHandle hHal, uint8_t device_mode, uint8_t *macAddr, uint8_t sessionId); @@ -717,6 +720,13 @@ QDF_STATUS sme_roam_del_pmkid_from_cache(tHalHandle hHal, uint8_t sessionId, const uint8_t *pBSSId, bool flush_cache); void sme_get_command_q_status(tHalHandle hHal); +QDF_STATUS sme_enable_rmc(tHalHandle hHal, uint32_t sessionId); +QDF_STATUS sme_disable_rmc(tHalHandle hHal, uint32_t sessionId); +QDF_STATUS sme_send_rmc_action_period(tHalHandle hHal, uint32_t sessionId); +QDF_STATUS sme_request_ibss_peer_info(tHalHandle hHal, void *pUserData, + pIbssPeerInfoCb peerInfoCbk, bool allPeerInfoReqd, uint8_t staIdx); +QDF_STATUS sme_send_cesium_enable_ind(tHalHandle hHal, uint32_t sessionId); + /* * SME API to enable/disable idle mode powersave * This should be called only if powersave offload diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index 9c9a9976147f..994fd53b2065 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -103,6 +103,15 @@ typedef enum eSmeState { #define SME_IS_START(pMac) (SME_STATE_STOP != (pMac)->sme.state) #define SME_IS_READY(pMac) (SME_STATE_READY == (pMac)->sme.state) +/* HDD Callback function */ +typedef void (*pIbssPeerInfoCb)(void *pUserData, void *infoParam); + +/* Peer info */ +typedef struct tagSmePeerInfoHddCbkInfo { + void *pUserData; + pIbssPeerInfoCb peerInfoCbk; +} tSmePeerInfoHddCbkInfo; + typedef struct sStatsExtEvent { uint32_t vdev_id; uint32_t event_data_len; @@ -156,6 +165,7 @@ typedef struct tagSmeStruct { tDblLinkList smeScanCmdPendingList; /* active scan command list */ tDblLinkList smeScanCmdActiveList; + tSmePeerInfoHddCbkInfo peerInfoParams; #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR host_event_wlan_status_payload_type eventPayload; #endif diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 7c435503aac1..be84e41c73b1 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -2092,6 +2092,28 @@ QDF_STATUS sme_set_ese_beacon_request(tHalHandle hHal, const uint8_t sessionId, #endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ +QDF_STATUS sme_ibss_peer_info_response_handleer(tHalHandle hHal, + tpSirIbssGetPeerInfoRspParams + pIbssPeerInfoParams) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: pMac is null", __func__); + return QDF_STATUS_E_FAILURE; + } + if (pMac->sme.peerInfoParams.peerInfoCbk == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: HDD callback is null", __func__); + return QDF_STATUS_E_FAILURE; + } + pMac->sme.peerInfoParams.peerInfoCbk(pMac->sme.peerInfoParams.pUserData, + &pIbssPeerInfoParams-> + ibssPeerInfoRspParams); + return QDF_STATUS_SUCCESS; +} + /** * sme_process_fw_mem_dump_rsp - process fw memory dump response from WMA * @@ -2457,7 +2479,17 @@ QDF_STATUS sme_process_msg(tHalHandle hHal, cds_msg_t *pMsg) qdf_mem_free(pMsg->bodyptr); break; #endif /* FEATURE_WLAN_LPHB */ - + case eWNI_SME_IBSS_PEER_INFO_RSP: + if (pMsg->bodyptr) { + sme_ibss_peer_info_response_handleer(pMac, + pMsg-> + bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; case eWNI_SME_READY_TO_SUSPEND_IND: if (pMsg->bodyptr) { sme_process_ready_to_suspend(pMac, pMsg->bodyptr); @@ -5334,6 +5366,60 @@ QDF_STATUS sme_dhcp_stop_ind(tHalHandle hHal, return status; } +/*--------------------------------------------------------------------------- + + \fn sme_TXFailMonitorStopInd + + \brief API to signal the FW to start monitoring TX failures + + \return QDF_STATUS SUCCESS. + + FAILURE or RESOURCES The API finished and failed. + --------------------------------------------------------------------------*/ +QDF_STATUS sme_tx_fail_monitor_start_stop_ind(tHalHandle hHal, uint8_t tx_fail_count, + void *txFailIndCallback) +{ + QDF_STATUS status; + QDF_STATUS qdf_status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tAniTXFailMonitorInd *pMsg; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + pMsg = (tAniTXFailMonitorInd *) + qdf_mem_malloc(sizeof(tAniTXFailMonitorInd)); + if (NULL == pMsg) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to allocate memory", __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + + pMsg->msgType = WMA_TX_FAIL_MONITOR_IND; + pMsg->msgLen = (uint16_t) sizeof(tAniTXFailMonitorInd); + + /* tx_fail_count = 0 should disable the Monitoring in FW */ + pMsg->tx_fail_count = tx_fail_count; + pMsg->txFailIndCallback = txFailIndCallback; + + cds_message.type = WMA_TX_FAIL_MONITOR_IND; + cds_message.bodyptr = pMsg; + cds_message.reserved = 0; + + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post TX Fail monitor Start MSG fail", + __func__); + qdf_mem_free(pMsg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + /* --------------------------------------------------------------------------- \fn sme_set_cfg_privacy \brief API to set configure privacy parameters @@ -10643,6 +10729,185 @@ sme_del_periodic_tx_ptrn(tHalHandle hal, return status; } +/** + * sme_enable_rmc() - enables RMC + * @hHal : Pointer to global HAL handle + * @sessionId : Session ID + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_enable_rmc(tHalHandle hHal, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + sms_log(pMac, LOG1, FL("enable RMC")); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + cds_message.bodyptr = NULL; + cds_message.type = WMA_RMC_ENABLE_IND; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post message to WMA", + __func__); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_disable_rmc() - disables RMC + * @hHal : Pointer to global HAL handle + * @sessionId : Session ID + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_disable_rmc(tHalHandle hHal, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + sms_log(pMac, LOG1, FL("disable RMC")); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + cds_message.bodyptr = NULL; + cds_message.type = WMA_RMC_DISABLE_IND; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post message to WMA", + __func__); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_send_rmc_action_period() - sends RMC action period param to target + * @hHal : Pointer to global HAL handle + * @sessionId : Session ID + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_send_rmc_action_period(tHalHandle hHal, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + cds_message.bodyptr = NULL; + cds_message.type = WMA_RMC_ACTION_PERIOD_IND; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post message to WMA", + __func__); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/** + * sme_request_ibss_peer_info() - request ibss peer info + * @hHal : Pointer to global HAL handle + * @pUserData : Pointer to user data + * @peerInfoCbk : Peer info callback + * @allPeerInfoReqd : All peer info required or not + * @staIdx : sta index + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_request_ibss_peer_info(tHalHandle hHal, void *pUserData, + pIbssPeerInfoCb peerInfoCbk, + bool allPeerInfoReqd, uint8_t staIdx) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tSirIbssGetPeerInfoReqParams *pIbssInfoReqParams; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + pMac->sme.peerInfoParams.peerInfoCbk = peerInfoCbk; + pMac->sme.peerInfoParams.pUserData = pUserData; + + pIbssInfoReqParams = (tSirIbssGetPeerInfoReqParams *) + qdf_mem_malloc(sizeof(tSirIbssGetPeerInfoReqParams)); + if (NULL == pIbssInfoReqParams) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for dhcp start", + __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + pIbssInfoReqParams->allPeerInfoReqd = allPeerInfoReqd; + pIbssInfoReqParams->staIdx = staIdx; + + cds_message.type = WMA_GET_IBSS_PEER_INFO_REQ; + cds_message.bodyptr = pIbssInfoReqParams; + cds_message.reserved = 0; + + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (QDF_STATUS_SUCCESS != qdf_status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post WMA_GET_IBSS_PEER_INFO_REQ MSG failed", + __func__); + qdf_mem_free(pIbssInfoReqParams); + qdf_status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + + return qdf_status; +} + +/* --------------------------------------------------------------------------- + \fn sme_send_cesium_enable_ind + \brief Used to send proprietary cesium enable indication to fw + \param hHal + \param sessionId + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_send_cesium_enable_ind(tHalHandle hHal, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + cds_message.bodyptr = NULL; + cds_message.type = WMA_IBSS_CESIUM_ENABLE_IND; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post message to WMA", + __func__); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + void sme_get_command_q_status(tHalHandle hHal) { tSmeCmd *pTempCmd = NULL; diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 8a33e767cf55..fbc4e43a9c7a 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -18103,6 +18103,7 @@ csr_roam_modify_add_ies(tpAniSirGlobal pMac, pModifyAddIEInd->modifyIE.ieIDLen = pModifyIE->ieIDLen; pModifyAddIEInd->modifyIE.pIEBuffer = pLocalBuffer; pModifyAddIEInd->modifyIE.ieBufferlength = pModifyIE->ieBufferlength; + pModifyAddIEInd->modifyIE.oui_length = pModifyIE->oui_length; pModifyAddIEInd->updateType = updateType; diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index c20b6820f89b..9b2ccdef514c 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -383,6 +383,8 @@ static const t_probeTime_dwellTime {28, 8} /* 10 SSID */ }; +typedef void (*txFailIndCallback)(uint8_t *peer_mac, uint8_t seqNo); + /** * enum t_wma_drv_type - wma driver type * @WMA_DRIVER_TYPE_PRODUCTION: production driver type @@ -1265,7 +1267,7 @@ typedef struct { uint8_t ibss_started; tSetBssKeyParams ibsskey_info; struct ieee80211com *dfs_ic; - + txFailIndCallback hddTxFailCb; #ifdef FEATURE_WLAN_SCAN_PNO qdf_wake_lock_t pno_wake_lock; #endif @@ -1292,6 +1294,8 @@ typedef struct { uint8_t staMaxLIModDtim; uint8_t staModDtim; uint8_t staDynamicDtim; + uint8_t enable_mhf_offload; + unsigned long last_mhf_entries_timestamp; int32_t dfs_pri_multiplier; uint32_t hw_bd_id; uint32_t hw_bd_info[HW_BD_INFO_SIZE]; diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index 9e97d2a7580f..b6741ea690ee 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -101,6 +101,9 @@ #define WMI_MAX_HOST_CREDITS 2 #define WMI_WOW_REQUIRED_CREDITS 1 +#define WMI_MAX_MHF_ENTRIES 32 + + #define MAX_HT_MCS_IDX 8 #define MAX_VHT_MCS_IDX 10 #define INVALID_MCS_IDX 255 @@ -795,6 +798,12 @@ QDF_STATUS wma_set_thermal_mgmt(tp_wma_handle wma_handle, int wma_thermal_mgmt_evt_handler(void *handle, uint8_t *event, uint32_t len); +int wma_ibss_peer_info_event_handler(void *handle, uint8_t *data, + uint32_t len); + +int wma_fast_tx_fail_event_handler(void *handle, uint8_t *data, + uint32_t len); + /* * wma_utils.c functions declarations */ @@ -1017,6 +1026,20 @@ QDF_STATUS wma_enable_arp_ns_offload(tp_wma_handle wma, tpSirHostOffloadReq pHostOffloadParams, bool bArpOnly); +QDF_STATUS wma_process_cesium_enable_ind(tp_wma_handle wma); + +QDF_STATUS wma_process_get_peer_info_req + (tp_wma_handle wma, tSirIbssGetPeerInfoReqParams *pReq); + +QDF_STATUS wma_process_tx_fail_monitor_ind + (tp_wma_handle wma, tAniTXFailMonitorInd *pReq); + +QDF_STATUS wma_process_rmc_enable_ind(tp_wma_handle wma); + +QDF_STATUS wma_process_rmc_disable_ind(tp_wma_handle wma); + +QDF_STATUS wma_process_rmc_action_period_ind(tp_wma_handle wma); + QDF_STATUS wma_process_add_periodic_tx_ptrn_ind(WMA_HANDLE handle, tSirAddPeriodicTxPtrn * pAddPeriodicTxPtrnParams); diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h index 9d4d1af58cc9..7d440c7a9163 100644 --- a/core/wma/inc/wma_types.h +++ b/core/wma/inc/wma_types.h @@ -303,6 +303,8 @@ #define WMA_DHCP_START_IND SIR_HAL_DHCP_START_IND #define WMA_DHCP_STOP_IND SIR_HAL_DHCP_STOP_IND +#define WMA_TX_FAIL_MONITOR_IND SIR_HAL_TX_FAIL_MONITOR_IND + #define WMA_HIDDEN_SSID_VDEV_RESTART SIR_HAL_HIDE_SSID_VDEV_RESTART #ifdef WLAN_FEATURE_GTK_OFFLOAD @@ -358,6 +360,14 @@ #define WMA_INIT_THERMAL_INFO_CMD SIR_HAL_INIT_THERMAL_INFO_CMD #define WMA_SET_THERMAL_LEVEL SIR_HAL_SET_THERMAL_LEVEL +#define WMA_RMC_ENABLE_IND SIR_HAL_RMC_ENABLE_IND +#define WMA_RMC_DISABLE_IND SIR_HAL_RMC_DISABLE_IND +#define WMA_RMC_ACTION_PERIOD_IND SIR_HAL_RMC_ACTION_PERIOD_IND + +/* IBSS peer info related message */ +#define WMA_GET_IBSS_PEER_INFO_REQ SIR_HAL_IBSS_PEER_INFO_REQ + +#define WMA_IBSS_CESIUM_ENABLE_IND SIR_HAL_IBSS_CESIUM_ENABLE_IND #ifdef FEATURE_WLAN_TDLS #define WMA_UPDATE_FW_TDLS_STATE SIR_HAL_UPDATE_FW_TDLS_STATE @@ -584,6 +594,8 @@ typedef void (*pWMATxRxCompFunc)(void *pContext, void *pData, /* parameter 2 - txComplete status : 1- success, 0 - failure. */ typedef QDF_STATUS (*pWMAAckFnTxComp)(tpAniSirGlobal, uint32_t); +typedef void (*wma_txFailIndCallback)(uint8_t *, uint8_t); + /* generic callback for updating parameters from target to UMAC */ typedef void (*wma_tgt_cfg_cb)(void *context, void *param); diff --git a/core/wma/src/wma_data.c b/core/wma/src/wma_data.c index 22f727255185..18bc5059501f 100644 --- a/core/wma/src/wma_data.c +++ b/core/wma/src/wma_data.c @@ -1976,6 +1976,152 @@ int wma_thermal_mgmt_evt_handler(void *handle, uint8_t *event, return 0; } +/** + * wma_ibss_peer_info_event_handler() - IBSS peer info event handler + * @handle: wma handle + * @data: event data + * @len: length of data + * + * This function handles IBSS peer info event from FW. + * + * Return: 0 for success or error code + */ +int wma_ibss_peer_info_event_handler(void *handle, uint8_t *data, + uint32_t len) +{ + cds_msg_t cds_msg; + wmi_peer_info *peer_info; + ol_txrx_pdev_handle pdev; + struct ol_txrx_peer_t *peer; + tSirIbssPeerInfoParams *pSmeRsp; + uint32_t count, num_peers, status; + tSirIbssGetPeerInfoRspParams *pRsp; + WMI_PEER_INFO_EVENTID_param_tlvs *param_tlvs; + wmi_peer_info_event_fixed_param *fix_param; + uint8_t peer_mac[IEEE80211_ADDR_LEN], staIdx; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == pdev) { + WMA_LOGE("%s: could not get pdev context", __func__); + return 0; + } + + param_tlvs = (WMI_PEER_INFO_EVENTID_param_tlvs *) data; + fix_param = param_tlvs->fixed_param; + peer_info = param_tlvs->peer_info; + num_peers = fix_param->num_peers; + status = 0; + + WMA_LOGE("%s: num_peers %d", __func__, num_peers); + + pRsp = qdf_mem_malloc(sizeof(tSirIbssGetPeerInfoRspParams)); + if (NULL == pRsp) { + WMA_LOGE("%s: could not allocate memory for ibss peer info rsp len %zu", + __func__, sizeof(tSirIbssGetPeerInfoRspParams)); + return 0; + } + + /*sanity check */ + if ((num_peers > 32) || (NULL == peer_info)) { + WMA_LOGE("%s: Invalid event data from target num_peers %d peer_info %p", + __func__, num_peers, peer_info); + status = 1; + goto send_response; + } + + for (count = 0; count < num_peers; count++) { + pSmeRsp = &pRsp->ibssPeerInfoRspParams.peerInfoParams[count]; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_info->peer_mac_address, + peer_mac); + peer = ol_txrx_find_peer_by_addr(pdev, peer_mac, &staIdx); + if (NULL == peer) { + WMA_LOGE("%s: peer 0x:%2x:0x%2x:0x%2x:0x%2x:0x%2x:0x%2x does not" + " exist could not populate response", __func__, + peer_mac[0], peer_mac[1], peer_mac[2], + peer_mac[3], peer_mac[4], peer_mac[5]); + + pSmeRsp->staIdx = 0xff; /*fill invalid staIdx */ + peer_info++; + continue; + } + pSmeRsp->staIdx = staIdx; + pSmeRsp->mcsIndex = 0; + pSmeRsp->rssi = peer_info->rssi + WMA_TGT_NOISE_FLOOR_DBM; + pSmeRsp->txRate = peer_info->data_rate; + pSmeRsp->txRateFlags = 0; + + WMA_LOGE("%s: peer 0x:%2x:0x%2x:0x%2x:0x%2x:0x%2x:0x%2x staIdx %d " + "rssi %d txRate %d", __func__, peer_mac[0], peer_mac[1], + peer_mac[2], peer_mac[3], peer_mac[4], peer_mac[5], + staIdx, pSmeRsp->rssi, pSmeRsp->txRate); + + peer_info++; + } + +send_response: + /* message header */ + pRsp->mesgType = eWNI_SME_IBSS_PEER_INFO_RSP; + pRsp->mesgLen = sizeof(tSirIbssGetPeerInfoRspParams); + pRsp->ibssPeerInfoRspParams.status = status; + pRsp->ibssPeerInfoRspParams.numPeers = num_peers; + + /* cds message wrapper */ + cds_msg.type = eWNI_SME_IBSS_PEER_INFO_RSP; + cds_msg.bodyptr = (void *)pRsp; + cds_msg.bodyval = 0; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, (cds_msg_t *) &cds_msg)) { + WMA_LOGE("%s: could not post peer info rsp msg to SME", + __func__); + /* free the mem and return */ + qdf_mem_free((void *)pRsp); + } + + return 0; +} + +/** + * wma_fast_tx_fail_event_handler() -tx failure event handler + * @handle: wma handle + * @data: event data + * @len: data length + * + * Handle fast tx failure indication event from FW + * + * Return: 0 for success or error code. + */ +int wma_fast_tx_fail_event_handler(void *handle, uint8_t *data, + uint32_t len) +{ + uint8_t tx_fail_cnt; + uint8_t peer_mac[IEEE80211_ADDR_LEN]; + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_PEER_TX_FAIL_CNT_THR_EVENTID_param_tlvs *param_tlvs; + wmi_peer_tx_fail_cnt_thr_event_fixed_param *fix_param; + + param_tlvs = (WMI_PEER_TX_FAIL_CNT_THR_EVENTID_param_tlvs *) data; + fix_param = param_tlvs->fixed_param; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&fix_param->peer_mac_address, peer_mac); + WMA_LOGE("%s: received fast tx failure event for peer" + " 0x:%2x:0x%2x:0x%2x:0x%2x:0x%2x:0x%2x seq No %d", __func__, + peer_mac[0], peer_mac[1], peer_mac[2], peer_mac[3], + peer_mac[4], peer_mac[5], fix_param->seq_no); + + tx_fail_cnt = fix_param->seq_no; + + /*call HDD callback */ + if (NULL != wma->hddTxFailCb) { + wma->hddTxFailCb(peer_mac, tx_fail_cnt); + } else { + WMA_LOGE("%s: HDD callback is %p", __func__, wma->hddTxFailCb); + } + + return 0; +} + /** * wma_decap_to_8023() - Decapsulate to 802.3 format * @msdu: skb buffer diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index 2db824c61073..b344c275cd9a 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -4323,6 +4323,325 @@ QDF_STATUS wma_enable_arp_ns_offload(tp_wma_handle wma, return QDF_STATUS_SUCCESS; } +/** + * wma_process_cesium_enable_ind() - enables cesium functionality in target + * @wma: wma handle + * + * Return: QDF status + */ +QDF_STATUS wma_process_cesium_enable_ind(tp_wma_handle wma) +{ + QDF_STATUS ret; + int32_t vdev_id; + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not enable cesium", + __func__); + return QDF_STATUS_E_FAILURE; + } + + /* Send enable cesium command to target */ + WMA_LOGE("Enable cesium in target for vdevId %d ", vdev_id); + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_ENABLE_RMC, 1); + if (ret) { + WMA_LOGE("Enable cesium failed for vdevId %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_get_peer_info_req() - sends get peer info cmd to target + * @wma: wma handle + * @preq: get peer info request + * + * Return: QDF status + */ +QDF_STATUS wma_process_get_peer_info_req + (tp_wma_handle wma, tSirIbssGetPeerInfoReqParams *pReq) +{ + int32_t ret; + uint8_t *p; + uint16_t len; + wmi_buf_t buf; + int32_t vdev_id; + ol_txrx_pdev_handle pdev; + struct ol_txrx_peer_t *peer; + uint8_t peer_mac[IEEE80211_ADDR_LEN]; + wmi_peer_info_req_cmd_fixed_param *p_get_peer_info_cmd; + uint8_t bcast_mac[IEEE80211_ADDR_LEN] = { 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff }; + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not get peer info", + __func__); + return QDF_STATUS_E_FAILURE; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev context", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (0xFF == pReq->staIdx) { + /*get info for all peers */ + qdf_mem_copy(peer_mac, bcast_mac, IEEE80211_ADDR_LEN); + } else { + /*get info for a single peer */ + peer = ol_txrx_peer_find_by_local_id(pdev, pReq->staIdx); + if (!peer) { + WMA_LOGE("%s: Failed to get peer handle using peer id %d", + __func__, pReq->staIdx); + return QDF_STATUS_E_FAILURE; + } + WMA_LOGE("%s: staIdx %d peer mac: 0x%2x:0x%2x:0x%2x:0x%2x:0x%2x:0x%2x", + __func__, pReq->staIdx, peer->mac_addr.raw[0], + peer->mac_addr.raw[1], peer->mac_addr.raw[2], + peer->mac_addr.raw[3], peer->mac_addr.raw[4], + peer->mac_addr.raw[5]); + qdf_mem_copy(peer_mac, peer->mac_addr.raw, IEEE80211_ADDR_LEN); + } + + len = sizeof(wmi_peer_info_req_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(p, len); + p_get_peer_info_cmd = (wmi_peer_info_req_cmd_fixed_param *) p; + + WMITLV_SET_HDR(&p_get_peer_info_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_info_req_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_info_req_cmd_fixed_param)); + + p_get_peer_info_cmd->vdev_id = vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_mac, + &p_get_peer_info_cmd->peer_mac_address); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PEER_INFO_REQ_CMDID); + + WMA_LOGE("IBSS get peer info cmd sent len: %d, vdev %d" + " command id: %d, status: %d", len, + p_get_peer_info_cmd->vdev_id, WMI_PEER_INFO_REQ_CMDID, ret); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_tx_fail_monitor_ind() - sends tx fail monitor cmd to target + * @wma: wma handle + * @pReq: tx fail monitor command params + * + * Return: QDF status + */ +QDF_STATUS wma_process_tx_fail_monitor_ind + (tp_wma_handle wma, tAniTXFailMonitorInd *pReq) +{ + QDF_STATUS ret; + int32_t vdev_id; + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not send fast tx fail" + " monitor indication message to target", __func__); + return QDF_STATUS_E_FAILURE; + } + + /* Send enable cesium command to target */ + WMA_LOGE("send fast tx fail monitor ind cmd target for vdevId %d val %d", + vdev_id, pReq->tx_fail_count); + + if (0 == pReq->tx_fail_count) { + wma->hddTxFailCb = NULL; + } else { + wma->hddTxFailCb = pReq->txFailIndCallback; + } + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_SET_IBSS_TX_FAIL_CNT_THR, + pReq->tx_fail_count); + if (ret) { + WMA_LOGE("tx fail monitor failed for vdevId %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_rmc_enable_ind() - enables RMC functionality in target + * @wma: wma handle + * + * Return: QDF status + */ +QDF_STATUS wma_process_rmc_enable_ind(tp_wma_handle wma) +{ + int ret; + uint8_t *p; + uint16_t len; + wmi_buf_t buf; + int32_t vdev_id; + wmi_rmc_set_mode_cmd_fixed_param *p_rmc_enable_cmd; + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not enable RMC", + __func__); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(wmi_rmc_set_mode_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(p, len); + p_rmc_enable_cmd = (wmi_rmc_set_mode_cmd_fixed_param *) p; + + WMITLV_SET_HDR(&p_rmc_enable_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_rmc_set_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_rmc_set_mode_cmd_fixed_param)); + + p_rmc_enable_cmd->vdev_id = vdev_id; + p_rmc_enable_cmd->enable_rmc = WMI_RMC_MODE_ENABLED; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_RMC_SET_MODE_CMDID); + + WMA_LOGE("Enable RMC cmd sent len: %d, vdev %d" " command id: %d," + " status: %d", len, p_rmc_enable_cmd->vdev_id, + WMI_RMC_SET_MODE_CMDID, ret); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_rmc_disable_ind() - disables rmc functionality in target + * @wma: wma handle + * + * Return: QDF status + */ +QDF_STATUS wma_process_rmc_disable_ind(tp_wma_handle wma) +{ + int ret; + uint8_t *p; + uint16_t len; + wmi_buf_t buf; + int32_t vdev_id; + wmi_rmc_set_mode_cmd_fixed_param *p_rmc_disable_cmd; + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not disable RMC", + __func__); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(wmi_rmc_set_mode_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(p, len); + p_rmc_disable_cmd = (wmi_rmc_set_mode_cmd_fixed_param *) p; + + WMITLV_SET_HDR(&p_rmc_disable_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_rmc_set_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_rmc_set_mode_cmd_fixed_param)); + + p_rmc_disable_cmd->vdev_id = vdev_id; + p_rmc_disable_cmd->enable_rmc = WMI_RMC_MODE_DISABLED; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_RMC_SET_MODE_CMDID); + + WMA_LOGE("Disable RMC cmd sent len: %d, vdev %d" " command id: %d," + " status: %d", len, p_rmc_disable_cmd->vdev_id, + WMI_RMC_SET_MODE_CMDID, ret); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_rmc_action_period_ind() - sends RMC action period to target + * @wma: wma handle + * + * Return: QDF status + */ +QDF_STATUS wma_process_rmc_action_period_ind(tp_wma_handle wma) +{ + int ret; + uint8_t *p; + uint16_t len; + uint32_t val; + wmi_buf_t buf; + int32_t vdev_id; + wmi_rmc_set_action_period_cmd_fixed_param *p_rmc_cmd; + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (NULL == mac) { + WMA_LOGE("%s: MAC mac does not exist", __func__); + return QDF_STATUS_E_FAILURE; + } + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not send" + " RMC action period to target", __func__); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(wmi_rmc_set_action_period_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(p, len); + p_rmc_cmd = (wmi_rmc_set_action_period_cmd_fixed_param *) p; + + WMITLV_SET_HDR(&p_rmc_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_rmc_set_action_period_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_rmc_set_action_period_cmd_fixed_param)); + + if (wlan_cfg_get_int(mac, WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, &val) + != eSIR_SUCCESS) { + WMA_LOGE("Failed to get value for RMC action period using default"); + val = WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STADEF; + } + + p_rmc_cmd->vdev_id = vdev_id; + p_rmc_cmd->periodicity_msec = val; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_RMC_SET_ACTION_PERIOD_CMDID); + + WMA_LOGE("RMC action period %d cmd sent len: %d, vdev %d" + " command id: %d, status: %d", p_rmc_cmd->periodicity_msec, + len, p_rmc_cmd->vdev_id, WMI_RMC_SET_ACTION_PERIOD_CMDID, ret); + + return QDF_STATUS_SUCCESS; +} + /** * wma_process_add_periodic_tx_ptrn_ind - add periodic tx ptrn * @handle: wma handle diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 9d4a9e2d4c0a..f503ed43a7e8 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -2695,6 +2695,34 @@ QDF_STATUS wma_start(void *cds_ctx) goto end; #endif /* QCA_WIFI_FTM */ + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_RMC)) { + + WMA_LOGD("FW supports cesium network, registering event handlers"); + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_INFO_EVENTID, + wma_ibss_peer_info_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register ibss peer info event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_TX_FAIL_CNT_THR_EVENTID, + wma_fast_tx_fail_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register peer fast tx failure event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + } else { + WMA_LOGE("Target does not support cesium network"); + } + qdf_status = wma_tx_attach(wma_handle); if (qdf_status != QDF_STATUS_SUCCESS) { WMA_LOGP("%s: Failed to register tx management", __func__); @@ -4860,6 +4888,30 @@ QDF_STATUS wma_mc_process_msg(void *cds_context, cds_msg_t *msg) qdf_mem_free(msg->bodyptr); break; + case WMA_IBSS_CESIUM_ENABLE_IND: + wma_process_cesium_enable_ind(wma_handle); + break; + case WMA_GET_IBSS_PEER_INFO_REQ: + wma_process_get_peer_info_req(wma_handle, + (tSirIbssGetPeerInfoReqParams *) + msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_TX_FAIL_MONITOR_IND: + wma_process_tx_fail_monitor_ind(wma_handle, + (tAniTXFailMonitorInd *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + + case WMA_RMC_ENABLE_IND: + wma_process_rmc_enable_ind(wma_handle); + break; + case WMA_RMC_DISABLE_IND: + wma_process_rmc_disable_ind(wma_handle); + break; + case WMA_RMC_ACTION_PERIOD_IND: + wma_process_rmc_action_period_ind(wma_handle); + break; case WMA_INIT_THERMAL_INFO_CMD: wma_process_init_thermal_info(wma_handle, (t_thermal_mgmt *) msg->bodyptr);