linux/drivers/net/wireless/ath/wcn36xx/testmode.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
   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 ANY
  11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#include <net/netlink.h>
  18#include <linux/firmware.h>
  19#include <net/cfg80211.h>
  20#include "wcn36xx.h"
  21
  22#include "testmode.h"
  23#include "testmode_i.h"
  24#include "hal.h"
  25#include "smd.h"
  26
  27static const struct nla_policy wcn36xx_tm_policy[WCN36XX_TM_ATTR_MAX + 1] = {
  28        [WCN36XX_TM_ATTR_CMD] = { .type = NLA_U16 },
  29        [WCN36XX_TM_ATTR_DATA] = { .type = NLA_BINARY,
  30        .len = WCN36XX_TM_DATA_MAX_LEN },
  31};
  32
  33struct build_release_number {
  34        u16 drv_major;
  35        u16 drv_minor;
  36        u16 drv_patch;
  37        u16 drv_build;
  38        u16 ptt_max;
  39        u16 ptt_min;
  40        u16 fw_ver;
  41} __packed;
  42
  43static int wcn36xx_tm_cmd_ptt(struct wcn36xx *wcn, struct ieee80211_vif *vif,
  44                              struct nlattr *tb[])
  45{
  46        int ret = 0, buf_len;
  47        void *buf;
  48        struct ftm_rsp_msg *msg, *rsp = NULL;
  49        struct sk_buff *skb;
  50
  51        if (!tb[WCN36XX_TM_ATTR_DATA])
  52                return -EINVAL;
  53
  54        buf = nla_data(tb[WCN36XX_TM_ATTR_DATA]);
  55        buf_len = nla_len(tb[WCN36XX_TM_ATTR_DATA]);
  56        msg = (struct ftm_rsp_msg *)buf;
  57
  58        wcn36xx_dbg(WCN36XX_DBG_TESTMODE,
  59                    "testmode cmd wmi msg_id 0x%04X msg_len %d buf %pK buf_len %d\n",
  60                   msg->msg_id, msg->msg_body_length,
  61                   buf, buf_len);
  62
  63        wcn36xx_dbg_dump(WCN36XX_DBG_TESTMODE_DUMP, "REQ ", buf, buf_len);
  64
  65        if (msg->msg_id == MSG_GET_BUILD_RELEASE_NUMBER) {
  66                struct build_release_number *body =
  67                                (struct build_release_number *)
  68                                msg->msg_response;
  69
  70                body->drv_major = wcn->fw_major;
  71                body->drv_minor = wcn->fw_minor;
  72                body->drv_patch = wcn->fw_version;
  73                body->drv_build = wcn->fw_revision;
  74                body->ptt_max = 10;
  75                body->ptt_min = 0;
  76
  77                rsp = msg;
  78                rsp->resp_status = 0;
  79        } else {
  80                wcn36xx_dbg(WCN36XX_DBG_TESTMODE,
  81                            "PPT Request >> HAL size %d\n",
  82                                msg->msg_body_length);
  83
  84                msg->resp_status = wcn36xx_smd_process_ptt_msg(wcn, vif, msg,
  85                                                               msg->msg_body_length, (void *)(&rsp));
  86
  87                wcn36xx_dbg(WCN36XX_DBG_TESTMODE,
  88                            "Response status = %d\n",
  89                                msg->resp_status);
  90                if (rsp)
  91                        wcn36xx_dbg(WCN36XX_DBG_TESTMODE,
  92                                    "PPT Response << HAL size %d\n",
  93                                        rsp->msg_body_length);
  94        }
  95
  96        if (!rsp) {
  97                rsp = msg;
  98                wcn36xx_warn("No response! Echoing request with response status %d\n",
  99                             rsp->resp_status);
 100        }
 101        wcn36xx_dbg_dump(WCN36XX_DBG_TESTMODE_DUMP, "RSP ",
 102                         rsp, rsp->msg_body_length);
 103
 104        skb = cfg80211_testmode_alloc_reply_skb(wcn->hw->wiphy,
 105                                                nla_total_size(msg->msg_body_length));
 106        if (!skb) {
 107                ret = -ENOMEM;
 108                goto out;
 109        }
 110
 111        ret = nla_put(skb, WCN36XX_TM_ATTR_DATA, rsp->msg_body_length, rsp);
 112        if (ret) {
 113                kfree_skb(skb);
 114                goto out;
 115        }
 116
 117        ret = cfg80211_testmode_reply(skb);
 118
 119out:
 120        if (rsp != msg)
 121                kfree(rsp);
 122
 123        return ret;
 124}
 125
 126int wcn36xx_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 127                   void *data, int len)
 128{
 129        struct wcn36xx *wcn = hw->priv;
 130        struct nlattr *tb[WCN36XX_TM_ATTR_MAX + 1];
 131        int ret = 0;
 132        unsigned short attr;
 133
 134        wcn36xx_dbg_dump(WCN36XX_DBG_TESTMODE_DUMP, "Data:", data, len);
 135        ret = nla_parse(tb, WCN36XX_TM_ATTR_MAX, data, len,
 136                        wcn36xx_tm_policy, NULL);
 137        if (ret)
 138                return ret;
 139
 140        if (!tb[WCN36XX_TM_ATTR_CMD])
 141                return -EINVAL;
 142
 143        attr = nla_get_u16(tb[WCN36XX_TM_ATTR_CMD]);
 144
 145        if (attr != WCN36XX_TM_CMD_PTT)
 146                return -EOPNOTSUPP;
 147
 148        return wcn36xx_tm_cmd_ptt(wcn, vif, tb);
 149}
 150