1 /* 2 * Copyright (c) 2018 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: implementation of the driver FTM functions interfacing with linux kernel 21 */ 22 23 #include <net/cfg80211.h> 24 #include <qdf_util.h> 25 #include <wlan_objmgr_pdev_obj.h> 26 #include <wlan_cfg80211.h> 27 #include <wlan_cfg80211_ftm.h> 28 #include <wlan_ftm_ucfg_api.h> 29 #include <wlan_osif_priv.h> 30 #include <qdf_types.h> 31 #include <qdf_module.h> 32 33 static const struct nla_policy 34 wlan_cfg80211_ftm_policy[WLAN_CFG80211_FTM_ATTR_MAX + 1] = { 35 [WLAN_CFG80211_FTM_ATTR_CMD] = {.type = NLA_U32}, 36 [WLAN_CFG80211_FTM_ATTR_DATA] = {.type = NLA_BINARY, 37 .len = WLAN_FTM_DATA_MAX_LEN}, 38 }; 39 40 static int 41 wlan_cfg80211_process_ftm_cmd(struct wlan_objmgr_pdev *pdev, 42 struct nlattr *tb[]) 43 { 44 int buf_len; 45 void *buf; 46 QDF_STATUS status; 47 48 if (!tb[WLAN_CFG80211_FTM_ATTR_DATA]) { 49 ftm_err("WLAN_CFG80211_FTM_ATTR_DATA attribute is invalid"); 50 return -EINVAL; 51 } 52 53 buf = nla_data(tb[WLAN_CFG80211_FTM_ATTR_DATA]); 54 buf_len = nla_len(tb[WLAN_CFG80211_FTM_ATTR_DATA]); 55 56 if (buf_len > WLAN_FTM_DATA_MAX_LEN) 57 return -EINVAL; 58 59 ftm_debug("****FTM Tx cmd len = %d*****", buf_len); 60 61 status = ucfg_wlan_ftm_testmode_cmd(pdev, buf, buf_len); 62 63 if (QDF_IS_STATUS_ERROR(status)) 64 status = QDF_STATUS_E_BUSY; 65 66 return qdf_status_to_os_return(status); 67 } 68 69 int 70 wlan_cfg80211_ftm_testmode_cmd(struct wlan_objmgr_pdev *pdev, 71 void *data, uint32_t len) 72 { 73 struct nlattr *tb[WLAN_CFG80211_FTM_ATTR_MAX + 1]; 74 int err = 0, cmd; 75 struct wifi_ftm_pdev_priv_obj *ftm_pdev_obj; 76 77 ftm_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev, 78 WLAN_UMAC_COMP_FTM); 79 if (!ftm_pdev_obj) { 80 ftm_err("Failed to get ftm pdev component"); 81 return -EINVAL; 82 } 83 84 ftm_pdev_obj->cmd_type = WIFI_FTM_CMD_NL80211; 85 86 err = wlan_cfg80211_nla_parse(tb, WLAN_CFG80211_FTM_ATTR_MAX - 1, data, 87 len, wlan_cfg80211_ftm_policy); 88 if (err) { 89 ftm_err("Testmode INV ATTR"); 90 return err; 91 } 92 93 if (!tb[WLAN_CFG80211_FTM_ATTR_CMD]) { 94 ftm_err("Testmode INV CMD"); 95 return -EINVAL; 96 } 97 cmd = nla_get_u32(tb[WLAN_CFG80211_FTM_ATTR_CMD]); 98 99 switch (cmd) { 100 case WLAN_CFG80211_FTM_CMD_WLAN_FTM: 101 err = wlan_cfg80211_process_ftm_cmd(pdev, tb); 102 break; 103 104 default: 105 ftm_err("unknown command: %d", cmd); 106 return -ENOENT; 107 } 108 109 return err; 110 } 111 112 qdf_export_symbol(wlan_cfg80211_ftm_testmode_cmd); 113 114 QDF_STATUS 115 wlan_cfg80211_ftm_rx_event(struct wlan_objmgr_pdev *pdev, 116 uint8_t *data, uint32_t len) 117 { 118 struct pdev_osif_priv *pdev_ospriv; 119 qdf_nbuf_t skb = NULL; 120 121 if (!data || !len) { 122 ftm_err("Null data or invalid length"); 123 return QDF_STATUS_E_INVAL; 124 } 125 126 pdev_ospriv = wlan_pdev_get_ospriv(pdev); 127 if (!pdev_ospriv) { 128 ftm_err("pdev_ospriv is NULL"); 129 return QDF_STATUS_E_INVAL; 130 } 131 132 ftm_debug("Testmode response event generated"); 133 #ifdef CONFIG_NL80211_TESTMODE 134 skb = cfg80211_testmode_alloc_event_skb(pdev_ospriv->wiphy, 135 len, GFP_ATOMIC); 136 #else 137 return QDF_STATUS_E_INVAL; 138 #endif 139 if (!skb) 140 return QDF_STATUS_E_NOMEM; 141 142 if (nla_put_u32(skb, WLAN_CFG80211_FTM_ATTR_CMD, 143 WLAN_CFG80211_FTM_CMD_WLAN_FTM) || 144 nla_put(skb, WLAN_CFG80211_FTM_ATTR_DATA, len, data)) { 145 goto nla_put_failure; 146 } 147 #ifdef CONFIG_NL80211_TESTMODE 148 cfg80211_testmode_event(skb, GFP_ATOMIC); 149 #endif 150 return QDF_STATUS_SUCCESS; 151 152 nla_put_failure: 153 qdf_nbuf_free(skb); 154 ftm_err("nla_put failed on testmode rx skb!"); 155 156 return QDF_STATUS_E_INVAL; 157 } 158