qcacld-3.0: Add support for NDP data initiator request
qcacld-2.0 to qcacld-3.0 propagation
Add host side changes to handle INITIATOR_REQ, INITIATOR_RSP,
NEW_PEER_IND and NDP_CONFIRM_IND to support NDP data initiator
request.
Change-Id: I10bf88d3fff27e1f842b720a598c923983c06c90
CRs-Fixed: 962367
diff --git a/core/hdd/src/wlan_hdd_nan_datapath.c b/core/hdd/src/wlan_hdd_nan_datapath.c
index 8e4e08c..0278f19 100644
--- a/core/hdd/src/wlan_hdd_nan_datapath.c
+++ b/core/hdd/src/wlan_hdd_nan_datapath.c
@@ -31,6 +31,8 @@
#include "wlan_hdd_includes.h"
#include "wlan_hdd_p2p.h"
#include "wma_api.h"
+#include "wlan_hdd_assoc.h"
+#include "sme_nan_datapath.h"
/* NLA policy */
static const struct nla_policy
@@ -39,8 +41,8 @@
[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID] = { .type = NLA_U16 },
[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR] = { .type = NLA_STRING,
.len = IFNAMSIZ },
- [QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID] = { .type = NLA_U32 },
- [QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_SPEC_CHANNEL] = { .type = NLA_U32 },
+ [QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID] = { .type = NLA_U16 },
+ [QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL] = { .type = NLA_U32 },
[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR] = {
.type = NLA_BINARY,
.len = QDF_MAC_ADDR_SIZE },
@@ -51,7 +53,7 @@
[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO] = { .type = NLA_BINARY,
.len = NDP_APP_INFO_LEN },
[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID] = { .type = NLA_U32 },
- [QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_RESPONSE_CODE] = { .type = NLA_U16 },
+ [QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE] = { .type = NLA_U16 },
[QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_STATUS_CODE] = { .type = NLA_U16 },
[QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR] = { .type = NLA_BINARY,
.len = QDF_MAC_ADDR_SIZE },
@@ -149,6 +151,52 @@
}
/**
+ * hdd_is_ndp_allowed() - Indicates if NDP is allowed
+ * @hdd_ctx: hdd context
+ *
+ * NDP is not allowed with any other role active except STA.
+ *
+ * Return: true if allowed, false otherwise
+ */
+static bool hdd_is_ndp_allowed(hdd_context_t *hdd_ctx)
+{
+ hdd_adapter_t *adapter;
+ hdd_station_ctx_t *sta_ctx;
+ QDF_STATUS status;
+ hdd_adapter_list_node_t *curr = NULL, *next = NULL;
+
+ status = hdd_get_front_adapter(hdd_ctx, &curr);
+ while (QDF_STATUS_SUCCESS == status) {
+ adapter = curr->pAdapter;
+ if (!adapter)
+ goto next_adapter;
+
+ switch (adapter->device_mode) {
+ case QDF_P2P_GO_MODE:
+ case QDF_SAP_MODE:
+ if (test_bit(SOFTAP_BSS_STARTED,
+ &adapter->event_flags))
+ return false;
+ break;
+ case QDF_P2P_CLIENT_MODE:
+ case QDF_IBSS_MODE:
+ sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+ if (hdd_conn_is_connected(sta_ctx) ||
+ hdd_is_connecting(sta_ctx))
+ return false;
+ break;
+ default:
+ break;
+ }
+next_adapter:
+ status = hdd_get_next_adapter(hdd_ctx, curr, &next);
+ curr = next;
+ }
+
+ return true;
+}
+
+/**
* hdd_ndi_start_bss() - Start BSS on NAN data interface
* @adapter: adapter context
* @operating_channel: channel on which the BSS to be started
@@ -383,7 +431,6 @@
return ret;
}
-
/**
* hdd_ndp_initiator_req_handler() - NDP initiator request handler
* @hdd_ctx: hdd context
@@ -394,6 +441,114 @@
static int hdd_ndp_initiator_req_handler(hdd_context_t *hdd_ctx,
struct nlattr **tb)
{
+ hdd_adapter_t *adapter;
+ char *iface_name;
+ struct ndp_initiator_req req;
+ QDF_STATUS status;
+ uint32_t ndp_qos_cfg;
+ tHalHandle hal = hdd_ctx->hHal;
+ struct nan_datapath_ctx *ndp_ctx;
+
+ ENTER();
+
+ if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) {
+ hdd_err(FL("Interface name string is unavailable"));
+ return -EINVAL;
+ }
+
+ iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]);
+ /* Check for interface in NDI mode */
+ adapter = hdd_get_adapter(hdd_ctx, QDF_NDI_MODE);
+ if (!adapter) {
+ hdd_err(FL("NAN data interface %s not available"),
+ iface_name);
+ return -EINVAL;
+ }
+
+ /* NAN data path coexists only with STA interface */
+ if (false == hdd_is_ndp_allowed(hdd_ctx)) {
+ hdd_err(FL("Unsupported concurrency for NAN datapath"));
+ return -EPERM;
+ }
+
+ ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter);
+
+ if (ndp_ctx->state == NAN_DATA_NDI_DELETED_STATE ||
+ ndp_ctx->state == NAN_DATA_NDI_DELETING_STATE ||
+ ndp_ctx->state == NAN_DATA_NDI_CREATING_STATE) {
+ hdd_err(FL("Data request not allowed in NDI current state: %d"),
+ ndp_ctx->state);
+ return -EINVAL;
+ }
+
+ req.vdev_id = adapter->sessionId;
+
+ if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) {
+ hdd_err(FL("Transaction ID is unavailable"));
+ return -EINVAL;
+ }
+ req.transaction_id =
+ nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]);
+
+ if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL]) {
+ hdd_err(FL("NDP channel is unavailable"));
+ return -EINVAL;
+ }
+ req.channel =
+ nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL]);
+
+ if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID]) {
+ hdd_err(FL("NDP service instance ID is unavailable"));
+ return -EINVAL;
+ }
+ req.service_instance_id =
+ nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID]);
+
+ qdf_mem_copy(req.self_ndi_mac_addr.bytes,
+ adapter->macAddressCurrent.bytes, QDF_MAC_ADDR_SIZE);
+
+ if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR]) {
+ hdd_err(FL("NDI peer discovery mac addr is unavailable"));
+ return -EINVAL;
+ }
+ qdf_mem_copy(req.peer_discovery_mac_addr.bytes,
+ nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR]),
+ QDF_MAC_ADDR_SIZE);
+
+ if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO_LEN]) {
+ hdd_err(FL("NDP app info len is unavailable"));
+ return -EINVAL;
+ }
+ req.ndp_info.ndp_app_info_len =
+ nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO_LEN]);
+
+ if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]) {
+ hdd_err(FL("NDP app info is unavailable"));
+ return -EINVAL;
+ }
+ req.ndp_info.ndp_app_info =
+ nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]);
+
+ if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS]) {
+ /* at present ndp config stores 4 bytes QOS info only */
+ req.ndp_config.ndp_cfg_len = 4;
+ req.ndp_config.ndp_cfg = (uint8_t *)&ndp_qos_cfg;
+ ndp_qos_cfg =
+ nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS]);
+ }
+
+ hddLog(LOG1,
+ FL("vdev_id: %d, transaction_id: %d, channel: %d, service_instance_id: %d, ndp_app_info_len: %d, peer_discovery_mac_addr: %pM"),
+ req.vdev_id, req.transaction_id, req.channel,
+ req.service_instance_id, req.ndp_info.ndp_app_info_len,
+ req.peer_discovery_mac_addr.bytes);
+ status = sme_ndp_initiator_req_handler(hal, &req);
+ if (status != QDF_STATUS_SUCCESS) {
+ hdd_err(FL("sme_ndp_initiator_req_handler failed, status: %d"),
+ status);
+ return -ECOMM;
+ }
+ EXIT();
return 0;
}
@@ -714,12 +869,74 @@
* @adapter: pointer to adapter context
* @rsp_params: response parameters
*
+ * Following vendor event is sent to cfg80211:
+ * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD =
+ * QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_RESPONSE (4 bytes)
+ * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID (2 bytes)
+ * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID (4 bytes)
+ * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_TYPE (4 bytes)
+ * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE (4 bytes)
+ *
* Return: none
*/
static void hdd_ndp_initiator_rsp_handler(hdd_adapter_t *adapter,
void *rsp_params)
{
+ struct sk_buff *vendor_event;
+ hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+ struct ndp_initiator_rsp *rsp = rsp_params;
+ uint32_t data_len = (4 * sizeof(uint32_t)) + (1 * sizeof(uint16_t)) +
+ NLMSG_HDRLEN + (5 * NLA_HDRLEN);
+
+ ENTER();
+
+ if (!rsp) {
+ hdd_err(FL("Invalid NDP Initator response"));
+ return;
+ }
+
+ if (0 != wlan_hdd_validate_context(hdd_ctx))
+ return;
+
+ vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
+ data_len, QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX,
+ GFP_KERNEL);
+ if (!vendor_event) {
+ hdd_err(FL("cfg80211_vendor_event_alloc failed"));
+ return;
+ }
+
+ if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD,
+ QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_RESPONSE))
+ goto ndp_initiator_rsp_nla_failed;
+
+ if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID,
+ rsp->transaction_id))
+ goto ndp_initiator_rsp_nla_failed;
+
+ if (nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID,
+ rsp->ndp_instance_id))
+ goto ndp_initiator_rsp_nla_failed;
+
+ if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_TYPE,
+ rsp->status))
+ goto ndp_initiator_rsp_nla_failed;
+
+ if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE,
+ 0))
+ goto ndp_initiator_rsp_nla_failed;
+
+ hddLog(LOG1,
+ FL("NDP Initiator rsp sent, tid:%d, instance id:%d, status:%d"),
+ rsp->transaction_id, rsp->ndp_instance_id, rsp->status);
+ cfg80211_vendor_event(vendor_event, GFP_KERNEL);
+ EXIT();
return;
+ndp_initiator_rsp_nla_failed:
+ hdd_err(FL("nla_put api failed"));
+ kfree_skb(vendor_event);
+ EXIT();
}
/**
@@ -732,7 +949,41 @@
static void hdd_ndp_new_peer_ind_handler(hdd_adapter_t *adapter,
void *ind_params)
{
- return;
+ struct sme_ndp_peer_ind *new_peer_ind = ind_params;
+ hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+ tSirBssDescription tmp_bss_descp = {0};
+ tCsrRoamInfo roam_info = {0};
+ struct nan_datapath_ctx *ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter);
+ hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+
+ ENTER();
+
+ if (NULL == ind_params) {
+ hdd_err(FL("Invalid new NDP peer params"));
+ return;
+ }
+
+ /* save peer in ndp ctx */
+ if (false == hdd_save_peer(sta_ctx, new_peer_ind->sta_id,
+ &new_peer_ind->peer_mac_addr)) {
+ hdd_err(FL("Ndp peer table full. cannot save new peer"));
+ return;
+ }
+
+ /* this function is called for each new peer */
+ ndp_ctx->active_ndp_peers++;
+ hdd_roam_register_sta(adapter, &roam_info, new_peer_ind->sta_id,
+ &new_peer_ind->peer_mac_addr, &tmp_bss_descp);
+ hdd_ctx->sta_to_adapter[new_peer_ind->sta_id] = adapter;
+ /* perform following steps for first new peer ind */
+ if (ndp_ctx->active_ndp_peers == 1) {
+ hddLog(LOG1, FL("Set ctx connection state to connected"));
+ sta_ctx->conn_info.connState = eConnectionState_NdiConnected;
+ hdd_wmm_connect(adapter, &roam_info, eCSR_BSS_TYPE_NDI);
+ netif_carrier_on(adapter->dev);
+ netif_tx_start_all_queues(adapter->dev);
+ }
+ EXIT();
}
/**
@@ -753,12 +1004,109 @@
* @adapter: pointer to adapter context
* @ind_params: indication parameters
*
+ * Following vendor event is sent to cfg80211:
+ * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD =
+ * QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND (4 bytes)
+ * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID (4 bytes)
+ * QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR (6 bytes)
+ * QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR (IFNAMSIZ)
+ * QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO (ndp_app_info_len size)
+ * QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE (4 bytes)
+ * QCA_WLAN_VENDOR_ATTR_NDP_RETURN_VALUE (4 bytes)
+ *
* Return: none
*/
static void hdd_ndp_confirm_ind_handler(hdd_adapter_t *adapter,
void *ind_params)
{
+ uint32_t ndp_qos_config = 0;
+ struct ndp_confirm_event *ndp_confirm = ind_params;
+ struct sk_buff *vendor_event;
+ hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+ struct nan_datapath_ctx *ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter);
+ uint32_t data_len;
+
+ ENTER();
+ if (!ndp_confirm) {
+ hdd_err(FL("Invalid NDP Initator response"));
+ return;
+ }
+
+ if (0 != wlan_hdd_validate_context(hdd_ctx))
+ return;
+
+ /* ndp_confirm is called each time user generated npd req succeeds */
+ ndp_ctx->active_ndp_sessions++;
+
+ data_len = (4 * sizeof(uint32_t)) + QDF_MAC_ADDR_SIZE + IFNAMSIZ +
+ sizeof(uint16_t) + NLMSG_HDRLEN + (8 * NLA_HDRLEN) +
+ ndp_confirm->ndp_info.ndp_app_info_len;
+
+ vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
+ data_len, QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX,
+ GFP_KERNEL);
+ if (!vendor_event) {
+ hdd_err(FL("cfg80211_vendor_event_alloc failed"));
+ return;
+ }
+
+ if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD,
+ QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND))
+ goto ndp_confirm_nla_failed;
+
+ if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID,
+ ndp_confirm->ndp_instance_id))
+ goto ndp_confirm_nla_failed;
+
+ if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR,
+ QDF_MAC_ADDR_SIZE, ndp_confirm->peer_ndi_mac_addr.bytes))
+ goto ndp_confirm_nla_failed;
+
+ if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR,
+ IFNAMSIZ, adapter->dev->name))
+ goto ndp_confirm_nla_failed;
+
+ if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO_LEN,
+ ndp_confirm->ndp_info.ndp_app_info_len))
+ goto ndp_confirm_nla_failed;
+
+ if (ndp_confirm->ndp_info.ndp_app_info_len && nla_put(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO,
+ ndp_confirm->ndp_info.ndp_app_info_len,
+ ndp_confirm->ndp_info.ndp_app_info))
+ goto ndp_confirm_nla_failed;
+
+ if (ndp_confirm->ndp_config.ndp_cfg_len) {
+ ndp_qos_config = *((uint32_t *)ndp_confirm->ndp_config.ndp_cfg);
+ /* at present ndp config stores 4 bytes QOS info only */
+ if (nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS,
+ ndp_qos_config))
+ goto ndp_confirm_nla_failed;
+ }
+
+ if (nla_put_u32(vendor_event,
+ QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE,
+ ndp_confirm->rsp_code))
+ goto ndp_confirm_nla_failed;
+
+ cfg80211_vendor_event(vendor_event, GFP_KERNEL);
+ hddLog(LOG1,
+ FL("NDP confim sent, ndp instance id: %d, peer addr: %pM, ndp_cfg: %d, rsp_code: %d"),
+ ndp_confirm->ndp_instance_id,
+ ndp_confirm->peer_ndi_mac_addr.bytes,
+ ndp_qos_config, ndp_confirm->rsp_code);
+
+ hddLog(LOG1, FL("NDP confim, ndp app info dump"));
+ QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG,
+ ndp_confirm->ndp_info.ndp_app_info,
+ ndp_confirm->ndp_info.ndp_app_info_len);
+ EXIT();
return;
+ndp_confirm_nla_failed:
+ hdd_err(FL("nla_put api failed"));
+ kfree_skb(vendor_event);
+ EXIT();
}
/**