From 22c05ef081d65a90f3612fbf42087579b0b10dfd Mon Sep 17 00:00:00 2001 From: Srinivas Girigowda Date: Mon, 13 Dec 2021 21:21:07 -0800 Subject: [PATCH] qcacld-3.0: Add support for TWT get_status In TWT component, add support for TWT get_status command i.e when host wants to query current status of TWT sessions. Change-Id: Ib43009e5f6a90c589db25f78e1ca43563f2950fe CRs-Fixed: 3085483 --- components/umac/twt/core/src/wlan_twt_main.c | 42 +- components/umac/twt/core/src/wlan_twt_main.h | 22 + .../dispatcher/inc/wlan_twt_ucfg_ext_api.h | 42 +- .../dispatcher/src/wlan_twt_ucfg_ext_api.c | 13 + core/hdd/src/wlan_hdd_twt.c | 2 +- os_if/twt/inc/osif_twt_ext_req.h | 17 + os_if/twt/src/osif_twt_ext_req.c | 478 ++++++++++++++++++ 7 files changed, 613 insertions(+), 3 deletions(-) diff --git a/components/umac/twt/core/src/wlan_twt_main.c b/components/umac/twt/core/src/wlan_twt_main.c index 918f745e52..b0e3ca27d9 100644 --- a/components/umac/twt/core/src/wlan_twt_main.c +++ b/components/umac/twt/core/src/wlan_twt_main.c @@ -804,7 +804,6 @@ end: * * Return: Return true if TWT session exists for given dialog ID. */ -static bool wlan_twt_is_setup_done(struct wlan_objmgr_psoc *psoc, struct qdf_mac_addr *peer_mac, uint8_t dialog_id) { @@ -1602,6 +1601,47 @@ wlan_twt_set_session_state(struct wlan_objmgr_psoc *psoc, wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); } +enum wlan_twt_session_state +wlan_twt_get_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + struct wlan_objmgr_peer *peer; + struct twt_peer_priv_obj *peer_priv; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + + if (!peer) { + twt_err("Peer object not found"); + return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err(" peer twt component object is NULL"); + return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + if (peer_priv->session_info[i].dialog_id == dialog_id && + dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) { + qdf_mutex_release(&peer_priv->twt_peer_lock); + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + return peer_priv->session_info[i].state; + } + } + + qdf_mutex_release(&peer_priv->twt_peer_lock); + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + + return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; +} + /** * wlan_twt_process_renego_failure() - Process TWT re-negotiation failure * @psoc: psoc diff --git a/components/umac/twt/core/src/wlan_twt_main.h b/components/umac/twt/core/src/wlan_twt_main.h index 6de0866ec0..19a351436f 100644 --- a/components/umac/twt/core/src/wlan_twt_main.h +++ b/components/umac/twt/core/src/wlan_twt_main.h @@ -239,3 +239,25 @@ wlan_twt_init_context(struct wlan_objmgr_psoc *psoc, */ QDF_STATUS wlan_twt_update_beacon_template(void); +/** + * wlan_twt_is_setup_done() - Check if TWT setup exists for a given dialog id + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * + * Return: true if TWT setup exists, false otherwise + */ +bool wlan_twt_is_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id); + +/** + * wlan_twt_get_session_state() - Get TWT session state + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * + * Return: enum wlan_twt_session_state + */ +enum wlan_twt_session_state +wlan_twt_get_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id); diff --git a/components/umac/twt/dispatcher/inc/wlan_twt_ucfg_ext_api.h b/components/umac/twt/dispatcher/inc/wlan_twt_ucfg_ext_api.h index c15f1f3f61..463049e6bb 100644 --- a/components/umac/twt/dispatcher/inc/wlan_twt_ucfg_ext_api.h +++ b/components/umac/twt/dispatcher/inc/wlan_twt_ucfg_ext_api.h @@ -226,6 +226,32 @@ ucfg_twt_set_osif_cb(osif_twt_get_global_ops_cb osif_twt_ops); * Return: QDF_STATUS_SUCCESS */ QDF_STATUS ucfg_twt_update_beacon_template(void); + +/** + * ucfg_twt_is_setup_done() - check if TWT setup is done or not + * for given dialog id + * @psoc: Pointer to global psoc object + * @peer_mac: Global peer mac address + * @dialog_id: Dialog ID + * + * Return: True if Setup is done, false otherwise + */ +bool +ucfg_twt_is_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id); + +/** + * ucfg_twt_get_session_state() - get TWT session state for a given dialog id + * @psoc: Pointer to global psoc object + * @peer_mac: Global peer mac address + * @dialog_id: Dialog ID + * + * Return: TWT session state + */ +enum wlan_twt_session_state +ucfg_twt_get_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id); #else static inline QDF_STATUS ucfg_twt_psoc_open(struct wlan_objmgr_psoc *psoc) @@ -290,6 +316,20 @@ ucfg_twt_set_osif_cb(osif_twt_get_global_ops_cb osif_twt_ops) { return QDF_STATUS_E_NOSUPPORT; } -#endif +static inline bool +ucfg_twt_is_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return false; +} + +static inline enum wlan_twt_session_state +ucfg_twt_get_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; +} +#endif #endif diff --git a/components/umac/twt/dispatcher/src/wlan_twt_ucfg_ext_api.c b/components/umac/twt/dispatcher/src/wlan_twt_ucfg_ext_api.c index fc7c1b067f..b0286977d9 100644 --- a/components/umac/twt/dispatcher/src/wlan_twt_ucfg_ext_api.c +++ b/components/umac/twt/dispatcher/src/wlan_twt_ucfg_ext_api.c @@ -170,3 +170,16 @@ QDF_STATUS ucfg_twt_update_beacon_template(void) return wlan_twt_update_beacon_template(); } +bool +ucfg_twt_is_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + return wlan_twt_is_setup_done(psoc, peer_mac, dialog_id); +} + +enum wlan_twt_session_state +ucfg_twt_get_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + return wlan_twt_get_session_state(psoc, peer_mac, dialog_id); +} diff --git a/core/hdd/src/wlan_hdd_twt.c b/core/hdd/src/wlan_hdd_twt.c index 8f13c8bde5..12f6655eb5 100644 --- a/core/hdd/src/wlan_hdd_twt.c +++ b/core/hdd/src/wlan_hdd_twt.c @@ -231,6 +231,7 @@ static int hdd_twt_configure(struct hdd_adapter *adapter, ret = osif_twt_setup_req(vdev, twt_param_attr); break; case QCA_WLAN_TWT_GET: + ret = osif_twt_get_session_req(vdev, twt_param_attr); break; case QCA_WLAN_TWT_TERMINATE: ret = hdd_twt_terminate_session(adapter, vdev, twt_param_attr); @@ -1062,7 +1063,6 @@ hdd_twt_get_peer_session_params(struct hdd_context *hdd_ctx, if (!hdd_ctx || !params) return qdf_status; - num_twt_session = ucfg_twt_get_peer_session_params(hdd_ctx->psoc, params); if (num_twt_session) diff --git a/os_if/twt/inc/osif_twt_ext_req.h b/os_if/twt/inc/osif_twt_ext_req.h index afe896c98a..b3c75f80e1 100644 --- a/os_if/twt/inc/osif_twt_ext_req.h +++ b/os_if/twt/inc/osif_twt_ext_req.h @@ -175,6 +175,16 @@ osif_twt_send_get_capabilities_response(struct wlan_objmgr_psoc *psoc, * Return: errno */ int osif_fill_peer_macaddr(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr); + +/** + * osif_twt_get_session_req() - Extract get TWT NL attributes + * @vdev: vdev pointer + * @twt_param_attr: TWT NL attributes coming from the user space + * + * Return: errno + */ +int osif_twt_get_session_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr); #else static inline int osif_twt_setup_req(struct wlan_objmgr_vdev *vdev, @@ -224,6 +234,13 @@ int osif_twt_nudge_req(struct wlan_objmgr_vdev *vdev, return 0; } +static inline +int osif_twt_get_session_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + return 0; +} + #endif #endif /* _OSIF_TWT_EXT_REQ_H_ */ diff --git a/os_if/twt/src/osif_twt_ext_req.c b/os_if/twt/src/osif_twt_ext_req.c index 7fc2e312ed..67b48ab6b5 100644 --- a/os_if/twt/src/osif_twt_ext_req.c +++ b/os_if/twt/src/osif_twt_ext_req.c @@ -30,6 +30,10 @@ #include #include #include +#include +#include "wlan_cp_stats_mc_ucfg_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_cp_stats_ucfg_api.h" #define TWT_ACK_COMPLETE_TIMEOUT 1000 @@ -1477,3 +1481,477 @@ int osif_twt_nudge_req(struct wlan_objmgr_vdev *vdev, return osif_send_twt_nudge_req(vdev, psoc, ¶ms); } + +static uint32_t +osif_twt_get_params_resp_len(struct twt_session_stats_info *params) +{ + uint32_t len = nla_total_size(0); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR */ + len += nla_total_size(QDF_MAC_ADDR_SIZE); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA */ + len += nla_total_size(sizeof(u32)); + + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP*/ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF */ + len += nla_total_size(sizeof(u64)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE */ + if (params->pm_responder_bit_valid) + len += nla_total_size(sizeof(u8)); + + return len; +} + +static enum qca_wlan_twt_setup_state +osif_get_converted_twt_state(enum wlan_twt_session_state state) +{ + switch (state) { + case WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED: + return QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; + case WLAN_TWT_SETUP_STATE_ACTIVE: + return QCA_WLAN_TWT_SETUP_STATE_ACTIVE; + case WLAN_TWT_SETUP_STATE_SUSPEND: + return QCA_WLAN_TWT_SETUP_STATE_SUSPEND; + default: + return QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; + } +} + +static QDF_STATUS +osif_twt_pack_get_params_resp_nlmsg(struct wlan_objmgr_psoc *psoc, + struct sk_buff *reply_skb, + struct twt_session_stats_info *params, + int num_twt_session) +{ + struct nlattr *config_attr, *nla_params; + enum wlan_twt_session_state state; + enum qca_wlan_twt_setup_state converted_state; + uint64_t tsf_val; + uint32_t wake_duration; + uint32_t wake_intvl_mantis_us, wake_intvl_mantis_tu; + int i, attr; + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + osif_err("TWT: get_params nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + for (i = 0; i < num_twt_session; i++) { + if (params[i].event_type != HOST_TWT_SESSION_SETUP && + params[i].event_type != HOST_TWT_SESSION_UPDATE) + continue; + + nla_params = nla_nest_start(reply_skb, i); + if (!nla_params) { + osif_err("TWT: get_params nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + params[i].peer_mac.bytes)) { + osif_err("TWT: get_params failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + + osif_debug("TWT: get_params peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params[i].peer_mac.bytes)); + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (nla_put_u8(reply_skb, attr, params[i].dialog_id)) { + osif_err("TWT: get_params failed to put dialog_id"); + return QDF_STATUS_E_INVAL; + } + + if (params[i].bcast) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST; + if (nla_put_flag(reply_skb, attr)) { + osif_err("TWT: get_params fail to put bcast"); + return QDF_STATUS_E_INVAL; + } + } + + if (params[i].trig) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER; + if (nla_put_flag(reply_skb, attr)) { + osif_err("TWT: get_params fail to put Trigger"); + return QDF_STATUS_E_INVAL; + } + } + + if (params[i].announ) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE; + if (nla_put_flag(reply_skb, attr)) { + osif_err("TWT: get_params fail to put Announce"); + return QDF_STATUS_E_INVAL; + } + } + + if (params[i].protection) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION; + if (nla_put_flag(reply_skb, attr)) { + osif_err("TWT: get_params fail to put Protect"); + return QDF_STATUS_E_INVAL; + } + } + + if (params[i].pm_responder_bit_valid) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE; + if (nla_put_u8(reply_skb, attr, + params[i].pm_responder_bit)) { + osif_err("TWT: fail to put pm responder mode"); + return QDF_STATUS_E_INVAL; + } + } + + if (!params[i].info_frame_disabled) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED; + if (nla_put_flag(reply_skb, attr)) { + osif_err("TWT: get_params put Info Enable fail"); + return QDF_STATUS_E_INVAL; + } + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION; + wake_duration = (params[i].wake_dura_us / + TWT_WAKE_DURATION_MULTIPLICATION_FACTOR); + if (nla_put_u32(reply_skb, attr, wake_duration)) { + osif_err("TWT: get_params failed to put Wake duration"); + return QDF_STATUS_E_INVAL; + } + + wake_intvl_mantis_us = params[i].wake_intvl_us; + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA; + if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_us)) { + osif_err("TWT: get_params failed to put Wake Interval in us"); + return QDF_STATUS_E_INVAL; + } + + wake_intvl_mantis_tu = params[i].wake_intvl_us / + TWT_WAKE_INTVL_MULTIPLICATION_FACTOR; + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA; + if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_tu)) { + osif_err("TWT: get_params failed to put Wake Interval"); + return QDF_STATUS_E_INVAL; + } + + osif_debug("TWT: Send mantissa_us:%d, mantissa_tu:%d to userspace", + wake_intvl_mantis_us, wake_intvl_mantis_tu); + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP; + if (nla_put_u8(reply_skb, attr, 0)) { + osif_err("TWT: get_params put Wake Interval Exp failed"); + return QDF_STATUS_E_INVAL; + } + + tsf_val = ((uint64_t)params[i].sp_tsf_us_hi << 32) | + params[i].sp_tsf_us_lo; + osif_debug("TWT: get_params dialog_id %d TSF = 0x%llx", + params[i].dialog_id, tsf_val); + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF; + if (wlan_cfg80211_nla_put_u64(reply_skb, attr, tsf_val)) { + osif_err("TWT: get_params failed to put TSF Value"); + return QDF_STATUS_E_INVAL; + } + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE; + state = ucfg_twt_get_session_state(psoc, + ¶ms[i].peer_mac, + params[i].dialog_id); + converted_state = osif_get_converted_twt_state(state); + if (nla_put_u32(reply_skb, attr, converted_state)) { + osif_err("TWT: get_params failed to put TWT state"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, nla_params); + } + nla_nest_end(reply_skb, config_attr); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +osif_twt_send_get_params_resp(struct wlan_objmgr_vdev *vdev, + struct twt_session_stats_info *params, + int num_twt_session) +{ + struct wlan_objmgr_psoc *psoc; + struct vdev_osif_priv *osif_priv; + struct sk_buff *reply_skb; + uint32_t skb_len = NLMSG_HDRLEN, i; + QDF_STATUS qdf_status; + struct wireless_dev *wdev; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return QDF_STATUS_E_INVAL; + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + return QDF_STATUS_E_INVAL; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + return QDF_STATUS_E_INVAL; + } + /* Length of attribute QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS */ + skb_len += NLA_HDRLEN; + + /* Length of twt session parameters */ + for (i = 0; i < num_twt_session; i++) { + if (params[i].event_type == HOST_TWT_SESSION_SETUP || + params[i].event_type == HOST_TWT_SESSION_UPDATE) + skb_len += osif_twt_get_params_resp_len(params + i); + } + + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wdev->wiphy, + skb_len); + if (!reply_skb) { + osif_err("TWT: get_params alloc reply skb failed"); + return QDF_STATUS_E_NOMEM; + } + + qdf_status = osif_twt_pack_get_params_resp_nlmsg(psoc, reply_skb, + params, + num_twt_session); + if (QDF_IS_STATUS_ERROR(qdf_status)) + goto fail; + + if (cfg80211_vendor_cmd_reply(reply_skb)) + qdf_status = QDF_STATUS_E_INVAL; + + return qdf_status; +fail: + kfree_skb(reply_skb); + return qdf_status; +} + +static QDF_STATUS +osif_twt_get_peer_session_params(struct wlan_objmgr_vdev *vdev, + struct twt_session_stats_info *params) +{ + struct wlan_objmgr_psoc *psoc; + int num_twt_session = 0; + QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; + + psoc = wlan_vdev_get_psoc(vdev); + + if (!psoc) + return qdf_status; + + num_twt_session = ucfg_cp_stats_twt_get_peer_session_params(psoc, + params); + + if (num_twt_session) + qdf_status = osif_twt_send_get_params_resp(vdev, params, + num_twt_session); + + return qdf_status; +} + +static QDF_STATUS +osif_send_inactive_session_reply(struct wlan_objmgr_vdev *vdev, + struct twt_session_stats_info *params) +{ + QDF_STATUS qdf_status; + int num_twt_session = 0; + + params[num_twt_session].event_type = HOST_TWT_SESSION_UPDATE; + num_twt_session++; + + qdf_status = osif_twt_send_get_params_resp(vdev, params, + num_twt_session); + + return qdf_status; +} + +static int +osif_twt_sap_get_session_params(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + struct wlan_objmgr_psoc *psoc; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + uint16_t num_peer; + struct twt_session_stats_info *params; + int ret, id, id1; + QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; + uint8_t vdev_id; + + ret = wlan_cfg80211_nla_parse_nested( + tb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + twt_param_attr, + qca_wlan_vendor_twt_add_dialog_policy); + + if (ret) + return ret; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return -EINVAL; + + num_peer = wlan_vdev_get_peer_count(vdev); + params = qdf_mem_malloc(TWT_PEER_MAX_SESSIONS * num_peer * + sizeof(*params)); + + if (!params) + return -ENOMEM; + + vdev_id = wlan_vdev_get_id(vdev); + params[0].vdev_id = vdev_id; + id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + id1 = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR; + + if (!tb[id] || !tb[id1]) { + osif_err_rl("TWT: get_params dialog_id or mac_addr is missing"); + goto done; + } + + params[0].dialog_id = nla_get_u8(tb[id]); + nla_memcpy(params[0].peer_mac.bytes, tb[id1], QDF_MAC_ADDR_SIZE); + + if (qdf_is_macaddr_broadcast(¶ms[0].peer_mac) && + params[0].dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) { + osif_err_rl("Bcast MAC valid with dlg_id:%d but here dlg_id is:%d", + TWT_ALL_SESSIONS_DIALOG_ID, params[0].dialog_id); + goto done; + } + + if (!params[0].dialog_id) + params[0].dialog_id = TWT_ALL_SESSIONS_DIALOG_ID; + + osif_debug("TWT: get_params dialog_id %d and mac_addr "QDF_MAC_ADDR_FMT, + params[0].dialog_id, + QDF_MAC_ADDR_REF(params[0].peer_mac.bytes)); + qdf_status = osif_twt_get_peer_session_params(vdev, params); + +done: + qdf_mem_free(params); + return qdf_status_to_os_return(qdf_status); +} + +static int +osif_twt_sta_get_session_params(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + struct wlan_objmgr_psoc *psoc; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + struct twt_session_stats_info + params[TWT_PSOC_MAX_SESSIONS] = { {0} }; + int ret, id; + QDF_STATUS qdf_status; + struct qdf_mac_addr bcast_addr = QDF_MAC_ADDR_BCAST_INIT; + struct qdf_mac_addr peer_mac; + uint8_t vdev_id; + + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + twt_param_attr, + qca_wlan_vendor_twt_add_dialog_policy); + if (ret) + return ret; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return -EINVAL; + + vdev_id = wlan_vdev_get_id(vdev); + params[0].vdev_id = vdev_id; + + /* + * Currently twt_get_params nl cmd is sending only dialog_id(STA), fill + * mac_addr of STA in params and call osif_twt_get_peer_session_params. + * When twt_get_params passes mac_addr and dialog_id of STA/SAP, update + * both mac_addr and dialog_id in params before calling + * osif_twt_get_peer_session_params. dialog_id if not received, + * dialog_id of value 0 will be used as default. + */ + + id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (tb[id]) + params[0].dialog_id = (uint32_t)nla_get_u8(tb[id]); + else + params[0].dialog_id = 0; + + if (osif_fill_peer_macaddr(vdev, peer_mac.bytes)) + return -EINVAL; + + if (params[0].dialog_id <= TWT_MAX_DIALOG_ID) { + qdf_copy_macaddr(¶ms[0].peer_mac, &peer_mac); + osif_debug("TWT: get_params peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params[0].peer_mac.bytes)); + } else { + qdf_copy_macaddr(¶ms[0].peer_mac, &bcast_addr); + } + + if (!ucfg_twt_is_setup_done(psoc, ¶ms[0].peer_mac, + params[0].dialog_id)) { + osif_debug("vdev%d: TWT session %d setup incomplete", vdev_id, + params[0].dialog_id); + qdf_status = osif_send_inactive_session_reply(vdev, params); + return qdf_status_to_os_return(qdf_status); + } + + osif_debug("TWT: get_params dialog_id %d and mac_addr "QDF_MAC_ADDR_FMT, + params[0].dialog_id, + QDF_MAC_ADDR_REF(params[0].peer_mac.bytes)); + + qdf_status = osif_twt_get_peer_session_params(vdev, params); + + return qdf_status_to_os_return(qdf_status); +} + +int osif_twt_get_session_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + enum QDF_OPMODE device_mode; + + device_mode = wlan_vdev_mlme_get_opmode(vdev); + + switch (device_mode) { + case QDF_STA_MODE: + return osif_twt_sta_get_session_params(vdev, twt_param_attr); + case QDF_SAP_MODE: + return osif_twt_sap_get_session_params(vdev, twt_param_attr); + default: + osif_err_rl("TWT get session params is not supported on %s", + qdf_opmode_str(device_mode)); + } + + return -EOPNOTSUPP; +}