From 1b899ef90497fb420027bb01c70028fb8967ea84 Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Wed, 6 Feb 2019 15:27:15 -0800 Subject: [PATCH] qcacld-3.0: Integrate DSC (nan) The Driver Synchronization Core (DSC) is a set of synchronization primitives for use by the driver's orchestration layer. It provides APIs for ensuring safe state transitions (including bring up and tear down) of major driver objects: a single driver, associated psocs, and their associated vdevs. As part of integrating the DSC APIs into OSIF, protect NAN datapath and NAN discovery. Change-Id: Icf24c8f7717cd1ca92616c781f06dacdd69c01f0 CRs-Fixed: 2398340 --- core/hdd/src/wlan_hdd_nan.c | 14 +- core/hdd/src/wlan_hdd_nan_datapath.c | 7 - os_if/nan/src/os_if_nan.c | 295 +++++++++++++++++++++++---- 3 files changed, 264 insertions(+), 52 deletions(-) diff --git a/core/hdd/src/wlan_hdd_nan.c b/core/hdd/src/wlan_hdd_nan.c index 5a4aaa020c83..bacf07be0fb8 100644 --- a/core/hdd/src/wlan_hdd_nan.c +++ b/core/hdd/src/wlan_hdd_nan.c @@ -157,11 +157,19 @@ int wlan_hdd_cfg80211_nan_ext_request(struct wiphy *wiphy, int data_len) { - int ret; + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; cds_ssr_protect(__func__); - ret = __wlan_hdd_cfg80211_nan_ext_request(wiphy, wdev, data, data_len); + errno = __wlan_hdd_cfg80211_nan_ext_request(wiphy, wdev, + data, data_len); cds_ssr_unprotect(__func__); - return ret; + osif_psoc_sync_op_stop(psoc_sync); + + return errno; } diff --git a/core/hdd/src/wlan_hdd_nan_datapath.c b/core/hdd/src/wlan_hdd_nan_datapath.c index febe1b521549..3160791a5be6 100644 --- a/core/hdd/src/wlan_hdd_nan_datapath.c +++ b/core/hdd/src/wlan_hdd_nan_datapath.c @@ -408,20 +408,13 @@ static int __wlan_hdd_cfg80211_process_ndp_cmd(struct wiphy *wiphy, int wlan_hdd_cfg80211_process_ndp_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) { - struct osif_psoc_sync *psoc_sync; int errno; - errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); - if (errno) - return errno; - cds_ssr_protect(__func__); errno = __wlan_hdd_cfg80211_process_ndp_cmd(wiphy, wdev, data, data_len); cds_ssr_unprotect(__func__); - osif_psoc_sync_op_stop(psoc_sync); - return errno; } diff --git a/os_if/nan/src/os_if_nan.c b/os_if/nan/src/os_if_nan.c index 85db32f1379b..055248d8bc6b 100644 --- a/os_if/nan/src/os_if_nan.c +++ b/os_if/nan/src/os_if_nan.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -20,6 +20,7 @@ * DOC: defines nan component os interface APIs */ +#include "osif_sync.h" #include "qdf_str.h" #include "qdf_trace.h" #include "qdf_types.h" @@ -168,22 +169,17 @@ vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX + 1] = { }, }; -static int os_if_nan_process_ndi_create(struct wlan_objmgr_psoc *psoc, - struct nlattr **tb) +static int __os_if_nan_process_ndi_create(struct wlan_objmgr_psoc *psoc, + char *iface_name, + struct nlattr **tb) { int ret; - char *iface_name; QDF_STATUS status; uint16_t transaction_id; struct wlan_objmgr_vdev *nan_vdev; struct nan_callbacks cb_obj; cfg80211_debug("enter"); - if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { - cfg80211_err("Interface name string is unavailable"); - return -EINVAL; - } - iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); nan_vdev = wlan_util_get_vdev_by_ifname(psoc, iface_name, WLAN_NAN_ID); if (nan_vdev) { @@ -215,6 +211,116 @@ static int os_if_nan_process_ndi_create(struct wlan_objmgr_psoc *psoc, return cb_obj.ndi_start(iface_name, transaction_id); } +static int +osif_nla_str(struct nlattr **tb, size_t attr_id, char **out_str) +{ + if (!tb || !tb[attr_id]) + return -EINVAL; + + *out_str = nla_data(tb[attr_id]); + + return 0; +} + +static int +osif_device_from_psoc(struct wlan_objmgr_psoc *psoc, struct device **out_dev) +{ + qdf_device_t qdf_dev; + + if (!psoc) + return -EINVAL; + + qdf_dev = wlan_psoc_get_qdf_dev(psoc); + if (!qdf_dev || !qdf_dev->dev) + return -EINVAL; + + *out_dev = qdf_dev->dev; + + return 0; +} + +static int osif_net_dev_from_vdev(struct wlan_objmgr_vdev *vdev, + struct net_device **out_net_dev) +{ + struct vdev_osif_priv *priv; + + if (!vdev) + return -EINVAL; + + priv = wlan_vdev_get_ospriv(vdev); + if (!priv || !priv->wdev || !priv->wdev->netdev) + return -EINVAL; + + *out_net_dev = priv->wdev->netdev; + + return 0; +} + +static int osif_net_dev_from_ifname(struct wlan_objmgr_psoc *psoc, + char *iface_name, + struct net_device **out_net_dev) +{ + struct wlan_objmgr_vdev *vdev; + struct net_device *net_dev; + int errno; + + vdev = wlan_util_get_vdev_by_ifname(psoc, iface_name, WLAN_NAN_ID); + if (!vdev) + return -EINVAL; + + errno = osif_net_dev_from_vdev(vdev, &net_dev); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + + if (errno) + return errno; + + *out_net_dev = net_dev; + + return 0; +} + +static int os_if_nan_process_ndi_create(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + struct device *dev; + struct net_device *net_dev; + struct osif_vdev_sync *vdev_sync; + char *ifname; + int errno; + + errno = osif_nla_str(tb, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, &ifname); + if (errno) + return errno; + + errno = osif_device_from_psoc(psoc, &dev); + if (errno) + return errno; + + errno = osif_vdev_sync_create_with_trans(dev, &vdev_sync); + if (errno) + return errno; + + errno = __os_if_nan_process_ndi_create(psoc, ifname, tb); + if (errno) + goto destroy_sync; + + errno = osif_net_dev_from_ifname(psoc, ifname, &net_dev); + if (errno) + goto destroy_sync; + + osif_vdev_sync_register(net_dev, vdev_sync); + osif_vdev_sync_trans_stop(vdev_sync); + + return 0; + +destroy_sync: + osif_vdev_sync_trans_stop(vdev_sync); + osif_vdev_sync_destroy(vdev_sync); + + return errno; +} + static void os_if_nan_vdev_delete_peer(struct wlan_objmgr_psoc *psoc, void *peer, void *nan_vdev) { @@ -226,24 +332,17 @@ static void os_if_nan_vdev_delete_peer(struct wlan_objmgr_psoc *psoc, } } -static int os_if_nan_process_ndi_delete(struct wlan_objmgr_psoc *psoc, - struct nlattr **tb) +static int __os_if_nan_process_ndi_delete(struct wlan_objmgr_psoc *psoc, + char *iface_name, + struct nlattr **tb) { uint8_t vdev_id; - char *iface_name; QDF_STATUS status; uint32_t num_peers; uint16_t transaction_id; struct nan_callbacks cb_obj; struct wlan_objmgr_vdev *nan_vdev = NULL; - if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { - cfg80211_err("Interface name string is unavailable"); - return -EINVAL; - } - - iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); - if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { cfg80211_err("Transaction id is unavailable"); return -EINVAL; @@ -285,6 +384,45 @@ static int os_if_nan_process_ndi_delete(struct wlan_objmgr_psoc *psoc, return cb_obj.ndi_delete(vdev_id, iface_name, transaction_id); } +static int os_if_nan_process_ndi_delete(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + struct net_device *net_dev; + struct osif_vdev_sync *vdev_sync; + char *ifname; + int errno; + + errno = osif_nla_str(tb, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, &ifname); + if (errno) + return errno; + + errno = osif_net_dev_from_ifname(psoc, ifname, &net_dev); + if (errno) + return errno; + + errno = osif_vdev_sync_trans_start_wait(net_dev, &vdev_sync); + if (errno) + return errno; + + osif_vdev_sync_unregister(net_dev); + osif_vdev_sync_wait_for_ops(vdev_sync); + + errno = __os_if_nan_process_ndi_delete(psoc, ifname, tb); + if (errno) + goto reregister; + + osif_vdev_sync_trans_stop(vdev_sync); + osif_vdev_sync_destroy(vdev_sync); + + return 0; + +reregister: + osif_vdev_sync_register(net_dev, vdev_sync); + osif_vdev_sync_trans_stop(vdev_sync); + + return errno; +} + /** * os_if_nan_parse_security_params() - parse vendor attributes for security * params. @@ -351,7 +489,7 @@ static int os_if_nan_parse_security_params(struct nlattr **tb, } /** - * os_if_nan_process_ndp_initiator_req() - NDP initiator request handler + * __os_if_nan_process_ndp_initiator_req() - NDP initiator request handler * @ctx: hdd context * @tb: parsed NL attribute list * @@ -371,22 +509,16 @@ static int os_if_nan_parse_security_params(struct nlattr **tb, * * Return: 0 on success or error code on failure */ -static int os_if_nan_process_ndp_initiator_req(struct wlan_objmgr_psoc *psoc, - struct nlattr **tb) +static int __os_if_nan_process_ndp_initiator_req(struct wlan_objmgr_psoc *psoc, + char *iface_name, + struct nlattr **tb) { int ret = 0; - char *iface_name; QDF_STATUS status; enum nan_datapath_state state; struct wlan_objmgr_vdev *nan_vdev; struct nan_datapath_initiator_req req = {0}; - if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { - cfg80211_err("Interface name string is unavailable"); - return -EINVAL; - } - - iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); nan_vdev = wlan_util_get_vdev_by_ifname(psoc, iface_name, WLAN_NAN_ID); if (!nan_vdev) { cfg80211_err("NAN data interface %s not available", iface_name); @@ -499,8 +631,35 @@ initiator_req_failed: return ret; } +static int os_if_nan_process_ndp_initiator_req(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + struct net_device *net_dev; + struct osif_vdev_sync *vdev_sync; + char *ifname; + int errno; + + errno = osif_nla_str(tb, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, &ifname); + if (errno) + return errno; + + errno = osif_net_dev_from_ifname(psoc, ifname, &net_dev); + if (errno) + return errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __os_if_nan_process_ndp_initiator_req(psoc, ifname, tb); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + /** - * os_if_nan_process_ndp_responder_req() - NDP responder request handler + * __os_if_nan_process_ndp_responder_req() - NDP responder request handler * @nan_ctx: hdd context * @tb: parsed NL attribute list * @@ -518,11 +677,11 @@ initiator_req_failed: * * Return: 0 on success or error code on failure */ -static int os_if_nan_process_ndp_responder_req(struct wlan_objmgr_psoc *psoc, - struct nlattr **tb) +static int __os_if_nan_process_ndp_responder_req(struct wlan_objmgr_psoc *psoc, + char *iface_name, + struct nlattr **tb) { int ret = 0; - char *iface_name; QDF_STATUS status; enum nan_datapath_state state; struct wlan_objmgr_vdev *nan_vdev = NULL; @@ -535,12 +694,6 @@ static int os_if_nan_process_ndp_responder_req(struct wlan_objmgr_psoc *psoc, req.ndp_rsp = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE]); if (req.ndp_rsp == NAN_DATAPATH_RESPONSE_ACCEPT) { - if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { - cfg80211_err("Interface not provided"); - return -ENODEV; - } - iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); - /* Check for an existing NAN interface */ nan_vdev = wlan_util_get_vdev_by_ifname(psoc, iface_name, WLAN_NAN_ID); @@ -662,8 +815,35 @@ responder_req_failed: } +static int os_if_nan_process_ndp_responder_req(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + struct net_device *net_dev; + struct osif_vdev_sync *vdev_sync; + char *ifname; + int errno; + + errno = osif_nla_str(tb, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, &ifname); + if (errno) + return errno; + + errno = osif_net_dev_from_ifname(psoc, ifname, &net_dev); + if (errno) + return errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __os_if_nan_process_ndp_responder_req(psoc, ifname, tb); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + /** - * os_if_nan_process_ndp_end_req() - NDP end request handler + * __os_if_nan_process_ndp_end_req() - NDP end request handler * @psoc: pointer to psoc object * * @tb: parsed NL attribute list @@ -672,8 +852,8 @@ responder_req_failed: * * Return: 0 on success or error code on failure */ -static int os_if_nan_process_ndp_end_req(struct wlan_objmgr_psoc *psoc, - struct nlattr **tb) +static int __os_if_nan_process_ndp_end_req(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) { int ret = 0; QDF_STATUS status; @@ -722,6 +902,37 @@ static int os_if_nan_process_ndp_end_req(struct wlan_objmgr_psoc *psoc, return ret; } +static int os_if_nan_process_ndp_end_req(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + struct wlan_objmgr_vdev *vdev; + struct net_device *net_dev; + struct osif_vdev_sync *vdev_sync; + int errno; + + vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(psoc, QDF_NDI_MODE, + WLAN_NAN_ID); + if (!vdev) + return -EINVAL; + + errno = osif_net_dev_from_vdev(vdev, &net_dev); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + + if (errno) + return errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __os_if_nan_process_ndp_end_req(psoc, tb); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + int os_if_nan_process_ndp_cmd(struct wlan_objmgr_psoc *psoc, const void *data, int data_len) {