Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause-Clear
0002 /*
0003  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
0004  */
0005 
0006 #include "testmode.h"
0007 #include <net/netlink.h>
0008 #include "debug.h"
0009 #include "wmi.h"
0010 #include "hw.h"
0011 #include "core.h"
0012 #include "testmode_i.h"
0013 
0014 static const struct nla_policy ath11k_tm_policy[ATH11K_TM_ATTR_MAX + 1] = {
0015     [ATH11K_TM_ATTR_CMD]        = { .type = NLA_U32 },
0016     [ATH11K_TM_ATTR_DATA]       = { .type = NLA_BINARY,
0017                         .len = ATH11K_TM_DATA_MAX_LEN },
0018     [ATH11K_TM_ATTR_WMI_CMDID]  = { .type = NLA_U32 },
0019     [ATH11K_TM_ATTR_VERSION_MAJOR]  = { .type = NLA_U32 },
0020     [ATH11K_TM_ATTR_VERSION_MINOR]  = { .type = NLA_U32 },
0021 };
0022 
0023 /* Returns true if callee consumes the skb and the skb should be discarded.
0024  * Returns false if skb is not used. Does not sleep.
0025  */
0026 bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id, struct sk_buff *skb)
0027 {
0028     struct sk_buff *nl_skb;
0029     bool consumed;
0030     int ret;
0031 
0032     ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
0033            "testmode event wmi cmd_id %d skb %pK skb->len %d\n",
0034            cmd_id, skb, skb->len);
0035 
0036     ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
0037 
0038     spin_lock_bh(&ar->data_lock);
0039 
0040     consumed = true;
0041 
0042     nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
0043                            2 * sizeof(u32) + skb->len,
0044                            GFP_ATOMIC);
0045     if (!nl_skb) {
0046         ath11k_warn(ar->ab,
0047                 "failed to allocate skb for testmode wmi event\n");
0048         goto out;
0049     }
0050 
0051     ret = nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD, ATH11K_TM_CMD_WMI);
0052     if (ret) {
0053         ath11k_warn(ar->ab,
0054                 "failed to put testmode wmi event cmd attribute: %d\n",
0055                 ret);
0056         kfree_skb(nl_skb);
0057         goto out;
0058     }
0059 
0060     ret = nla_put_u32(nl_skb, ATH11K_TM_ATTR_WMI_CMDID, cmd_id);
0061     if (ret) {
0062         ath11k_warn(ar->ab,
0063                 "failed to put testmode wmi even cmd_id: %d\n",
0064                 ret);
0065         kfree_skb(nl_skb);
0066         goto out;
0067     }
0068 
0069     ret = nla_put(nl_skb, ATH11K_TM_ATTR_DATA, skb->len, skb->data);
0070     if (ret) {
0071         ath11k_warn(ar->ab,
0072                 "failed to copy skb to testmode wmi event: %d\n",
0073                 ret);
0074         kfree_skb(nl_skb);
0075         goto out;
0076     }
0077 
0078     cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
0079 
0080 out:
0081     spin_unlock_bh(&ar->data_lock);
0082 
0083     return consumed;
0084 }
0085 
0086 static int ath11k_tm_cmd_get_version(struct ath11k *ar, struct nlattr *tb[])
0087 {
0088     struct sk_buff *skb;
0089     int ret;
0090 
0091     ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
0092            "testmode cmd get version_major %d version_minor %d\n",
0093            ATH11K_TESTMODE_VERSION_MAJOR,
0094            ATH11K_TESTMODE_VERSION_MINOR);
0095 
0096     skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy,
0097                         nla_total_size(sizeof(u32)));
0098     if (!skb)
0099         return -ENOMEM;
0100 
0101     ret = nla_put_u32(skb, ATH11K_TM_ATTR_VERSION_MAJOR,
0102               ATH11K_TESTMODE_VERSION_MAJOR);
0103     if (ret) {
0104         kfree_skb(skb);
0105         return ret;
0106     }
0107 
0108     ret = nla_put_u32(skb, ATH11K_TM_ATTR_VERSION_MINOR,
0109               ATH11K_TESTMODE_VERSION_MINOR);
0110     if (ret) {
0111         kfree_skb(skb);
0112         return ret;
0113     }
0114 
0115     return cfg80211_testmode_reply(skb);
0116 }
0117 
0118 static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[])
0119 {
0120     struct ath11k_pdev_wmi *wmi = ar->wmi;
0121     struct sk_buff *skb;
0122     u32 cmd_id, buf_len;
0123     int ret;
0124     void *buf;
0125 
0126     mutex_lock(&ar->conf_mutex);
0127 
0128     if (ar->state != ATH11K_STATE_ON) {
0129         ret = -ENETDOWN;
0130         goto out;
0131     }
0132 
0133     if (!tb[ATH11K_TM_ATTR_DATA]) {
0134         ret = -EINVAL;
0135         goto out;
0136     }
0137 
0138     if (!tb[ATH11K_TM_ATTR_WMI_CMDID]) {
0139         ret = -EINVAL;
0140         goto out;
0141     }
0142 
0143     buf = nla_data(tb[ATH11K_TM_ATTR_DATA]);
0144     buf_len = nla_len(tb[ATH11K_TM_ATTR_DATA]);
0145     cmd_id = nla_get_u32(tb[ATH11K_TM_ATTR_WMI_CMDID]);
0146 
0147     ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
0148            "testmode cmd wmi cmd_id %d buf %pK buf_len %d\n",
0149            cmd_id, buf, buf_len);
0150 
0151     ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", buf, buf_len);
0152 
0153     skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, buf_len);
0154     if (!skb) {
0155         ret = -ENOMEM;
0156         goto out;
0157     }
0158 
0159     memcpy(skb->data, buf, buf_len);
0160 
0161     ret = ath11k_wmi_cmd_send(wmi, skb, cmd_id);
0162     if (ret) {
0163         dev_kfree_skb(skb);
0164         ath11k_warn(ar->ab, "failed to transmit wmi command (testmode): %d\n",
0165                 ret);
0166         goto out;
0167     }
0168 
0169     ret = 0;
0170 
0171 out:
0172     mutex_unlock(&ar->conf_mutex);
0173     return ret;
0174 }
0175 
0176 int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
0177           void *data, int len)
0178 {
0179     struct ath11k *ar = hw->priv;
0180     struct nlattr *tb[ATH11K_TM_ATTR_MAX + 1];
0181     int ret;
0182 
0183     ret = nla_parse(tb, ATH11K_TM_ATTR_MAX, data, len, ath11k_tm_policy,
0184             NULL);
0185     if (ret)
0186         return ret;
0187 
0188     if (!tb[ATH11K_TM_ATTR_CMD])
0189         return -EINVAL;
0190 
0191     switch (nla_get_u32(tb[ATH11K_TM_ATTR_CMD])) {
0192     case ATH11K_TM_CMD_GET_VERSION:
0193         return ath11k_tm_cmd_get_version(ar, tb);
0194     case ATH11K_TM_CMD_WMI:
0195         return ath11k_tm_cmd_wmi(ar, tb);
0196     default:
0197         return -EOPNOTSUPP;
0198     }
0199 }