1 | /* |
2 | * Copyright (c) 2010-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011 Qualcomm Atheros, Inc. |
4 | * |
5 | * Permission to use, copy, modify, and/or distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above |
7 | * copyright notice and this permission notice appear in all copies. |
8 | * |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | */ |
17 | |
18 | #include "testmode.h" |
19 | #include "debug.h" |
20 | |
21 | #include <net/netlink.h> |
22 | |
23 | enum ath6kl_tm_attr { |
24 | __ATH6KL_TM_ATTR_INVALID = 0, |
25 | ATH6KL_TM_ATTR_CMD = 1, |
26 | ATH6KL_TM_ATTR_DATA = 2, |
27 | |
28 | /* keep last */ |
29 | __ATH6KL_TM_ATTR_AFTER_LAST, |
30 | ATH6KL_TM_ATTR_MAX = __ATH6KL_TM_ATTR_AFTER_LAST - 1, |
31 | }; |
32 | |
33 | enum ath6kl_tm_cmd { |
34 | ATH6KL_TM_CMD_TCMD = 0, |
35 | ATH6KL_TM_CMD_RX_REPORT = 1, /* not used anymore */ |
36 | }; |
37 | |
38 | #define ATH6KL_TM_DATA_MAX_LEN 5000 |
39 | |
40 | static const struct nla_policy ath6kl_tm_policy[ATH6KL_TM_ATTR_MAX + 1] = { |
41 | [ATH6KL_TM_ATTR_CMD] = { .type = NLA_U32 }, |
42 | [ATH6KL_TM_ATTR_DATA] = { .type = NLA_BINARY, |
43 | .len = ATH6KL_TM_DATA_MAX_LEN }, |
44 | }; |
45 | |
46 | void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, size_t buf_len) |
47 | { |
48 | struct sk_buff *skb; |
49 | |
50 | if (!buf || buf_len == 0) |
51 | return; |
52 | |
53 | skb = cfg80211_testmode_alloc_event_skb(wiphy: ar->wiphy, approxlen: buf_len, GFP_KERNEL); |
54 | if (!skb) { |
55 | ath6kl_warn(fmt: "failed to allocate testmode rx skb!\n" ); |
56 | return; |
57 | } |
58 | if (nla_put_u32(skb, attrtype: ATH6KL_TM_ATTR_CMD, value: ATH6KL_TM_CMD_TCMD) || |
59 | nla_put(skb, attrtype: ATH6KL_TM_ATTR_DATA, attrlen: buf_len, data: buf)) |
60 | goto nla_put_failure; |
61 | cfg80211_testmode_event(skb, GFP_KERNEL); |
62 | return; |
63 | |
64 | nla_put_failure: |
65 | kfree_skb(skb); |
66 | ath6kl_warn(fmt: "nla_put failed on testmode rx skb!\n" ); |
67 | } |
68 | |
69 | int ath6kl_tm_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, |
70 | void *data, int len) |
71 | { |
72 | struct ath6kl *ar = wiphy_priv(wiphy); |
73 | struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1]; |
74 | int err, buf_len; |
75 | void *buf; |
76 | |
77 | err = nla_parse_deprecated(tb, maxtype: ATH6KL_TM_ATTR_MAX, head: data, len, |
78 | policy: ath6kl_tm_policy, NULL); |
79 | if (err) |
80 | return err; |
81 | |
82 | if (!tb[ATH6KL_TM_ATTR_CMD]) |
83 | return -EINVAL; |
84 | |
85 | switch (nla_get_u32(nla: tb[ATH6KL_TM_ATTR_CMD])) { |
86 | case ATH6KL_TM_CMD_TCMD: |
87 | if (!tb[ATH6KL_TM_ATTR_DATA]) |
88 | return -EINVAL; |
89 | |
90 | buf = nla_data(nla: tb[ATH6KL_TM_ATTR_DATA]); |
91 | buf_len = nla_len(nla: tb[ATH6KL_TM_ATTR_DATA]); |
92 | |
93 | ath6kl_wmi_test_cmd(wmi: ar->wmi, buf, len: buf_len); |
94 | |
95 | return 0; |
96 | |
97 | case ATH6KL_TM_CMD_RX_REPORT: |
98 | default: |
99 | return -EOPNOTSUPP; |
100 | } |
101 | } |
102 | |