blob: f5bc43b830b1f6ab60f4debf2760b8ab2c3b6350 [file] [log] [blame]
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001/*
2 * Copyright (c) 2015-2016 Quantenna Communications, Inc.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <linux/types.h>
17#include <linux/skbuff.h>
18
19#include "cfg80211.h"
20#include "core.h"
21#include "qlink.h"
22#include "qlink_util.h"
23#include "bus.h"
24#include "commands.h"
25
26static int qtnf_cmd_check_reply_header(const struct qlink_resp *resp,
27 u16 cmd_id, u8 mac_id, u8 vif_id,
28 size_t resp_size)
29{
30 if (unlikely(le16_to_cpu(resp->cmd_id) != cmd_id)) {
31 pr_warn("VIF%u.%u CMD%x: bad cmd_id in response: 0x%.4X\n",
32 mac_id, vif_id, cmd_id, le16_to_cpu(resp->cmd_id));
33 return -EINVAL;
34 }
35
36 if (unlikely(resp->macid != mac_id)) {
37 pr_warn("VIF%u.%u CMD%x: bad MAC in response: %u\n",
38 mac_id, vif_id, cmd_id, resp->macid);
39 return -EINVAL;
40 }
41
42 if (unlikely(resp->vifid != vif_id)) {
43 pr_warn("VIF%u.%u CMD%x: bad VIF in response: %u\n",
44 mac_id, vif_id, cmd_id, resp->vifid);
45 return -EINVAL;
46 }
47
48 if (unlikely(le16_to_cpu(resp->mhdr.len) < resp_size)) {
49 pr_warn("VIF%u.%u CMD%x: bad response size %u < %zu\n",
50 mac_id, vif_id, cmd_id,
51 le16_to_cpu(resp->mhdr.len), resp_size);
52 return -ENOSPC;
53 }
54
55 return 0;
56}
57
58static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus,
59 struct sk_buff *cmd_skb,
60 struct sk_buff **response_skb,
61 u16 *result_code,
62 size_t const_resp_size,
63 size_t *var_resp_size)
64{
65 struct qlink_cmd *cmd;
66 const struct qlink_resp *resp;
67 struct sk_buff *resp_skb = NULL;
68 u16 cmd_id;
69 u8 mac_id, vif_id;
70 int ret;
71
72 cmd = (struct qlink_cmd *)cmd_skb->data;
73 cmd_id = le16_to_cpu(cmd->cmd_id);
74 mac_id = cmd->macid;
75 vif_id = cmd->vifid;
76 cmd->mhdr.len = cpu_to_le16(cmd_skb->len);
77
78 if (unlikely(bus->fw_state != QTNF_FW_STATE_ACTIVE &&
79 le16_to_cpu(cmd->cmd_id) != QLINK_CMD_FW_INIT)) {
80 pr_warn("VIF%u.%u: drop cmd 0x%.4X in fw state %d\n",
81 mac_id, vif_id, le16_to_cpu(cmd->cmd_id),
82 bus->fw_state);
83 return -ENODEV;
84 }
85
86 pr_debug("VIF%u.%u cmd=0x%.4X\n", mac_id, vif_id,
87 le16_to_cpu(cmd->cmd_id));
88
89 ret = qtnf_trans_send_cmd_with_resp(bus, cmd_skb, &resp_skb);
90
91 if (unlikely(ret))
92 goto out;
93
94 resp = (const struct qlink_resp *)resp_skb->data;
95 ret = qtnf_cmd_check_reply_header(resp, cmd_id, mac_id, vif_id,
96 const_resp_size);
97
98 if (unlikely(ret))
99 goto out;
100
101 if (likely(result_code))
102 *result_code = le16_to_cpu(resp->result);
103
104 /* Return length of variable part of response */
105 if (response_skb && var_resp_size)
106 *var_resp_size = le16_to_cpu(resp->mhdr.len) - const_resp_size;
107
108out:
109 if (response_skb)
110 *response_skb = resp_skb;
111 else
112 consume_skb(resp_skb);
113
114 return ret;
115}
116
117static inline int qtnf_cmd_send(struct qtnf_bus *bus,
118 struct sk_buff *cmd_skb,
119 u16 *result_code)
120{
121 return qtnf_cmd_send_with_reply(bus, cmd_skb, NULL, result_code,
122 sizeof(struct qlink_resp), NULL);
123}
124
125static struct sk_buff *qtnf_cmd_alloc_new_cmdskb(u8 macid, u8 vifid, u16 cmd_no,
126 size_t cmd_size)
127{
128 struct qlink_cmd *cmd;
129 struct sk_buff *cmd_skb;
130
131 cmd_skb = __dev_alloc_skb(sizeof(*cmd) +
132 QTNF_MAX_CMD_BUF_SIZE, GFP_KERNEL);
133 if (unlikely(!cmd_skb)) {
134 pr_err("VIF%u.%u CMD %u: alloc failed\n", macid, vifid, cmd_no);
135 return NULL;
136 }
137
Johannes Bergb080db52017-06-16 14:29:19 +0200138 skb_put_zero(cmd_skb, cmd_size);
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700139
140 cmd = (struct qlink_cmd *)cmd_skb->data;
141 cmd->mhdr.len = cpu_to_le16(cmd_skb->len);
142 cmd->mhdr.type = cpu_to_le16(QLINK_MSG_TYPE_CMD);
143 cmd->cmd_id = cpu_to_le16(cmd_no);
144 cmd->macid = macid;
145 cmd->vifid = vifid;
146
147 return cmd_skb;
148}
149
150int qtnf_cmd_send_start_ap(struct qtnf_vif *vif)
151{
152 struct sk_buff *cmd_skb;
153 u16 res_code = QLINK_CMD_RESULT_OK;
154 int ret;
155
156 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
157 QLINK_CMD_START_AP,
158 sizeof(struct qlink_cmd));
159 if (unlikely(!cmd_skb))
160 return -ENOMEM;
161
162 qtnf_bus_lock(vif->mac->bus);
163
164 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
165
166 if (unlikely(ret))
167 goto out;
168
169 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
170 pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
171 vif->vifid, res_code);
172 ret = -EFAULT;
173 goto out;
174 }
175
176 vif->bss_status |= QTNF_STATE_AP_START;
177 netif_carrier_on(vif->netdev);
178
179out:
180 qtnf_bus_unlock(vif->mac->bus);
181 return ret;
182}
183
Igor Mitsyanko9b692df2017-10-04 18:38:06 -0700184int qtnf_cmd_send_config_ap(struct qtnf_vif *vif,
185 const struct cfg80211_ap_settings *s)
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700186{
187 struct sk_buff *cmd_skb;
Igor Mitsyanko8b5f4aa2017-10-04 18:38:07 -0700188 struct qlink_cmd_config_ap *cmd;
189 struct qlink_auth_encr *aen;
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700190 u16 res_code = QLINK_CMD_RESULT_OK;
191 int ret;
192 int i;
193
194 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
195 QLINK_CMD_CONFIG_AP,
Igor Mitsyanko8b5f4aa2017-10-04 18:38:07 -0700196 sizeof(*cmd));
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700197 if (unlikely(!cmd_skb))
198 return -ENOMEM;
199
Igor Mitsyanko8b5f4aa2017-10-04 18:38:07 -0700200 cmd = (struct qlink_cmd_config_ap *)cmd_skb->data;
201 cmd->dtim_period = s->dtim_period;
202 cmd->beacon_interval = cpu_to_le16(s->beacon_interval);
203 cmd->hidden_ssid = qlink_hidden_ssid_nl2q(s->hidden_ssid);
204 cmd->inactivity_timeout = cpu_to_le16(s->inactivity_timeout);
205 cmd->smps_mode = s->smps_mode;
206 cmd->p2p_ctwindow = s->p2p_ctwindow;
207 cmd->p2p_opp_ps = s->p2p_opp_ps;
208 cmd->pbss = s->pbss;
209 cmd->ht_required = s->ht_required;
210 cmd->vht_required = s->vht_required;
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700211
Igor Mitsyanko8b5f4aa2017-10-04 18:38:07 -0700212 aen = &cmd->aen;
213 aen->auth_type = s->auth_type;
214 aen->privacy = !!s->privacy;
215 aen->mfp = 0;
216 aen->wpa_versions = cpu_to_le32(s->crypto.wpa_versions);
217 aen->cipher_group = cpu_to_le32(s->crypto.cipher_group);
218 aen->n_ciphers_pairwise = cpu_to_le32(s->crypto.n_ciphers_pairwise);
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700219 for (i = 0; i < QLINK_MAX_NR_CIPHER_SUITES; i++)
Igor Mitsyanko8b5f4aa2017-10-04 18:38:07 -0700220 aen->ciphers_pairwise[i] =
221 cpu_to_le32(s->crypto.ciphers_pairwise[i]);
222 aen->n_akm_suites = cpu_to_le32(s->crypto.n_akm_suites);
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700223 for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++)
Igor Mitsyanko8b5f4aa2017-10-04 18:38:07 -0700224 aen->akm_suites[i] = cpu_to_le32(s->crypto.akm_suites[i]);
225 aen->control_port = s->crypto.control_port;
226 aen->control_port_no_encrypt = s->crypto.control_port_no_encrypt;
227 aen->control_port_ethertype =
Igor Mitsyanko9b692df2017-10-04 18:38:06 -0700228 cpu_to_le16(be16_to_cpu(s->crypto.control_port_ethertype));
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700229
Igor Mitsyankof99201c2017-10-04 18:38:08 -0700230 if (s->ssid && s->ssid_len > 0 && s->ssid_len <= IEEE80211_MAX_SSID_LEN)
231 qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, s->ssid,
232 s->ssid_len);
233
234 if (cfg80211_chandef_valid(&s->chandef)) {
235 struct qlink_tlv_chandef *chtlv =
236 (struct qlink_tlv_chandef *)skb_put(cmd_skb,
237 sizeof(*chtlv));
238
239 chtlv->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANDEF);
240 chtlv->hdr.len = cpu_to_le16(sizeof(*chtlv) -
241 sizeof(chtlv->hdr));
242 qlink_chandef_cfg2q(&s->chandef, &chtlv->chan);
243 }
244
Igor Mitsyanko8b5f4aa2017-10-04 18:38:07 -0700245 qtnf_bus_lock(vif->mac->bus);
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700246
247 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
248
249 if (unlikely(ret))
250 goto out;
251
252 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
253 pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
254 vif->vifid, res_code);
255 ret = -EFAULT;
256 goto out;
257 }
258
259 vif->bss_status |= QTNF_STATE_AP_CONFIG;
260
261out:
262 qtnf_bus_unlock(vif->mac->bus);
263 return ret;
264}
265
266int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif)
267{
268 struct sk_buff *cmd_skb;
269 u16 res_code = QLINK_CMD_RESULT_OK;
270 int ret;
271
272 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
273 QLINK_CMD_STOP_AP,
274 sizeof(struct qlink_cmd));
275 if (unlikely(!cmd_skb))
276 return -ENOMEM;
277
278 qtnf_bus_lock(vif->mac->bus);
279
280 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
281
282 if (unlikely(ret))
283 goto out;
284
285 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
286 pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
287 vif->vifid, res_code);
288 ret = -EFAULT;
289 goto out;
290 }
291
292 vif->bss_status &= ~QTNF_STATE_AP_START;
293 vif->bss_status &= ~QTNF_STATE_AP_CONFIG;
294
295 netif_carrier_off(vif->netdev);
296
297out:
298 qtnf_bus_unlock(vif->mac->bus);
299 return ret;
300}
301
302int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg)
303{
304 struct sk_buff *cmd_skb;
305 struct qlink_cmd_mgmt_frame_register *cmd;
306 u16 res_code = QLINK_CMD_RESULT_OK;
307 int ret;
308
309 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
310 QLINK_CMD_REGISTER_MGMT,
311 sizeof(*cmd));
312 if (unlikely(!cmd_skb))
313 return -ENOMEM;
314
315 qtnf_bus_lock(vif->mac->bus);
316
317 cmd = (struct qlink_cmd_mgmt_frame_register *)cmd_skb->data;
318 cmd->frame_type = cpu_to_le16(frame_type);
319 cmd->do_register = reg;
320
321 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
322
323 if (unlikely(ret))
324 goto out;
325
326 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
327 pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
328 vif->vifid, res_code);
329 ret = -EFAULT;
330 goto out;
331 }
332
333out:
334 qtnf_bus_unlock(vif->mac->bus);
335 return ret;
336}
337
338int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,
339 u16 freq, const u8 *buf, size_t len)
340{
341 struct sk_buff *cmd_skb;
342 struct qlink_cmd_mgmt_frame_tx *cmd;
343 u16 res_code = QLINK_CMD_RESULT_OK;
344 int ret;
345
346 if (sizeof(*cmd) + len > QTNF_MAX_CMD_BUF_SIZE) {
347 pr_warn("VIF%u.%u: frame is too big: %zu\n", vif->mac->macid,
348 vif->vifid, len);
349 return -E2BIG;
350 }
351
352 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
353 QLINK_CMD_SEND_MGMT_FRAME,
354 sizeof(*cmd));
355 if (unlikely(!cmd_skb))
356 return -ENOMEM;
357
358 qtnf_bus_lock(vif->mac->bus);
359
360 cmd = (struct qlink_cmd_mgmt_frame_tx *)cmd_skb->data;
361 cmd->cookie = cpu_to_le32(cookie);
362 cmd->freq = cpu_to_le16(freq);
363 cmd->flags = cpu_to_le16(flags);
364
365 if (len && buf)
366 qtnf_cmd_skb_put_buffer(cmd_skb, buf, len);
367
368 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
369
370 if (unlikely(ret))
371 goto out;
372
373 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
374 pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
375 vif->vifid, res_code);
376 ret = -EFAULT;
377 goto out;
378 }
379
380out:
381 qtnf_bus_unlock(vif->mac->bus);
382 return ret;
383}
384
385int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type,
386 const u8 *buf, size_t len)
387{
388 struct sk_buff *cmd_skb;
389 struct qlink_cmd_mgmt_append_ie *cmd;
390 u16 res_code = QLINK_CMD_RESULT_OK;
391 int ret;
392
393 if (sizeof(*cmd) + len > QTNF_MAX_CMD_BUF_SIZE) {
394 pr_warn("VIF%u.%u: %u frame is too big: %zu\n", vif->mac->macid,
395 vif->vifid, frame_type, len);
396 return -E2BIG;
397 }
398
399 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
400 QLINK_CMD_MGMT_SET_APPIE,
401 sizeof(*cmd));
402 if (unlikely(!cmd_skb))
403 return -ENOMEM;
404
405 qtnf_bus_lock(vif->mac->bus);
406
407 cmd = (struct qlink_cmd_mgmt_append_ie *)cmd_skb->data;
408 cmd->type = frame_type;
409 cmd->flags = 0;
410
411 /* If len == 0 then IE buf for specified frame type
412 * should be cleared on EP.
413 */
414 if (len && buf)
415 qtnf_cmd_skb_put_buffer(cmd_skb, buf, len);
416
417 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
418
419 if (unlikely(ret))
420 goto out;
421
422 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
423 pr_err("VIF%u.%u frame %u: CMD failed: %u\n", vif->mac->macid,
424 vif->vifid, frame_type, res_code);
425 ret = -EFAULT;
426 goto out;
427 }
428
429out:
430 qtnf_bus_unlock(vif->mac->bus);
431 return ret;
432}
433
434static void
435qtnf_sta_info_parse_basic_counters(struct station_info *sinfo,
436 const struct qlink_sta_stat_basic_counters *counters)
437{
438 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES) |
439 BIT(NL80211_STA_INFO_TX_BYTES);
440 sinfo->rx_bytes = get_unaligned_le64(&counters->rx_bytes);
441 sinfo->tx_bytes = get_unaligned_le64(&counters->tx_bytes);
442
443 sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
444 BIT(NL80211_STA_INFO_TX_PACKETS) |
445 BIT(NL80211_STA_INFO_BEACON_RX);
446 sinfo->rx_packets = get_unaligned_le32(&counters->rx_packets);
447 sinfo->tx_packets = get_unaligned_le32(&counters->tx_packets);
448 sinfo->rx_beacon = get_unaligned_le64(&counters->rx_beacons);
449
450 sinfo->filled |= BIT(NL80211_STA_INFO_RX_DROP_MISC) |
451 BIT(NL80211_STA_INFO_TX_FAILED);
452 sinfo->rx_dropped_misc = get_unaligned_le32(&counters->rx_dropped);
453 sinfo->tx_failed = get_unaligned_le32(&counters->tx_failed);
454}
455
456static void
457qtnf_sta_info_parse_rate(struct rate_info *rate_dst,
458 const struct qlink_sta_info_rate *rate_src)
459{
460 rate_dst->legacy = get_unaligned_le16(&rate_src->rate) * 10;
461
462 rate_dst->mcs = rate_src->mcs;
463 rate_dst->nss = rate_src->nss;
464 rate_dst->flags = 0;
465
466 switch (rate_src->bw) {
467 case QLINK_STA_INFO_RATE_BW_5:
468 rate_dst->bw = RATE_INFO_BW_5;
469 break;
470 case QLINK_STA_INFO_RATE_BW_10:
471 rate_dst->bw = RATE_INFO_BW_10;
472 break;
473 case QLINK_STA_INFO_RATE_BW_20:
474 rate_dst->bw = RATE_INFO_BW_20;
475 break;
476 case QLINK_STA_INFO_RATE_BW_40:
477 rate_dst->bw = RATE_INFO_BW_40;
478 break;
479 case QLINK_STA_INFO_RATE_BW_80:
480 rate_dst->bw = RATE_INFO_BW_80;
481 break;
482 case QLINK_STA_INFO_RATE_BW_160:
483 rate_dst->bw = RATE_INFO_BW_160;
484 break;
485 default:
486 rate_dst->bw = 0;
487 break;
488 }
489
490 if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_HT_MCS)
491 rate_dst->flags |= RATE_INFO_FLAGS_MCS;
492 else if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_VHT_MCS)
493 rate_dst->flags |= RATE_INFO_FLAGS_VHT_MCS;
494}
495
496static void
497qtnf_sta_info_parse_flags(struct nl80211_sta_flag_update *dst,
498 const struct qlink_sta_info_state *src)
499{
500 u32 mask, value;
501
502 dst->mask = 0;
503 dst->set = 0;
504
505 mask = le32_to_cpu(src->mask);
506 value = le32_to_cpu(src->value);
507
508 if (mask & QLINK_STA_FLAG_AUTHORIZED) {
509 dst->mask |= BIT(NL80211_STA_FLAG_AUTHORIZED);
510 if (value & QLINK_STA_FLAG_AUTHORIZED)
511 dst->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
512 }
513
514 if (mask & QLINK_STA_FLAG_SHORT_PREAMBLE) {
515 dst->mask |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
516 if (value & QLINK_STA_FLAG_SHORT_PREAMBLE)
517 dst->set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
518 }
519
520 if (mask & QLINK_STA_FLAG_WME) {
521 dst->mask |= BIT(NL80211_STA_FLAG_WME);
522 if (value & QLINK_STA_FLAG_WME)
523 dst->set |= BIT(NL80211_STA_FLAG_WME);
524 }
525
526 if (mask & QLINK_STA_FLAG_MFP) {
527 dst->mask |= BIT(NL80211_STA_FLAG_MFP);
528 if (value & QLINK_STA_FLAG_MFP)
529 dst->set |= BIT(NL80211_STA_FLAG_MFP);
530 }
531
532 if (mask & QLINK_STA_FLAG_AUTHENTICATED) {
533 dst->mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
534 if (value & QLINK_STA_FLAG_AUTHENTICATED)
535 dst->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
536 }
537
538 if (mask & QLINK_STA_FLAG_TDLS_PEER) {
539 dst->mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
540 if (value & QLINK_STA_FLAG_TDLS_PEER)
541 dst->set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
542 }
543
544 if (mask & QLINK_STA_FLAG_ASSOCIATED) {
545 dst->mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
546 if (value & QLINK_STA_FLAG_ASSOCIATED)
547 dst->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
548 }
549}
550
551static void
552qtnf_sta_info_parse_generic_info(struct station_info *sinfo,
553 const struct qlink_sta_info_generic *info)
554{
555 sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME) |
556 BIT(NL80211_STA_INFO_INACTIVE_TIME);
557 sinfo->connected_time = get_unaligned_le32(&info->connected_time);
558 sinfo->inactive_time = get_unaligned_le32(&info->inactive_time);
559
560 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL) |
561 BIT(NL80211_STA_INFO_SIGNAL_AVG);
562 sinfo->signal = info->rssi - 120;
563 sinfo->signal_avg = info->rssi_avg - QLINK_RSSI_OFFSET;
564
565 if (info->rx_rate.rate) {
566 sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
567 qtnf_sta_info_parse_rate(&sinfo->rxrate, &info->rx_rate);
568 }
569
570 if (info->tx_rate.rate) {
571 sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
572 qtnf_sta_info_parse_rate(&sinfo->txrate, &info->tx_rate);
573 }
574
575 sinfo->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
576 qtnf_sta_info_parse_flags(&sinfo->sta_flags, &info->state);
577}
578
579static int qtnf_cmd_sta_info_parse(struct station_info *sinfo,
580 const u8 *payload, size_t payload_size)
581{
582 const struct qlink_sta_stat_basic_counters *counters;
583 const struct qlink_sta_info_generic *sta_info;
584 u16 tlv_type;
585 u16 tlv_value_len;
586 size_t tlv_full_len;
587 const struct qlink_tlv_hdr *tlv;
588
589 sinfo->filled = 0;
590
591 tlv = (const struct qlink_tlv_hdr *)payload;
592 while (payload_size >= sizeof(struct qlink_tlv_hdr)) {
593 tlv_type = le16_to_cpu(tlv->type);
594 tlv_value_len = le16_to_cpu(tlv->len);
595 tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
596 if (tlv_full_len > payload_size) {
597 pr_warn("malformed TLV 0x%.2X; LEN: %u\n",
598 tlv_type, tlv_value_len);
599 return -EINVAL;
600 }
601 switch (tlv_type) {
602 case QTN_TLV_ID_STA_BASIC_COUNTERS:
603 if (unlikely(tlv_value_len < sizeof(*counters))) {
604 pr_err("invalid TLV size %.4X: %u\n",
605 tlv_type, tlv_value_len);
606 break;
607 }
608
609 counters = (void *)tlv->val;
610 qtnf_sta_info_parse_basic_counters(sinfo, counters);
611 break;
612 case QTN_TLV_ID_STA_GENERIC_INFO:
613 if (unlikely(tlv_value_len < sizeof(*sta_info)))
614 break;
615
616 sta_info = (void *)tlv->val;
617 qtnf_sta_info_parse_generic_info(sinfo, sta_info);
618 break;
619 default:
620 pr_warn("unexpected TLV type: %.4X\n", tlv_type);
621 break;
622 }
623 payload_size -= tlv_full_len;
624 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
625 }
626
627 if (payload_size) {
628 pr_warn("malformed TLV buf; bytes left: %zu\n", payload_size);
629 return -EINVAL;
630 }
631
632 return 0;
633}
634
635int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac,
636 struct station_info *sinfo)
637{
638 struct sk_buff *cmd_skb, *resp_skb = NULL;
639 struct qlink_cmd_get_sta_info *cmd;
640 const struct qlink_resp_get_sta_info *resp;
641 size_t var_resp_len;
642 u16 res_code = QLINK_CMD_RESULT_OK;
643 int ret = 0;
644
645 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
646 QLINK_CMD_GET_STA_INFO,
647 sizeof(*cmd));
648
649 if (unlikely(!cmd_skb))
650 return -ENOMEM;
651
652 qtnf_bus_lock(vif->mac->bus);
653
654 cmd = (struct qlink_cmd_get_sta_info *)cmd_skb->data;
655 ether_addr_copy(cmd->sta_addr, sta_mac);
656
657 ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb,
658 &res_code, sizeof(*resp),
659 &var_resp_len);
660
661 if (unlikely(ret))
662 goto out;
663
664 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
665 switch (res_code) {
666 case QLINK_CMD_RESULT_ENOTFOUND:
667 pr_warn("VIF%u.%u: %pM STA not found\n",
668 vif->mac->macid, vif->vifid, sta_mac);
669 ret = -ENOENT;
670 break;
671 default:
672 pr_err("VIF%u.%u: can't get info for %pM: %u\n",
673 vif->mac->macid, vif->vifid, sta_mac, res_code);
674 ret = -EFAULT;
675 break;
676 }
677 goto out;
678 }
679
680 resp = (const struct qlink_resp_get_sta_info *)resp_skb->data;
681
682 if (unlikely(!ether_addr_equal(sta_mac, resp->sta_addr))) {
683 pr_err("VIF%u.%u: wrong mac in reply: %pM != %pM\n",
684 vif->mac->macid, vif->vifid, resp->sta_addr, sta_mac);
685 ret = -EINVAL;
686 goto out;
687 }
688
689 ret = qtnf_cmd_sta_info_parse(sinfo, resp->info, var_resp_len);
690
691out:
692 qtnf_bus_unlock(vif->mac->bus);
693 consume_skb(resp_skb);
694
695 return ret;
696}
697
698static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif,
699 enum nl80211_iftype iftype,
700 u8 *mac_addr,
701 enum qlink_cmd_type cmd_type)
702{
703 struct sk_buff *cmd_skb, *resp_skb = NULL;
704 struct qlink_cmd_manage_intf *cmd;
705 const struct qlink_resp_manage_intf *resp;
706 u16 res_code = QLINK_CMD_RESULT_OK;
707 int ret = 0;
708
709 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
710 cmd_type,
711 sizeof(*cmd));
712 if (unlikely(!cmd_skb))
713 return -ENOMEM;
714
715 qtnf_bus_lock(vif->mac->bus);
716
717 cmd = (struct qlink_cmd_manage_intf *)cmd_skb->data;
718
719 switch (iftype) {
720 case NL80211_IFTYPE_AP:
721 cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_AP);
722 break;
723 case NL80211_IFTYPE_STATION:
724 cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_STATION);
725 break;
726 default:
727 pr_err("VIF%u.%u: unsupported type %d\n", vif->mac->macid,
728 vif->vifid, iftype);
729 ret = -EINVAL;
730 goto out;
731 }
732
733 if (mac_addr)
734 ether_addr_copy(cmd->intf_info.mac_addr, mac_addr);
735 else
736 eth_zero_addr(cmd->intf_info.mac_addr);
737
738 ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb,
739 &res_code, sizeof(*resp), NULL);
740
741 if (unlikely(ret))
742 goto out;
743
744 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
745 pr_err("VIF%u.%u: CMD %d failed: %u\n", vif->mac->macid,
746 vif->vifid, cmd_type, res_code);
747 ret = -EFAULT;
748 goto out;
749 }
750
751 resp = (const struct qlink_resp_manage_intf *)resp_skb->data;
752 ether_addr_copy(vif->mac_addr, resp->intf_info.mac_addr);
753
754out:
755 qtnf_bus_unlock(vif->mac->bus);
756 consume_skb(resp_skb);
757
758 return ret;
759}
760
761int qtnf_cmd_send_add_intf(struct qtnf_vif *vif,
762 enum nl80211_iftype iftype, u8 *mac_addr)
763{
764 return qtnf_cmd_send_add_change_intf(vif, iftype, mac_addr,
765 QLINK_CMD_ADD_INTF);
766}
767
768int qtnf_cmd_send_change_intf_type(struct qtnf_vif *vif,
769 enum nl80211_iftype iftype, u8 *mac_addr)
770{
771 return qtnf_cmd_send_add_change_intf(vif, iftype, mac_addr,
772 QLINK_CMD_CHANGE_INTF);
773}
774
775int qtnf_cmd_send_del_intf(struct qtnf_vif *vif)
776{
777 struct sk_buff *cmd_skb;
778 struct qlink_cmd_manage_intf *cmd;
779 u16 res_code = QLINK_CMD_RESULT_OK;
780 int ret = 0;
781
782 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
783 QLINK_CMD_DEL_INTF,
784 sizeof(*cmd));
785 if (unlikely(!cmd_skb))
786 return -ENOMEM;
787
788 qtnf_bus_lock(vif->mac->bus);
789
790 cmd = (struct qlink_cmd_manage_intf *)cmd_skb->data;
791
792 switch (vif->wdev.iftype) {
793 case NL80211_IFTYPE_AP:
794 cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_AP);
795 break;
796 case NL80211_IFTYPE_STATION:
797 cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_STATION);
798 break;
799 default:
800 pr_warn("VIF%u.%u: unsupported iftype %d\n", vif->mac->macid,
801 vif->vifid, vif->wdev.iftype);
802 ret = -EINVAL;
803 goto out;
804 }
805
806 eth_zero_addr(cmd->intf_info.mac_addr);
807
808 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
809
810 if (unlikely(ret))
811 goto out;
812
813 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
814 pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
815 vif->vifid, res_code);
816 ret = -EFAULT;
817 goto out;
818 }
819
820out:
821 qtnf_bus_unlock(vif->mac->bus);
822 return ret;
823}
824
Sergey Matyukevich4dd07d22017-07-28 02:06:43 +0300825static u32 qtnf_cmd_resp_reg_rule_flags_parse(u32 qflags)
826{
827 u32 flags = 0;
828
829 if (qflags & QLINK_RRF_NO_OFDM)
830 flags |= NL80211_RRF_NO_OFDM;
831
832 if (qflags & QLINK_RRF_NO_CCK)
833 flags |= NL80211_RRF_NO_CCK;
834
835 if (qflags & QLINK_RRF_NO_INDOOR)
836 flags |= NL80211_RRF_NO_INDOOR;
837
838 if (qflags & QLINK_RRF_NO_OUTDOOR)
839 flags |= NL80211_RRF_NO_OUTDOOR;
840
841 if (qflags & QLINK_RRF_DFS)
842 flags |= NL80211_RRF_DFS;
843
844 if (qflags & QLINK_RRF_PTP_ONLY)
845 flags |= NL80211_RRF_PTP_ONLY;
846
847 if (qflags & QLINK_RRF_PTMP_ONLY)
848 flags |= NL80211_RRF_PTMP_ONLY;
849
850 if (qflags & QLINK_RRF_NO_IR)
851 flags |= NL80211_RRF_NO_IR;
852
853 if (qflags & QLINK_RRF_AUTO_BW)
854 flags |= NL80211_RRF_AUTO_BW;
855
856 if (qflags & QLINK_RRF_IR_CONCURRENT)
857 flags |= NL80211_RRF_IR_CONCURRENT;
858
859 if (qflags & QLINK_RRF_NO_HT40MINUS)
860 flags |= NL80211_RRF_NO_HT40MINUS;
861
862 if (qflags & QLINK_RRF_NO_HT40PLUS)
863 flags |= NL80211_RRF_NO_HT40PLUS;
864
865 if (qflags & QLINK_RRF_NO_80MHZ)
866 flags |= NL80211_RRF_NO_80MHZ;
867
868 if (qflags & QLINK_RRF_NO_160MHZ)
869 flags |= NL80211_RRF_NO_160MHZ;
870
871 return flags;
872}
873
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700874static int
875qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,
Sergey Matyukevich4dd07d22017-07-28 02:06:43 +0300876 const struct qlink_resp_get_hw_info *resp,
877 size_t info_len)
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700878{
879 struct qtnf_hw_info *hwinfo = &bus->hw_info;
Sergey Matyukevich4dd07d22017-07-28 02:06:43 +0300880 const struct qlink_tlv_hdr *tlv;
881 const struct qlink_tlv_reg_rule *tlv_rule;
882 struct ieee80211_reg_rule *rule;
883 u16 tlv_type;
884 u16 tlv_value_len;
885 unsigned int rule_idx = 0;
886
887 if (WARN_ON(resp->n_reg_rules > NL80211_MAX_SUPP_REG_RULES))
888 return -E2BIG;
889
890 hwinfo->rd = kzalloc(sizeof(*hwinfo->rd)
891 + sizeof(struct ieee80211_reg_rule)
892 * resp->n_reg_rules, GFP_KERNEL);
893
894 if (!hwinfo->rd)
895 return -ENOMEM;
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700896
897 hwinfo->num_mac = resp->num_mac;
898 hwinfo->mac_bitmap = resp->mac_bitmap;
899 hwinfo->fw_ver = le32_to_cpu(resp->fw_ver);
900 hwinfo->ql_proto_ver = le16_to_cpu(resp->ql_proto_ver);
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700901 hwinfo->total_tx_chain = resp->total_tx_chain;
902 hwinfo->total_rx_chain = resp->total_rx_chain;
903 hwinfo->hw_capab = le32_to_cpu(resp->hw_capab);
Sergey Matyukevich4dd07d22017-07-28 02:06:43 +0300904 hwinfo->rd->n_reg_rules = resp->n_reg_rules;
905 hwinfo->rd->alpha2[0] = resp->alpha2[0];
906 hwinfo->rd->alpha2[1] = resp->alpha2[1];
907
908 switch (resp->dfs_region) {
909 case QLINK_DFS_FCC:
910 hwinfo->rd->dfs_region = NL80211_DFS_FCC;
911 break;
912 case QLINK_DFS_ETSI:
913 hwinfo->rd->dfs_region = NL80211_DFS_ETSI;
914 break;
915 case QLINK_DFS_JP:
916 hwinfo->rd->dfs_region = NL80211_DFS_JP;
917 break;
918 case QLINK_DFS_UNSET:
919 default:
920 hwinfo->rd->dfs_region = NL80211_DFS_UNSET;
921 break;
922 }
923
924 tlv = (const struct qlink_tlv_hdr *)resp->info;
925
926 while (info_len >= sizeof(*tlv)) {
927 tlv_type = le16_to_cpu(tlv->type);
928 tlv_value_len = le16_to_cpu(tlv->len);
929
930 if (tlv_value_len + sizeof(*tlv) > info_len) {
931 pr_warn("malformed TLV 0x%.2X; LEN: %u\n",
932 tlv_type, tlv_value_len);
933 return -EINVAL;
934 }
935
936 switch (tlv_type) {
937 case QTN_TLV_ID_REG_RULE:
938 if (rule_idx >= resp->n_reg_rules) {
939 pr_warn("unexpected number of rules: %u\n",
940 resp->n_reg_rules);
941 return -EINVAL;
942 }
943
944 if (tlv_value_len != sizeof(*tlv_rule) - sizeof(*tlv)) {
945 pr_warn("malformed TLV 0x%.2X; LEN: %u\n",
946 tlv_type, tlv_value_len);
947 return -EINVAL;
948 }
949
950 tlv_rule = (const struct qlink_tlv_reg_rule *)tlv;
951 rule = &hwinfo->rd->reg_rules[rule_idx++];
952
953 rule->freq_range.start_freq_khz =
954 le32_to_cpu(tlv_rule->start_freq_khz);
955 rule->freq_range.end_freq_khz =
956 le32_to_cpu(tlv_rule->end_freq_khz);
957 rule->freq_range.max_bandwidth_khz =
958 le32_to_cpu(tlv_rule->max_bandwidth_khz);
959 rule->power_rule.max_antenna_gain =
960 le32_to_cpu(tlv_rule->max_antenna_gain);
961 rule->power_rule.max_eirp =
962 le32_to_cpu(tlv_rule->max_eirp);
963 rule->dfs_cac_ms =
964 le32_to_cpu(tlv_rule->dfs_cac_ms);
965 rule->flags = qtnf_cmd_resp_reg_rule_flags_parse(
966 le32_to_cpu(tlv_rule->flags));
967 break;
968 default:
969 break;
970 }
971
972 info_len -= tlv_value_len + sizeof(*tlv);
973 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
974 }
975
976 if (rule_idx != resp->n_reg_rules) {
977 pr_warn("unexpected number of rules: expected %u got %u\n",
978 resp->n_reg_rules, rule_idx);
979 kfree(hwinfo->rd);
980 hwinfo->rd = NULL;
981 return -EINVAL;
982 }
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700983
984 pr_info("fw_version=%d, MACs map %#x, alpha2=\"%c%c\", chains Tx=%u Rx=%u\n",
985 hwinfo->fw_ver, hwinfo->mac_bitmap,
Sergey Matyukevich4dd07d22017-07-28 02:06:43 +0300986 hwinfo->rd->alpha2[0], hwinfo->rd->alpha2[1],
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700987 hwinfo->total_tx_chain, hwinfo->total_rx_chain);
988
989 return 0;
990}
991
992static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,
993 const u8 *tlv_buf, size_t tlv_buf_size)
994{
995 struct ieee80211_iface_limit *limits = NULL;
996 const struct qlink_iface_limit *limit_record;
997 size_t record_count = 0, rec = 0;
Sergey Matyukevich41c8fa02017-07-28 02:06:52 +0300998 u16 tlv_type, tlv_value_len;
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -0700999 struct qlink_iface_comb_num *comb;
1000 size_t tlv_full_len;
1001 const struct qlink_tlv_hdr *tlv;
1002
1003 mac->macinfo.n_limits = 0;
1004
1005 tlv = (const struct qlink_tlv_hdr *)tlv_buf;
1006 while (tlv_buf_size >= sizeof(struct qlink_tlv_hdr)) {
1007 tlv_type = le16_to_cpu(tlv->type);
1008 tlv_value_len = le16_to_cpu(tlv->len);
1009 tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
1010 if (tlv_full_len > tlv_buf_size) {
1011 pr_warn("MAC%u: malformed TLV 0x%.2X; LEN: %u\n",
1012 mac->macid, tlv_type, tlv_value_len);
1013 return -EINVAL;
1014 }
1015
1016 switch (tlv_type) {
1017 case QTN_TLV_ID_NUM_IFACE_COMB:
1018 if (unlikely(tlv_value_len != sizeof(*comb)))
1019 return -EINVAL;
1020
1021 comb = (void *)tlv->val;
1022 record_count = le16_to_cpu(comb->iface_comb_num);
1023
1024 mac->macinfo.n_limits = record_count;
1025 /* free earlier iface limits memory */
1026 kfree(mac->macinfo.limits);
1027 mac->macinfo.limits =
1028 kzalloc(sizeof(*mac->macinfo.limits) *
1029 record_count, GFP_KERNEL);
1030
1031 if (unlikely(!mac->macinfo.limits))
1032 return -ENOMEM;
1033
1034 limits = mac->macinfo.limits;
1035 break;
1036 case QTN_TLV_ID_IFACE_LIMIT:
1037 if (unlikely(!limits)) {
1038 pr_warn("MAC%u: limits are not inited\n",
1039 mac->macid);
1040 return -EINVAL;
1041 }
1042
1043 if (unlikely(tlv_value_len != sizeof(*limit_record))) {
1044 pr_warn("MAC%u: record size mismatch\n",
1045 mac->macid);
1046 return -EINVAL;
1047 }
1048
1049 limit_record = (void *)tlv->val;
1050 limits[rec].max = le16_to_cpu(limit_record->max_num);
Sergey Matyukevich41c8fa02017-07-28 02:06:52 +03001051 limits[rec].types = qlink_iface_type_to_nl_mask(
1052 le16_to_cpu(limit_record->type));
1053
1054 /* supported modes: STA, AP */
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001055 limits[rec].types &= BIT(NL80211_IFTYPE_AP) |
Sergey Matyukevich805b28c2017-07-28 02:06:54 +03001056 BIT(NL80211_IFTYPE_AP_VLAN) |
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001057 BIT(NL80211_IFTYPE_STATION);
1058
1059 pr_debug("MAC%u: MAX: %u; TYPES: %.4X\n", mac->macid,
1060 limits[rec].max, limits[rec].types);
1061
1062 if (limits[rec].types)
1063 rec++;
1064 break;
1065 default:
1066 break;
1067 }
Sergey Matyukevich805b28c2017-07-28 02:06:54 +03001068
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001069 tlv_buf_size -= tlv_full_len;
1070 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
1071 }
1072
1073 if (tlv_buf_size) {
1074 pr_warn("MAC%u: malformed TLV buf; bytes left: %zu\n",
1075 mac->macid, tlv_buf_size);
1076 return -EINVAL;
1077 }
1078
1079 if (mac->macinfo.n_limits != rec) {
1080 pr_err("MAC%u: combination mismatch: reported=%zu parsed=%zu\n",
1081 mac->macid, mac->macinfo.n_limits, rec);
1082 return -EINVAL;
1083 }
1084
1085 return 0;
1086}
1087
1088static void
1089qtnf_cmd_resp_proc_mac_info(struct qtnf_wmac *mac,
1090 const struct qlink_resp_get_mac_info *resp_info)
1091{
1092 struct qtnf_mac_info *mac_info;
1093 struct qtnf_vif *vif;
1094
1095 mac_info = &mac->macinfo;
1096
1097 mac_info->bands_cap = resp_info->bands_cap;
1098 mac_info->phymode_cap = resp_info->phymode_cap;
1099 memcpy(&mac_info->dev_mac, &resp_info->dev_mac,
1100 sizeof(mac_info->dev_mac));
1101
1102 ether_addr_copy(mac->macaddr, mac_info->dev_mac);
1103
1104 vif = qtnf_mac_get_base_vif(mac);
1105 if (vif)
1106 ether_addr_copy(vif->mac_addr, mac->macaddr);
1107 else
1108 pr_err("could not get valid base vif\n");
1109
1110 mac_info->num_tx_chain = resp_info->num_tx_chain;
1111 mac_info->num_rx_chain = resp_info->num_rx_chain;
1112
1113 mac_info->max_ap_assoc_sta = le16_to_cpu(resp_info->max_ap_assoc_sta);
1114 mac_info->radar_detect_widths =
1115 qlink_chan_width_mask_to_nl(le16_to_cpu(
1116 resp_info->radar_detect_widths));
1117
1118 memcpy(&mac_info->ht_cap, &resp_info->ht_cap, sizeof(mac_info->ht_cap));
1119 memcpy(&mac_info->vht_cap, &resp_info->vht_cap,
1120 sizeof(mac_info->vht_cap));
1121}
1122
1123static int
1124qtnf_cmd_resp_fill_channels_info(struct ieee80211_supported_band *band,
1125 struct qlink_resp_get_chan_info *resp,
1126 size_t payload_len)
1127{
1128 u16 tlv_type;
1129 size_t tlv_len;
1130 const struct qlink_tlv_hdr *tlv;
1131 const struct qlink_tlv_channel *qchan;
1132 struct ieee80211_channel *chan;
1133 unsigned int chidx = 0;
1134 u32 qflags;
1135
Sergey Matyukevich4dd07d22017-07-28 02:06:43 +03001136 if (band->channels) {
1137 if (band->n_channels == resp->num_chans) {
1138 memset(band->channels, 0,
1139 sizeof(*band->channels) * band->n_channels);
1140 } else {
1141 kfree(band->channels);
1142 band->n_channels = 0;
1143 band->channels = NULL;
1144 }
1145 }
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001146
1147 band->n_channels = resp->num_chans;
1148 if (band->n_channels == 0)
1149 return 0;
1150
Sergey Matyukevich4dd07d22017-07-28 02:06:43 +03001151 if (!band->channels)
1152 band->channels = kcalloc(band->n_channels, sizeof(*chan),
1153 GFP_KERNEL);
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001154 if (!band->channels) {
1155 band->n_channels = 0;
1156 return -ENOMEM;
1157 }
1158
1159 tlv = (struct qlink_tlv_hdr *)resp->info;
1160
1161 while (payload_len >= sizeof(*tlv)) {
1162 tlv_type = le16_to_cpu(tlv->type);
1163 tlv_len = le16_to_cpu(tlv->len) + sizeof(*tlv);
1164
1165 if (tlv_len > payload_len) {
1166 pr_warn("malformed TLV 0x%.2X; LEN: %zu\n",
1167 tlv_type, tlv_len);
1168 goto error_ret;
1169 }
1170
1171 switch (tlv_type) {
1172 case QTN_TLV_ID_CHANNEL:
1173 if (unlikely(tlv_len != sizeof(*qchan))) {
1174 pr_err("invalid channel TLV len %zu\n",
1175 tlv_len);
1176 goto error_ret;
1177 }
1178
1179 if (chidx == band->n_channels) {
1180 pr_err("too many channel TLVs\n");
1181 goto error_ret;
1182 }
1183
1184 qchan = (const struct qlink_tlv_channel *)tlv;
1185 chan = &band->channels[chidx++];
1186 qflags = le32_to_cpu(qchan->flags);
1187
1188 chan->hw_value = le16_to_cpu(qchan->hw_value);
1189 chan->band = band->band;
1190 chan->center_freq = le16_to_cpu(qchan->center_freq);
1191 chan->max_antenna_gain = (int)qchan->max_antenna_gain;
1192 chan->max_power = (int)qchan->max_power;
1193 chan->max_reg_power = (int)qchan->max_reg_power;
1194 chan->beacon_found = qchan->beacon_found;
1195 chan->dfs_cac_ms = le32_to_cpu(qchan->dfs_cac_ms);
1196 chan->flags = 0;
1197
1198 if (qflags & QLINK_CHAN_DISABLED)
1199 chan->flags |= IEEE80211_CHAN_DISABLED;
1200
1201 if (qflags & QLINK_CHAN_NO_IR)
1202 chan->flags |= IEEE80211_CHAN_NO_IR;
1203
1204 if (qflags & QLINK_CHAN_NO_HT40PLUS)
1205 chan->flags |= IEEE80211_CHAN_NO_HT40PLUS;
1206
1207 if (qflags & QLINK_CHAN_NO_HT40MINUS)
1208 chan->flags |= IEEE80211_CHAN_NO_HT40MINUS;
1209
1210 if (qflags & QLINK_CHAN_NO_OFDM)
1211 chan->flags |= IEEE80211_CHAN_NO_OFDM;
1212
1213 if (qflags & QLINK_CHAN_NO_80MHZ)
1214 chan->flags |= IEEE80211_CHAN_NO_80MHZ;
1215
1216 if (qflags & QLINK_CHAN_NO_160MHZ)
1217 chan->flags |= IEEE80211_CHAN_NO_160MHZ;
1218
1219 if (qflags & QLINK_CHAN_INDOOR_ONLY)
1220 chan->flags |= IEEE80211_CHAN_INDOOR_ONLY;
1221
1222 if (qflags & QLINK_CHAN_IR_CONCURRENT)
1223 chan->flags |= IEEE80211_CHAN_IR_CONCURRENT;
1224
1225 if (qflags & QLINK_CHAN_NO_20MHZ)
1226 chan->flags |= IEEE80211_CHAN_NO_20MHZ;
1227
1228 if (qflags & QLINK_CHAN_NO_10MHZ)
1229 chan->flags |= IEEE80211_CHAN_NO_10MHZ;
1230
1231 if (qflags & QLINK_CHAN_RADAR) {
1232 chan->flags |= IEEE80211_CHAN_RADAR;
1233 chan->dfs_state_entered = jiffies;
1234
1235 if (qchan->dfs_state == QLINK_DFS_USABLE)
1236 chan->dfs_state = NL80211_DFS_USABLE;
1237 else if (qchan->dfs_state ==
1238 QLINK_DFS_AVAILABLE)
1239 chan->dfs_state = NL80211_DFS_AVAILABLE;
1240 else
1241 chan->dfs_state =
1242 NL80211_DFS_UNAVAILABLE;
1243 }
1244
1245 pr_debug("chan=%d flags=%#x max_pow=%d max_reg_pow=%d\n",
1246 chan->hw_value, chan->flags, chan->max_power,
1247 chan->max_reg_power);
1248 break;
1249 default:
1250 pr_warn("unknown TLV type: %#x\n", tlv_type);
1251 break;
1252 }
1253
1254 payload_len -= tlv_len;
1255 tlv = (struct qlink_tlv_hdr *)((u8 *)tlv + tlv_len);
1256 }
1257
1258 if (payload_len) {
1259 pr_err("malformed TLV buf; bytes left: %zu\n", payload_len);
1260 goto error_ret;
1261 }
1262
1263 if (band->n_channels != chidx) {
1264 pr_err("channel count mismatch: reported=%d, parsed=%d\n",
1265 band->n_channels, chidx);
1266 goto error_ret;
1267 }
1268
1269 return 0;
1270
1271error_ret:
1272 kfree(band->channels);
1273 band->channels = NULL;
1274 band->n_channels = 0;
1275
1276 return -EINVAL;
1277}
1278
1279static int qtnf_cmd_resp_proc_phy_params(struct qtnf_wmac *mac,
1280 const u8 *payload, size_t payload_len)
1281{
1282 struct qtnf_mac_info *mac_info;
1283 struct qlink_tlv_frag_rts_thr *phy_thr;
1284 struct qlink_tlv_rlimit *limit;
1285 struct qlink_tlv_cclass *class;
1286 u16 tlv_type;
1287 u16 tlv_value_len;
1288 size_t tlv_full_len;
1289 const struct qlink_tlv_hdr *tlv;
1290
1291 mac_info = &mac->macinfo;
1292
1293 tlv = (struct qlink_tlv_hdr *)payload;
1294 while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
1295 tlv_type = le16_to_cpu(tlv->type);
1296 tlv_value_len = le16_to_cpu(tlv->len);
1297 tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
1298
1299 if (tlv_full_len > payload_len) {
1300 pr_warn("MAC%u: malformed TLV 0x%.2X; LEN: %u\n",
1301 mac->macid, tlv_type, tlv_value_len);
1302 return -EINVAL;
1303 }
1304
1305 switch (tlv_type) {
1306 case QTN_TLV_ID_FRAG_THRESH:
1307 phy_thr = (void *)tlv;
1308 mac_info->frag_thr = (u32)le16_to_cpu(phy_thr->thr);
1309 break;
1310 case QTN_TLV_ID_RTS_THRESH:
1311 phy_thr = (void *)tlv;
1312 mac_info->rts_thr = (u32)le16_to_cpu(phy_thr->thr);
1313 break;
1314 case QTN_TLV_ID_SRETRY_LIMIT:
1315 limit = (void *)tlv;
1316 mac_info->sretry_limit = limit->rlimit;
1317 break;
1318 case QTN_TLV_ID_LRETRY_LIMIT:
1319 limit = (void *)tlv;
1320 mac_info->lretry_limit = limit->rlimit;
1321 break;
1322 case QTN_TLV_ID_COVERAGE_CLASS:
1323 class = (void *)tlv;
1324 mac_info->coverage_class = class->cclass;
1325 break;
1326 default:
1327 pr_err("MAC%u: Unknown TLV type: %#x\n", mac->macid,
1328 le16_to_cpu(tlv->type));
1329 break;
1330 }
1331
1332 payload_len -= tlv_full_len;
1333 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
1334 }
1335
1336 if (payload_len) {
1337 pr_warn("MAC%u: malformed TLV buf; bytes left: %zu\n",
1338 mac->macid, payload_len);
1339 return -EINVAL;
1340 }
1341
1342 return 0;
1343}
1344
Sergey Matyukevich7c04b432017-07-28 02:06:46 +03001345static int
1346qtnf_cmd_resp_proc_chan_stat_info(struct qtnf_chan_stats *stats,
1347 const u8 *payload, size_t payload_len)
1348{
1349 struct qlink_chan_stats *qlink_stats;
1350 const struct qlink_tlv_hdr *tlv;
1351 size_t tlv_full_len;
1352 u16 tlv_value_len;
1353 u16 tlv_type;
1354
1355 tlv = (struct qlink_tlv_hdr *)payload;
1356 while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
1357 tlv_type = le16_to_cpu(tlv->type);
1358 tlv_value_len = le16_to_cpu(tlv->len);
1359 tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
1360 if (tlv_full_len > payload_len) {
1361 pr_warn("malformed TLV 0x%.2X; LEN: %u\n",
1362 tlv_type, tlv_value_len);
1363 return -EINVAL;
1364 }
1365 switch (tlv_type) {
1366 case QTN_TLV_ID_CHANNEL_STATS:
1367 if (unlikely(tlv_value_len != sizeof(*qlink_stats))) {
1368 pr_err("invalid CHANNEL_STATS entry size\n");
1369 return -EINVAL;
1370 }
1371
1372 qlink_stats = (void *)tlv->val;
1373
1374 stats->chan_num = le32_to_cpu(qlink_stats->chan_num);
1375 stats->cca_tx = le32_to_cpu(qlink_stats->cca_tx);
1376 stats->cca_rx = le32_to_cpu(qlink_stats->cca_rx);
1377 stats->cca_busy = le32_to_cpu(qlink_stats->cca_busy);
1378 stats->cca_try = le32_to_cpu(qlink_stats->cca_try);
1379 stats->chan_noise = qlink_stats->chan_noise;
1380
1381 pr_debug("chan(%u) try(%u) busy(%u) noise(%d)\n",
1382 stats->chan_num, stats->cca_try,
1383 stats->cca_busy, stats->chan_noise);
1384 break;
1385 default:
1386 pr_warn("Unknown TLV type: %#x\n",
1387 le16_to_cpu(tlv->type));
1388 }
1389 payload_len -= tlv_full_len;
1390 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
1391 }
1392
1393 if (payload_len) {
1394 pr_warn("malformed TLV buf; bytes left: %zu\n", payload_len);
1395 return -EINVAL;
1396 }
1397
1398 return 0;
1399}
1400
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001401int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac)
1402{
1403 struct sk_buff *cmd_skb, *resp_skb = NULL;
1404 const struct qlink_resp_get_mac_info *resp;
1405 size_t var_data_len;
1406 u16 res_code = QLINK_CMD_RESULT_OK;
1407 int ret = 0;
1408
1409 cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
1410 QLINK_CMD_MAC_INFO,
1411 sizeof(struct qlink_cmd));
1412 if (unlikely(!cmd_skb))
1413 return -ENOMEM;
1414
1415 qtnf_bus_lock(mac->bus);
1416
1417 ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code,
1418 sizeof(*resp), &var_data_len);
1419 if (unlikely(ret))
1420 goto out;
1421
1422 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
1423 pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code);
1424 ret = -EFAULT;
1425 goto out;
1426 }
1427
1428 resp = (const struct qlink_resp_get_mac_info *)resp_skb->data;
1429 qtnf_cmd_resp_proc_mac_info(mac, resp);
1430 ret = qtnf_parse_variable_mac_info(mac, resp->var_info, var_data_len);
1431
1432out:
1433 qtnf_bus_unlock(mac->bus);
1434 consume_skb(resp_skb);
1435
1436 return ret;
1437}
1438
1439int qtnf_cmd_get_hw_info(struct qtnf_bus *bus)
1440{
1441 struct sk_buff *cmd_skb, *resp_skb = NULL;
1442 const struct qlink_resp_get_hw_info *resp;
1443 u16 res_code = QLINK_CMD_RESULT_OK;
1444 int ret = 0;
Sergey Matyukevich4dd07d22017-07-28 02:06:43 +03001445 size_t info_len;
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001446
1447 cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
1448 QLINK_CMD_GET_HW_INFO,
1449 sizeof(struct qlink_cmd));
1450 if (unlikely(!cmd_skb))
1451 return -ENOMEM;
1452
1453 qtnf_bus_lock(bus);
1454
1455 ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, &res_code,
Sergey Matyukevich4dd07d22017-07-28 02:06:43 +03001456 sizeof(*resp), &info_len);
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001457
1458 if (unlikely(ret))
1459 goto out;
1460
1461 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
1462 pr_err("cmd exec failed: 0x%.4X\n", res_code);
1463 ret = -EFAULT;
1464 goto out;
1465 }
1466
1467 resp = (const struct qlink_resp_get_hw_info *)resp_skb->data;
Sergey Matyukevich4dd07d22017-07-28 02:06:43 +03001468 ret = qtnf_cmd_resp_proc_hw_info(bus, resp, info_len);
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001469
1470out:
1471 qtnf_bus_unlock(bus);
1472 consume_skb(resp_skb);
1473
1474 return ret;
1475}
1476
1477int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac,
1478 struct ieee80211_supported_band *band)
1479{
1480 struct sk_buff *cmd_skb, *resp_skb = NULL;
1481 size_t info_len;
1482 struct qlink_cmd_chans_info_get *cmd;
1483 struct qlink_resp_get_chan_info *resp;
1484 u16 res_code = QLINK_CMD_RESULT_OK;
1485 int ret = 0;
1486 u8 qband;
1487
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001488 switch (band->band) {
1489 case NL80211_BAND_2GHZ:
1490 qband = QLINK_BAND_2GHZ;
1491 break;
1492 case NL80211_BAND_5GHZ:
1493 qband = QLINK_BAND_5GHZ;
1494 break;
1495 case NL80211_BAND_60GHZ:
1496 qband = QLINK_BAND_60GHZ;
1497 break;
1498 default:
1499 return -EINVAL;
1500 }
1501
Colin Ian Kingbc0384e2017-06-02 16:40:45 +01001502 cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0,
1503 QLINK_CMD_CHANS_INFO_GET,
1504 sizeof(*cmd));
1505 if (!cmd_skb)
1506 return -ENOMEM;
1507
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001508 cmd = (struct qlink_cmd_chans_info_get *)cmd_skb->data;
1509 cmd->band = qband;
Sergey Matyukevich9ef75092017-07-28 02:06:45 +03001510
1511 qtnf_bus_lock(mac->bus);
1512
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001513 ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code,
1514 sizeof(*resp), &info_len);
1515
1516 if (unlikely(ret))
1517 goto out;
1518
1519 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
1520 pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code);
1521 ret = -EFAULT;
1522 goto out;
1523 }
1524
1525 resp = (struct qlink_resp_get_chan_info *)resp_skb->data;
1526 if (resp->band != qband) {
1527 pr_err("MAC%u: reply band %u != cmd band %u\n", mac->macid,
1528 resp->band, qband);
1529 ret = -EINVAL;
1530 goto out;
1531 }
1532
1533 ret = qtnf_cmd_resp_fill_channels_info(band, resp, info_len);
1534
1535out:
Sergey Matyukevich9ef75092017-07-28 02:06:45 +03001536 qtnf_bus_unlock(mac->bus);
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001537 consume_skb(resp_skb);
1538
1539 return ret;
1540}
1541
1542int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac)
1543{
1544 struct sk_buff *cmd_skb, *resp_skb = NULL;
1545 size_t response_size;
1546 struct qlink_resp_phy_params *resp;
1547 u16 res_code = QLINK_CMD_RESULT_OK;
1548 int ret = 0;
1549
1550 cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0,
1551 QLINK_CMD_PHY_PARAMS_GET,
1552 sizeof(struct qlink_cmd));
1553 if (!cmd_skb)
1554 return -ENOMEM;
1555
1556 qtnf_bus_lock(mac->bus);
1557
1558 ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code,
1559 sizeof(*resp), &response_size);
1560
1561 if (unlikely(ret))
1562 goto out;
1563
1564 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
1565 pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code);
1566 ret = -EFAULT;
1567 goto out;
1568 }
1569
1570 resp = (struct qlink_resp_phy_params *)resp_skb->data;
1571 ret = qtnf_cmd_resp_proc_phy_params(mac, resp->info, response_size);
1572
1573out:
1574 qtnf_bus_unlock(mac->bus);
1575 consume_skb(resp_skb);
1576
1577 return ret;
1578}
1579
1580int qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed)
1581{
1582 struct wiphy *wiphy = priv_to_wiphy(mac);
1583 struct sk_buff *cmd_skb;
1584 u16 res_code = QLINK_CMD_RESULT_OK;
1585 int ret = 0;
1586
1587 cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0,
1588 QLINK_CMD_PHY_PARAMS_SET,
1589 sizeof(struct qlink_cmd));
1590 if (!cmd_skb)
1591 return -ENOMEM;
1592
1593 qtnf_bus_lock(mac->bus);
1594
1595 if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
1596 qtnf_cmd_skb_put_tlv_u16(cmd_skb, QTN_TLV_ID_FRAG_THRESH,
1597 wiphy->frag_threshold);
1598 if (changed & WIPHY_PARAM_RTS_THRESHOLD)
1599 qtnf_cmd_skb_put_tlv_u16(cmd_skb, QTN_TLV_ID_RTS_THRESH,
1600 wiphy->rts_threshold);
1601 if (changed & WIPHY_PARAM_COVERAGE_CLASS)
1602 qtnf_cmd_skb_put_tlv_u8(cmd_skb, QTN_TLV_ID_COVERAGE_CLASS,
1603 wiphy->coverage_class);
1604
1605 ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code);
1606
1607 if (unlikely(ret))
1608 goto out;
1609
1610 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
1611 pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code);
1612 ret = -EFAULT;
1613 goto out;
1614 }
1615
1616out:
1617 qtnf_bus_unlock(mac->bus);
1618 return ret;
1619}
1620
1621int qtnf_cmd_send_init_fw(struct qtnf_bus *bus)
1622{
1623 struct sk_buff *cmd_skb;
1624 u16 res_code = QLINK_CMD_RESULT_OK;
1625 int ret = 0;
1626
1627 cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
1628 QLINK_CMD_FW_INIT,
1629 sizeof(struct qlink_cmd));
1630 if (unlikely(!cmd_skb))
1631 return -ENOMEM;
1632
1633 qtnf_bus_lock(bus);
1634
1635 ret = qtnf_cmd_send(bus, cmd_skb, &res_code);
1636
1637 if (unlikely(ret))
1638 goto out;
1639
1640 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
1641 pr_err("cmd exec failed: 0x%.4X\n", res_code);
1642 ret = -EFAULT;
1643 goto out;
1644 }
1645
1646out:
1647 qtnf_bus_unlock(bus);
1648 return ret;
1649}
1650
1651void qtnf_cmd_send_deinit_fw(struct qtnf_bus *bus)
1652{
1653 struct sk_buff *cmd_skb;
1654
1655 cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
1656 QLINK_CMD_FW_DEINIT,
1657 sizeof(struct qlink_cmd));
1658 if (!cmd_skb)
1659 return;
1660
1661 qtnf_bus_lock(bus);
1662
1663 qtnf_cmd_send(bus, cmd_skb, NULL);
1664
1665 qtnf_bus_unlock(bus);
1666}
1667
1668int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,
1669 const u8 *mac_addr, struct key_params *params)
1670{
1671 struct sk_buff *cmd_skb;
1672 struct qlink_cmd_add_key *cmd;
1673 u16 res_code = QLINK_CMD_RESULT_OK;
1674 int ret = 0;
1675
1676 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
1677 QLINK_CMD_ADD_KEY,
1678 sizeof(*cmd));
1679 if (unlikely(!cmd_skb))
1680 return -ENOMEM;
1681
1682 qtnf_bus_lock(vif->mac->bus);
1683
1684 cmd = (struct qlink_cmd_add_key *)cmd_skb->data;
1685
1686 if (mac_addr)
1687 ether_addr_copy(cmd->addr, mac_addr);
1688 else
1689 eth_broadcast_addr(cmd->addr);
1690
1691 cmd->cipher = cpu_to_le32(params->cipher);
1692 cmd->key_index = key_index;
1693 cmd->pairwise = pairwise;
1694
1695 if (params->key && params->key_len > 0)
1696 qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_KEY,
1697 params->key,
1698 params->key_len);
1699
1700 if (params->seq && params->seq_len > 0)
1701 qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_SEQ,
1702 params->seq,
1703 params->seq_len);
1704
1705 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
1706 if (unlikely(ret))
1707 goto out;
1708
1709 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
1710 pr_err("VIF%u.%u: CMD failed: %u\n",
1711 vif->mac->macid, vif->vifid, res_code);
1712 ret = -EFAULT;
1713 goto out;
1714 }
1715
1716out:
1717 qtnf_bus_unlock(vif->mac->bus);
1718 return ret;
1719}
1720
1721int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,
1722 const u8 *mac_addr)
1723{
1724 struct sk_buff *cmd_skb;
1725 struct qlink_cmd_del_key *cmd;
1726 u16 res_code = QLINK_CMD_RESULT_OK;
1727 int ret = 0;
1728
1729 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
1730 QLINK_CMD_DEL_KEY,
1731 sizeof(*cmd));
1732 if (unlikely(!cmd_skb))
1733 return -ENOMEM;
1734
1735 qtnf_bus_lock(vif->mac->bus);
1736
1737 cmd = (struct qlink_cmd_del_key *)cmd_skb->data;
1738
1739 if (mac_addr)
1740 ether_addr_copy(cmd->addr, mac_addr);
1741 else
1742 eth_broadcast_addr(cmd->addr);
1743
1744 cmd->key_index = key_index;
1745 cmd->pairwise = pairwise;
1746 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
1747 if (unlikely(ret))
1748 goto out;
1749
1750 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
1751 pr_err("VIF%u.%u: CMD failed: %u\n",
1752 vif->mac->macid, vif->vifid, res_code);
1753 ret = -EFAULT;
1754 goto out;
1755 }
1756
1757out:
1758 qtnf_bus_unlock(vif->mac->bus);
1759 return ret;
1760}
1761
1762int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index,
1763 bool unicast, bool multicast)
1764{
1765 struct sk_buff *cmd_skb;
1766 struct qlink_cmd_set_def_key *cmd;
1767 u16 res_code = QLINK_CMD_RESULT_OK;
1768 int ret = 0;
1769
1770 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
1771 QLINK_CMD_SET_DEFAULT_KEY,
1772 sizeof(*cmd));
1773 if (unlikely(!cmd_skb))
1774 return -ENOMEM;
1775
1776 qtnf_bus_lock(vif->mac->bus);
1777
1778 cmd = (struct qlink_cmd_set_def_key *)cmd_skb->data;
1779 cmd->key_index = key_index;
1780 cmd->unicast = unicast;
1781 cmd->multicast = multicast;
1782 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
1783 if (unlikely(ret))
1784 goto out;
1785
1786 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
1787 pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
1788 vif->vifid, res_code);
1789 ret = -EFAULT;
1790 goto out;
1791 }
1792
1793out:
1794 qtnf_bus_unlock(vif->mac->bus);
1795 return ret;
1796}
1797
1798int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index)
1799{
1800 struct sk_buff *cmd_skb;
1801 struct qlink_cmd_set_def_mgmt_key *cmd;
1802 u16 res_code = QLINK_CMD_RESULT_OK;
1803 int ret = 0;
1804
1805 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
1806 QLINK_CMD_SET_DEFAULT_MGMT_KEY,
1807 sizeof(*cmd));
1808 if (unlikely(!cmd_skb))
1809 return -ENOMEM;
1810
1811 qtnf_bus_lock(vif->mac->bus);
1812
1813 cmd = (struct qlink_cmd_set_def_mgmt_key *)cmd_skb->data;
1814 cmd->key_index = key_index;
1815 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
1816 if (unlikely(ret))
1817 goto out;
1818
1819 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
1820 pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
1821 vif->vifid, res_code);
1822 ret = -EFAULT;
1823 goto out;
1824 }
1825
1826out:
1827 qtnf_bus_unlock(vif->mac->bus);
1828 return ret;
1829}
1830
1831static u32 qtnf_encode_sta_flags(u32 flags)
1832{
1833 u32 code = 0;
1834
1835 if (flags & BIT(NL80211_STA_FLAG_AUTHORIZED))
1836 code |= QLINK_STA_FLAG_AUTHORIZED;
1837 if (flags & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
1838 code |= QLINK_STA_FLAG_SHORT_PREAMBLE;
1839 if (flags & BIT(NL80211_STA_FLAG_WME))
1840 code |= QLINK_STA_FLAG_WME;
1841 if (flags & BIT(NL80211_STA_FLAG_MFP))
1842 code |= QLINK_STA_FLAG_MFP;
1843 if (flags & BIT(NL80211_STA_FLAG_AUTHENTICATED))
1844 code |= QLINK_STA_FLAG_AUTHENTICATED;
1845 if (flags & BIT(NL80211_STA_FLAG_TDLS_PEER))
1846 code |= QLINK_STA_FLAG_TDLS_PEER;
1847 if (flags & BIT(NL80211_STA_FLAG_ASSOCIATED))
1848 code |= QLINK_STA_FLAG_ASSOCIATED;
1849 return code;
1850}
1851
1852int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac,
1853 struct station_parameters *params)
1854{
1855 struct sk_buff *cmd_skb;
1856 struct qlink_cmd_change_sta *cmd;
1857 u16 res_code = QLINK_CMD_RESULT_OK;
1858 int ret = 0;
1859
1860 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
1861 QLINK_CMD_CHANGE_STA,
1862 sizeof(*cmd));
1863 if (unlikely(!cmd_skb))
1864 return -ENOMEM;
1865
1866 qtnf_bus_lock(vif->mac->bus);
1867
1868 cmd = (struct qlink_cmd_change_sta *)cmd_skb->data;
1869 ether_addr_copy(cmd->sta_addr, mac);
Sergey Matyukevich805b28c2017-07-28 02:06:54 +03001870
1871 switch (vif->wdev.iftype) {
1872 case NL80211_IFTYPE_AP:
1873 cmd->if_type = cpu_to_le16(QLINK_IFTYPE_AP);
1874 cmd->sta_flags_mask = cpu_to_le32(qtnf_encode_sta_flags(
1875 params->sta_flags_mask));
1876 cmd->sta_flags_set = cpu_to_le32(qtnf_encode_sta_flags(
1877 params->sta_flags_set));
1878 break;
1879 case NL80211_IFTYPE_STATION:
1880 cmd->if_type = cpu_to_le16(QLINK_IFTYPE_STATION);
1881 cmd->sta_flags_mask = cpu_to_le32(qtnf_encode_sta_flags(
1882 params->sta_flags_mask));
1883 cmd->sta_flags_set = cpu_to_le32(qtnf_encode_sta_flags(
1884 params->sta_flags_set));
1885 break;
1886 default:
1887 pr_err("unsupported iftype %d\n", vif->wdev.iftype);
1888 ret = -EINVAL;
1889 goto out;
1890 }
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07001891
1892 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
1893 if (unlikely(ret))
1894 goto out;
1895
1896 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
1897 pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
1898 vif->vifid, res_code);
1899 ret = -EFAULT;
1900 goto out;
1901 }
1902
1903out:
1904 qtnf_bus_unlock(vif->mac->bus);
1905 return ret;
1906}
1907
1908int qtnf_cmd_send_del_sta(struct qtnf_vif *vif,
1909 struct station_del_parameters *params)
1910{
1911 struct sk_buff *cmd_skb;
1912 struct qlink_cmd_del_sta *cmd;
1913 u16 res_code = QLINK_CMD_RESULT_OK;
1914 int ret = 0;
1915
1916 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
1917 QLINK_CMD_DEL_STA,
1918 sizeof(*cmd));
1919 if (unlikely(!cmd_skb))
1920 return -ENOMEM;
1921
1922 qtnf_bus_lock(vif->mac->bus);
1923
1924 cmd = (struct qlink_cmd_del_sta *)cmd_skb->data;
1925
1926 if (params->mac)
1927 ether_addr_copy(cmd->sta_addr, params->mac);
1928 else
1929 eth_broadcast_addr(cmd->sta_addr); /* flush all stations */
1930
1931 cmd->subtype = params->subtype;
1932 cmd->reason_code = cpu_to_le16(params->reason_code);
1933
1934 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
1935 if (unlikely(ret))
1936 goto out;
1937
1938 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
1939 pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
1940 vif->vifid, res_code);
1941 ret = -EFAULT;
1942 goto out;
1943 }
1944
1945out:
1946 qtnf_bus_unlock(vif->mac->bus);
1947 return ret;
1948}
1949
1950int qtnf_cmd_send_scan(struct qtnf_wmac *mac)
1951{
1952 struct sk_buff *cmd_skb;
1953 u16 res_code = QLINK_CMD_RESULT_OK;
1954 struct ieee80211_channel *sc;
1955 struct cfg80211_scan_request *scan_req = mac->scan_req;
1956 struct qlink_tlv_channel *qchan;
1957 int n_channels;
1958 int count = 0;
1959 int ret;
1960 u32 flags;
1961
1962 if (scan_req->n_ssids > QTNF_MAX_SSID_LIST_LENGTH) {
1963 pr_err("MAC%u: too many SSIDs in scan request\n", mac->macid);
1964 return -EINVAL;
1965 }
1966
1967 cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
1968 QLINK_CMD_SCAN,
1969 sizeof(struct qlink_cmd));
1970 if (unlikely(!cmd_skb))
1971 return -ENOMEM;
1972
1973 qtnf_bus_lock(mac->bus);
1974
1975 if (scan_req->n_ssids != 0) {
1976 while (count < scan_req->n_ssids) {
1977 qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID,
1978 scan_req->ssids[count].ssid,
1979 scan_req->ssids[count].ssid_len);
1980 count++;
1981 }
1982 }
1983
1984 if (scan_req->ie_len != 0)
1985 qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_IE_SET,
1986 scan_req->ie,
1987 scan_req->ie_len);
1988
1989 if (scan_req->n_channels) {
1990 n_channels = scan_req->n_channels;
1991 count = 0;
1992
1993 while (n_channels != 0) {
1994 sc = scan_req->channels[count];
1995 if (sc->flags & IEEE80211_CHAN_DISABLED) {
1996 n_channels--;
1997 continue;
1998 }
1999
2000 pr_debug("MAC%u: scan chan=%d, freq=%d, flags=%#x\n",
2001 mac->macid, sc->hw_value, sc->center_freq,
2002 sc->flags);
Johannes Bergb080db52017-06-16 14:29:19 +02002003 qchan = skb_put_zero(cmd_skb, sizeof(*qchan));
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07002004 flags = 0;
2005
2006 qchan->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANNEL);
2007 qchan->hdr.len = cpu_to_le16(sizeof(*qchan) -
2008 sizeof(struct qlink_tlv_hdr));
2009 qchan->center_freq = cpu_to_le16(sc->center_freq);
2010 qchan->hw_value = cpu_to_le16(sc->hw_value);
2011
2012 if (sc->flags & IEEE80211_CHAN_NO_IR)
2013 flags |= QLINK_CHAN_NO_IR;
2014
2015 if (sc->flags & IEEE80211_CHAN_RADAR)
2016 flags |= QLINK_CHAN_RADAR;
2017
2018 qchan->flags = cpu_to_le32(flags);
2019 n_channels--;
2020 count++;
2021 }
2022 }
2023
2024 ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code);
2025
2026 if (unlikely(ret))
2027 goto out;
2028
2029 pr_debug("MAC%u: scan started\n", mac->macid);
2030
2031 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
2032 pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code);
2033 ret = -EFAULT;
2034 goto out;
2035 }
2036out:
2037 qtnf_bus_unlock(mac->bus);
2038 return ret;
2039}
2040
2041int qtnf_cmd_send_connect(struct qtnf_vif *vif,
2042 struct cfg80211_connect_params *sme)
2043{
2044 struct sk_buff *cmd_skb;
2045 struct qlink_cmd_connect *cmd;
2046 struct qtnf_bss_config *bss_cfg = &vif->bss_cfg;
2047 struct qlink_auth_encr aen;
2048 u16 res_code = QLINK_CMD_RESULT_OK;
2049 int ret;
2050 int i;
2051
2052 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
2053 QLINK_CMD_CONNECT,
2054 sizeof(*cmd));
2055 if (unlikely(!cmd_skb))
2056 return -ENOMEM;
2057
2058 qtnf_bus_lock(vif->mac->bus);
2059
2060 cmd = (struct qlink_cmd_connect *)cmd_skb->data;
2061
2062 ether_addr_copy(cmd->bssid, bss_cfg->bssid);
2063
Igor Mitsyanko96d4eaf2017-09-21 14:34:32 -07002064 if (sme->channel)
2065 cmd->channel = cpu_to_le16(sme->channel->hw_value);
2066 else
2067 cmd->channel = 0;
Igor Mitsyanko98f44cb2017-05-11 14:51:01 -07002068
2069 cmd->bg_scan_period = cpu_to_le16(bss_cfg->bg_scan_period);
2070
2071 memset(&aen, 0, sizeof(aen));
2072 aen.auth_type = bss_cfg->auth_type;
2073 aen.privacy = !!bss_cfg->privacy;
2074 aen.mfp = bss_cfg->mfp;
2075 aen.wpa_versions = cpu_to_le32(bss_cfg->crypto.wpa_versions);
2076 aen.cipher_group = cpu_to_le32(bss_cfg->crypto.cipher_group);
2077 aen.n_ciphers_pairwise = cpu_to_le32(
2078 bss_cfg->crypto.n_ciphers_pairwise);
2079
2080 for (i = 0; i < QLINK_MAX_NR_CIPHER_SUITES; i++)
2081 aen.ciphers_pairwise[i] = cpu_to_le32(
2082 bss_cfg->crypto.ciphers_pairwise[i]);
2083
2084 aen.n_akm_suites = cpu_to_le32(bss_cfg->crypto.n_akm_suites);
2085
2086 for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++)
2087 aen.akm_suites[i] = cpu_to_le32(
2088 bss_cfg->crypto.akm_suites[i]);
2089
2090 aen.control_port = bss_cfg->crypto.control_port;
2091 aen.control_port_no_encrypt =
2092 bss_cfg->crypto.control_port_no_encrypt;
2093 aen.control_port_ethertype = cpu_to_le16(be16_to_cpu(
2094 bss_cfg->crypto.control_port_ethertype));
2095
2096 qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, bss_cfg->ssid,
2097 bss_cfg->ssid_len);
2098 qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_CRYPTO, (u8 *)&aen,
2099 sizeof(aen));
2100
2101 if (sme->ie_len != 0)
2102 qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_IE_SET,
2103 sme->ie,
2104 sme->ie_len);
2105
2106 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
2107
2108 if (unlikely(ret))
2109 goto out;
2110
2111 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
2112 pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
2113 vif->vifid, res_code);
2114 ret = -EFAULT;
2115 goto out;
2116 }
2117out:
2118 qtnf_bus_unlock(vif->mac->bus);
2119 return ret;
2120}
2121
2122int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code)
2123{
2124 struct sk_buff *cmd_skb;
2125 struct qlink_cmd_disconnect *cmd;
2126 u16 res_code = QLINK_CMD_RESULT_OK;
2127 int ret;
2128
2129 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
2130 QLINK_CMD_DISCONNECT,
2131 sizeof(*cmd));
2132 if (unlikely(!cmd_skb))
2133 return -ENOMEM;
2134
2135 qtnf_bus_lock(vif->mac->bus);
2136
2137 cmd = (struct qlink_cmd_disconnect *)cmd_skb->data;
2138 cmd->reason = cpu_to_le16(reason_code);
2139
2140 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
2141
2142 if (unlikely(ret))
2143 goto out;
2144
2145 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
2146 pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
2147 vif->vifid, res_code);
2148 ret = -EFAULT;
2149 goto out;
2150 }
2151out:
2152 qtnf_bus_unlock(vif->mac->bus);
2153 return ret;
2154}
2155
2156int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up)
2157{
2158 struct sk_buff *cmd_skb;
2159 struct qlink_cmd_updown *cmd;
2160 u16 res_code = QLINK_CMD_RESULT_OK;
2161 int ret;
2162
2163 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
2164 QLINK_CMD_UPDOWN_INTF,
2165 sizeof(*cmd));
2166 if (unlikely(!cmd_skb))
2167 return -ENOMEM;
2168
2169 cmd = (struct qlink_cmd_updown *)cmd_skb->data;
2170 cmd->if_up = !!up;
2171
2172 qtnf_bus_lock(vif->mac->bus);
2173
2174 ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
2175
2176 if (unlikely(ret))
2177 goto out;
2178
2179 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
2180 pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid,
2181 vif->vifid, res_code);
2182 ret = -EFAULT;
2183 goto out;
2184 }
2185out:
2186 qtnf_bus_unlock(vif->mac->bus);
2187 return ret;
2188}
Sergey Matyukevich4dd07d22017-07-28 02:06:43 +03002189
2190int qtnf_cmd_reg_notify(struct qtnf_bus *bus, struct regulatory_request *req)
2191{
2192 struct sk_buff *cmd_skb;
2193 int ret;
2194 u16 res_code;
2195 struct qlink_cmd_reg_notify *cmd;
2196
2197 cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
2198 QLINK_CMD_REG_NOTIFY,
2199 sizeof(*cmd));
2200 if (!cmd_skb)
2201 return -ENOMEM;
2202
2203 cmd = (struct qlink_cmd_reg_notify *)cmd_skb->data;
2204 cmd->alpha2[0] = req->alpha2[0];
2205 cmd->alpha2[1] = req->alpha2[1];
2206
2207 switch (req->initiator) {
2208 case NL80211_REGDOM_SET_BY_CORE:
2209 cmd->initiator = QLINK_REGDOM_SET_BY_CORE;
2210 break;
2211 case NL80211_REGDOM_SET_BY_USER:
2212 cmd->initiator = QLINK_REGDOM_SET_BY_USER;
2213 break;
2214 case NL80211_REGDOM_SET_BY_DRIVER:
2215 cmd->initiator = QLINK_REGDOM_SET_BY_DRIVER;
2216 break;
2217 case NL80211_REGDOM_SET_BY_COUNTRY_IE:
2218 cmd->initiator = QLINK_REGDOM_SET_BY_COUNTRY_IE;
2219 break;
2220 }
2221
2222 switch (req->user_reg_hint_type) {
2223 case NL80211_USER_REG_HINT_USER:
2224 cmd->user_reg_hint_type = QLINK_USER_REG_HINT_USER;
2225 break;
2226 case NL80211_USER_REG_HINT_CELL_BASE:
2227 cmd->user_reg_hint_type = QLINK_USER_REG_HINT_CELL_BASE;
2228 break;
2229 case NL80211_USER_REG_HINT_INDOOR:
2230 cmd->user_reg_hint_type = QLINK_USER_REG_HINT_INDOOR;
2231 break;
2232 }
2233
2234 qtnf_bus_lock(bus);
2235
2236 ret = qtnf_cmd_send(bus, cmd_skb, &res_code);
2237 if (ret)
2238 goto out;
2239
2240 switch (res_code) {
2241 case QLINK_CMD_RESULT_ENOTSUPP:
2242 pr_warn("reg update not supported\n");
2243 ret = -EOPNOTSUPP;
2244 break;
2245 case QLINK_CMD_RESULT_EALREADY:
2246 pr_info("regulatory domain is already set to %c%c",
2247 req->alpha2[0], req->alpha2[1]);
2248 ret = -EALREADY;
2249 break;
2250 case QLINK_CMD_RESULT_OK:
2251 ret = 0;
2252 break;
2253 default:
2254 ret = -EFAULT;
2255 break;
2256 }
2257
2258out:
2259 qtnf_bus_unlock(bus);
2260
2261 return ret;
2262}
Sergey Matyukevich7c04b432017-07-28 02:06:46 +03002263
2264int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel,
2265 struct qtnf_chan_stats *stats)
2266{
2267 struct sk_buff *cmd_skb, *resp_skb = NULL;
2268 struct qlink_cmd_get_chan_stats *cmd;
2269 struct qlink_resp_get_chan_stats *resp;
2270 size_t var_data_len;
2271 u16 res_code = QLINK_CMD_RESULT_OK;
2272 int ret = 0;
2273
2274 cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
2275 QLINK_CMD_CHAN_STATS,
2276 sizeof(*cmd));
2277 if (!cmd_skb)
2278 return -ENOMEM;
2279
2280 qtnf_bus_lock(mac->bus);
2281
2282 cmd = (struct qlink_cmd_get_chan_stats *)cmd_skb->data;
2283 cmd->channel = cpu_to_le16(channel);
2284
2285 ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code,
2286 sizeof(*resp), &var_data_len);
2287 if (unlikely(ret)) {
2288 qtnf_bus_unlock(mac->bus);
2289 return ret;
2290 }
2291
2292 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
2293 switch (res_code) {
2294 case QLINK_CMD_RESULT_ENOTFOUND:
2295 ret = -ENOENT;
2296 break;
2297 default:
2298 pr_err("cmd exec failed: 0x%.4X\n", res_code);
2299 ret = -EFAULT;
2300 break;
2301 }
2302 goto out;
2303 }
2304
2305 resp = (struct qlink_resp_get_chan_stats *)resp_skb->data;
2306 ret = qtnf_cmd_resp_proc_chan_stat_info(stats, resp->info,
2307 var_data_len);
2308
2309out:
2310 qtnf_bus_unlock(mac->bus);
2311 consume_skb(resp_skb);
2312 return ret;
2313}
Sergey Matyukevich978836952017-07-28 02:06:50 +03002314
Igor Mitsyanko8c015b92017-09-21 14:34:34 -07002315int qtnf_cmd_send_chan_switch(struct qtnf_vif *vif,
Sergey Matyukevich978836952017-07-28 02:06:50 +03002316 struct cfg80211_csa_settings *params)
2317{
Igor Mitsyanko8c015b92017-09-21 14:34:34 -07002318 struct qtnf_wmac *mac = vif->mac;
Sergey Matyukevich978836952017-07-28 02:06:50 +03002319 struct qlink_cmd_chan_switch *cmd;
2320 struct sk_buff *cmd_skb;
2321 u16 res_code = QLINK_CMD_RESULT_OK;
2322 int ret;
2323
Igor Mitsyanko8c015b92017-09-21 14:34:34 -07002324 cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, vif->vifid,
Sergey Matyukevich978836952017-07-28 02:06:50 +03002325 QLINK_CMD_CHAN_SWITCH,
2326 sizeof(*cmd));
2327
2328 if (unlikely(!cmd_skb))
2329 return -ENOMEM;
2330
2331 qtnf_bus_lock(mac->bus);
2332
2333 cmd = (struct qlink_cmd_chan_switch *)cmd_skb->data;
2334 cmd->channel = cpu_to_le16(params->chandef.chan->hw_value);
2335 cmd->radar_required = params->radar_required;
2336 cmd->block_tx = params->block_tx;
2337 cmd->beacon_count = params->count;
2338
2339 ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code);
2340
2341 if (unlikely(ret))
2342 goto out;
2343
2344 switch (res_code) {
2345 case QLINK_CMD_RESULT_OK:
Sergey Matyukevich978836952017-07-28 02:06:50 +03002346 ret = 0;
2347 break;
2348 case QLINK_CMD_RESULT_ENOTFOUND:
2349 ret = -ENOENT;
2350 break;
2351 case QLINK_CMD_RESULT_ENOTSUPP:
2352 ret = -EOPNOTSUPP;
2353 break;
2354 case QLINK_CMD_RESULT_EALREADY:
2355 ret = -EALREADY;
2356 break;
2357 case QLINK_CMD_RESULT_INVALID:
2358 default:
2359 ret = -EFAULT;
2360 break;
2361 }
2362
2363out:
2364 qtnf_bus_unlock(mac->bus);
2365 return ret;
2366}
Igor Mitsyanko9e5478b2017-09-21 14:34:31 -07002367
2368int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef)
2369{
2370 struct qtnf_bus *bus = vif->mac->bus;
2371 const struct qlink_resp_channel_get *resp;
2372 struct sk_buff *cmd_skb;
2373 struct sk_buff *resp_skb = NULL;
2374 u16 res_code = QLINK_CMD_RESULT_OK;
2375 int ret;
2376
2377 cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
2378 QLINK_CMD_CHAN_GET,
2379 sizeof(struct qlink_cmd));
2380 if (unlikely(!cmd_skb))
2381 return -ENOMEM;
2382
2383 qtnf_bus_lock(bus);
2384
2385 ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, &res_code,
2386 sizeof(*resp), NULL);
2387
2388 qtnf_bus_unlock(bus);
2389
2390 if (unlikely(ret))
2391 goto out;
2392
2393 if (unlikely(res_code != QLINK_CMD_RESULT_OK)) {
2394 ret = -ENODATA;
2395 goto out;
2396 }
2397
2398 resp = (const struct qlink_resp_channel_get *)resp_skb->data;
2399 qlink_chandef_q2cfg(priv_to_wiphy(vif->mac), &resp->chan, chdef);
2400
2401out:
2402 consume_skb(resp_skb);
2403 return ret;
2404}