2 * Copyright (c) 2010-2011 Atheros Communications Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <net/netlink.h>
22 __ATH6KL_TM_ATTR_INVALID
= 0,
23 ATH6KL_TM_ATTR_CMD
= 1,
24 ATH6KL_TM_ATTR_DATA
= 2,
27 __ATH6KL_TM_ATTR_AFTER_LAST
,
28 ATH6KL_TM_ATTR_MAX
= __ATH6KL_TM_ATTR_AFTER_LAST
- 1,
32 ATH6KL_TM_CMD_TCMD
= 0,
33 ATH6KL_TM_CMD_RX_REPORT
= 1,
36 #define ATH6KL_TM_DATA_MAX_LEN 5000
38 static const struct nla_policy ath6kl_tm_policy
[ATH6KL_TM_ATTR_MAX
+ 1] = {
39 [ATH6KL_TM_ATTR_CMD
] = { .type
= NLA_U32
},
40 [ATH6KL_TM_ATTR_DATA
] = { .type
= NLA_BINARY
,
41 .len
= ATH6KL_TM_DATA_MAX_LEN
},
44 void ath6kl_tm_rx_report_event(struct ath6kl
*ar
, void *buf
, size_t buf_len
)
46 if (down_interruptible(&ar
->sem
))
49 kfree(ar
->tm
.rx_report
);
51 ar
->tm
.rx_report
= kmemdup(buf
, buf_len
, GFP_KERNEL
);
52 ar
->tm
.rx_report_len
= buf_len
;
56 wake_up(&ar
->event_wq
);
59 static int ath6kl_tm_rx_report(struct ath6kl
*ar
, void *buf
, size_t buf_len
,
65 if (down_interruptible(&ar
->sem
))
68 if (!test_bit(WMI_READY
, &ar
->flag
)) {
73 if (test_bit(DESTROY_IN_PROGRESS
, &ar
->flag
)) {
78 if (ath6kl_wmi_test_cmd(ar
->wmi
, buf
, buf_len
) < 0) {
83 left
= wait_event_interruptible_timeout(ar
->event_wq
,
84 ar
->tm
.rx_report
!= NULL
,
90 } else if (left
< 0) {
95 if (ar
->tm
.rx_report
== NULL
|| ar
->tm
.rx_report_len
== 0) {
100 NLA_PUT(skb
, ATH6KL_TM_ATTR_DATA
, ar
->tm
.rx_report_len
,
103 kfree(ar
->tm
.rx_report
);
104 ar
->tm
.rx_report
= NULL
;
116 int ath6kl_tm_cmd(struct wiphy
*wiphy
, void *data
, int len
)
118 struct ath6kl
*ar
= wiphy_priv(wiphy
);
119 struct nlattr
*tb
[ATH6KL_TM_ATTR_MAX
+ 1];
120 int err
, buf_len
, reply_len
;
124 err
= nla_parse(tb
, ATH6KL_TM_ATTR_MAX
, data
, len
,
129 if (!tb
[ATH6KL_TM_ATTR_CMD
])
132 switch (nla_get_u32(tb
[ATH6KL_TM_ATTR_CMD
])) {
133 case ATH6KL_TM_CMD_TCMD
:
134 if (!tb
[ATH6KL_TM_ATTR_DATA
])
137 buf
= nla_data(tb
[ATH6KL_TM_ATTR_DATA
]);
138 buf_len
= nla_len(tb
[ATH6KL_TM_ATTR_DATA
]);
140 ath6kl_wmi_test_cmd(ar
->wmi
, buf
, buf_len
);
145 case ATH6KL_TM_CMD_RX_REPORT
:
146 if (!tb
[ATH6KL_TM_ATTR_DATA
])
149 buf
= nla_data(tb
[ATH6KL_TM_ATTR_DATA
]);
150 buf_len
= nla_len(tb
[ATH6KL_TM_ATTR_DATA
]);
152 reply_len
= nla_total_size(ATH6KL_TM_DATA_MAX_LEN
);
153 skb
= cfg80211_testmode_alloc_reply_skb(wiphy
, reply_len
);
157 err
= ath6kl_tm_rx_report(ar
, buf
, buf_len
, skb
);
163 return cfg80211_testmode_reply(skb
);