1 // SPDX-License-Identifier: BSD-3-Clause-Clear
3 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
7 #include <net/netlink.h>
12 #include "testmode_i.h"
14 static const struct nla_policy ath11k_tm_policy
[ATH11K_TM_ATTR_MAX
+ 1] = {
15 [ATH11K_TM_ATTR_CMD
] = { .type
= NLA_U32
},
16 [ATH11K_TM_ATTR_DATA
] = { .type
= NLA_BINARY
,
17 .len
= ATH11K_TM_DATA_MAX_LEN
},
18 [ATH11K_TM_ATTR_WMI_CMDID
] = { .type
= NLA_U32
},
19 [ATH11K_TM_ATTR_VERSION_MAJOR
] = { .type
= NLA_U32
},
20 [ATH11K_TM_ATTR_VERSION_MINOR
] = { .type
= NLA_U32
},
23 /* Returns true if callee consumes the skb and the skb should be discarded.
24 * Returns false if skb is not used. Does not sleep.
26 bool ath11k_tm_event_wmi(struct ath11k
*ar
, u32 cmd_id
, struct sk_buff
*skb
)
28 struct sk_buff
*nl_skb
;
32 ath11k_dbg(ar
->ab
, ATH11K_DBG_TESTMODE
,
33 "testmode event wmi cmd_id %d skb %pK skb->len %d\n",
34 cmd_id
, skb
, skb
->len
);
36 ath11k_dbg_dump(ar
->ab
, ATH11K_DBG_TESTMODE
, NULL
, "", skb
->data
, skb
->len
);
38 spin_lock_bh(&ar
->data_lock
);
42 nl_skb
= cfg80211_testmode_alloc_event_skb(ar
->hw
->wiphy
,
43 2 * sizeof(u32
) + skb
->len
,
47 "failed to allocate skb for testmode wmi event\n");
51 ret
= nla_put_u32(nl_skb
, ATH11K_TM_ATTR_CMD
, ATH11K_TM_CMD_WMI
);
54 "failed to to put testmode wmi event cmd attribute: %d\n",
60 ret
= nla_put_u32(nl_skb
, ATH11K_TM_ATTR_WMI_CMDID
, cmd_id
);
63 "failed to to put testmode wmi even cmd_id: %d\n",
69 ret
= nla_put(nl_skb
, ATH11K_TM_ATTR_DATA
, skb
->len
, skb
->data
);
72 "failed to copy skb to testmode wmi event: %d\n",
78 cfg80211_testmode_event(nl_skb
, GFP_ATOMIC
);
81 spin_unlock_bh(&ar
->data_lock
);
86 static int ath11k_tm_cmd_get_version(struct ath11k
*ar
, struct nlattr
*tb
[])
91 ath11k_dbg(ar
->ab
, ATH11K_DBG_TESTMODE
,
92 "testmode cmd get version_major %d version_minor %d\n",
93 ATH11K_TESTMODE_VERSION_MAJOR
,
94 ATH11K_TESTMODE_VERSION_MINOR
);
96 skb
= cfg80211_testmode_alloc_reply_skb(ar
->hw
->wiphy
,
97 nla_total_size(sizeof(u32
)));
101 ret
= nla_put_u32(skb
, ATH11K_TM_ATTR_VERSION_MAJOR
,
102 ATH11K_TESTMODE_VERSION_MAJOR
);
108 ret
= nla_put_u32(skb
, ATH11K_TM_ATTR_VERSION_MINOR
,
109 ATH11K_TESTMODE_VERSION_MINOR
);
115 return cfg80211_testmode_reply(skb
);
118 static int ath11k_tm_cmd_wmi(struct ath11k
*ar
, struct nlattr
*tb
[])
120 struct ath11k_pdev_wmi
*wmi
= ar
->wmi
;
126 mutex_lock(&ar
->conf_mutex
);
128 if (ar
->state
!= ATH11K_STATE_ON
) {
133 if (!tb
[ATH11K_TM_ATTR_DATA
]) {
138 if (!tb
[ATH11K_TM_ATTR_WMI_CMDID
]) {
143 buf
= nla_data(tb
[ATH11K_TM_ATTR_DATA
]);
144 buf_len
= nla_len(tb
[ATH11K_TM_ATTR_DATA
]);
145 cmd_id
= nla_get_u32(tb
[ATH11K_TM_ATTR_WMI_CMDID
]);
147 ath11k_dbg(ar
->ab
, ATH11K_DBG_TESTMODE
,
148 "testmode cmd wmi cmd_id %d buf %pK buf_len %d\n",
149 cmd_id
, buf
, buf_len
);
151 ath11k_dbg_dump(ar
->ab
, ATH11K_DBG_TESTMODE
, NULL
, "", buf
, buf_len
);
153 skb
= ath11k_wmi_alloc_skb(wmi
->wmi_ab
, buf_len
);
159 memcpy(skb
->data
, buf
, buf_len
);
161 ret
= ath11k_wmi_cmd_send(wmi
, skb
, cmd_id
);
164 ath11k_warn(ar
->ab
, "failed to transmit wmi command (testmode): %d\n",
172 mutex_unlock(&ar
->conf_mutex
);
176 int ath11k_tm_cmd(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
179 struct ath11k
*ar
= hw
->priv
;
180 struct nlattr
*tb
[ATH11K_TM_ATTR_MAX
+ 1];
183 ret
= nla_parse(tb
, ATH11K_TM_ATTR_MAX
, data
, len
, ath11k_tm_policy
,
188 if (!tb
[ATH11K_TM_ATTR_CMD
])
191 switch (nla_get_u32(tb
[ATH11K_TM_ATTR_CMD
])) {
192 case ATH11K_TM_CMD_GET_VERSION
:
193 return ath11k_tm_cmd_get_version(ar
, tb
);
194 case ATH11K_TM_CMD_WMI
:
195 return ath11k_tm_cmd_wmi(ar
, tb
);