1 /* 2 * Copyright (c) 2010-2011 Atheros Communications Inc. 3 * 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. 7 * 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. 15 */ 16 17 #include "testmode.h" 18 #include "debug.h" 19 20 #include <net/netlink.h> 21 22 enum ath6kl_tm_attr { 23 __ATH6KL_TM_ATTR_INVALID = 0, 24 ATH6KL_TM_ATTR_CMD = 1, 25 ATH6KL_TM_ATTR_DATA = 2, 26 27 /* keep last */ 28 __ATH6KL_TM_ATTR_AFTER_LAST, 29 ATH6KL_TM_ATTR_MAX = __ATH6KL_TM_ATTR_AFTER_LAST - 1, 30 }; 31 32 enum ath6kl_tm_cmd { 33 ATH6KL_TM_CMD_TCMD = 0, 34 ATH6KL_TM_CMD_RX_REPORT = 1, /* not used anymore */ 35 }; 36 37 #define ATH6KL_TM_DATA_MAX_LEN 5000 38 39 static const struct nla_policy ath6kl_tm_policy[ATH6KL_TM_ATTR_MAX + 1] = { 40 [ATH6KL_TM_ATTR_CMD] = { .type = NLA_U32 }, 41 [ATH6KL_TM_ATTR_DATA] = { .type = NLA_BINARY, 42 .len = ATH6KL_TM_DATA_MAX_LEN }, 43 }; 44 45 void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, size_t buf_len) 46 { 47 struct sk_buff *skb; 48 49 if (!buf || buf_len == 0) 50 return; 51 52 skb = cfg80211_testmode_alloc_event_skb(ar->wiphy, buf_len, GFP_KERNEL); 53 if (!skb) { 54 ath6kl_warn("failed to allocate testmode rx skb!\n"); 55 return; 56 } 57 NLA_PUT_U32(skb, ATH6KL_TM_ATTR_CMD, ATH6KL_TM_CMD_TCMD); 58 NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, buf_len, buf); 59 cfg80211_testmode_event(skb, GFP_KERNEL); 60 return; 61 62 nla_put_failure: 63 kfree_skb(skb); 64 ath6kl_warn("nla_put failed on testmode rx skb!\n"); 65 } 66 67 int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) 68 { 69 struct ath6kl *ar = wiphy_priv(wiphy); 70 struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1]; 71 int err, buf_len; 72 void *buf; 73 74 err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len, 75 ath6kl_tm_policy); 76 if (err) 77 return err; 78 79 if (!tb[ATH6KL_TM_ATTR_CMD]) 80 return -EINVAL; 81 82 switch (nla_get_u32(tb[ATH6KL_TM_ATTR_CMD])) { 83 case ATH6KL_TM_CMD_TCMD: 84 if (!tb[ATH6KL_TM_ATTR_DATA]) 85 return -EINVAL; 86 87 buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]); 88 buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]); 89 90 ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len); 91 92 return 0; 93 94 break; 95 case ATH6KL_TM_CMD_RX_REPORT: 96 default: 97 return -EOPNOTSUPP; 98 } 99 } 100