linux/drivers/net/wireless/ti/wlcore/vendor_cmd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * This file is part of wlcore
   4 *
   5 * Copyright (C) 2014 Texas Instruments. All rights reserved.
   6 */
   7
   8#include <linux/pm_runtime.h>
   9
  10#include <net/mac80211.h>
  11#include <net/netlink.h>
  12
  13#include "wlcore.h"
  14#include "debug.h"
  15#include "hw_ops.h"
  16#include "vendor_cmd.h"
  17
  18static const
  19struct nla_policy wlcore_vendor_attr_policy[NUM_WLCORE_VENDOR_ATTR] = {
  20        [WLCORE_VENDOR_ATTR_FREQ]               = { .type = NLA_U32 },
  21        [WLCORE_VENDOR_ATTR_GROUP_ID]           = { .type = NLA_U32 },
  22        [WLCORE_VENDOR_ATTR_GROUP_KEY]          = { .type = NLA_BINARY,
  23                                                    .len = WLAN_MAX_KEY_LEN },
  24};
  25
  26static int
  27wlcore_vendor_cmd_smart_config_start(struct wiphy *wiphy,
  28                                     struct wireless_dev *wdev,
  29                                     const void *data, int data_len)
  30{
  31        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
  32        struct wl1271 *wl = hw->priv;
  33        struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR];
  34        int ret;
  35
  36        wl1271_debug(DEBUG_CMD, "vendor cmd smart config start");
  37
  38        if (!data)
  39                return -EINVAL;
  40
  41        ret = nla_parse_deprecated(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len,
  42                                   wlcore_vendor_attr_policy, NULL);
  43        if (ret)
  44                return ret;
  45
  46        if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID])
  47                return -EINVAL;
  48
  49        mutex_lock(&wl->mutex);
  50
  51        if (unlikely(wl->state != WLCORE_STATE_ON)) {
  52                ret = -EINVAL;
  53                goto out;
  54        }
  55
  56        ret = pm_runtime_get_sync(wl->dev);
  57        if (ret < 0) {
  58                pm_runtime_put_noidle(wl->dev);
  59                goto out;
  60        }
  61
  62        ret = wlcore_smart_config_start(wl,
  63                        nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]));
  64
  65        pm_runtime_mark_last_busy(wl->dev);
  66        pm_runtime_put_autosuspend(wl->dev);
  67out:
  68        mutex_unlock(&wl->mutex);
  69
  70        return ret;
  71}
  72
  73static int
  74wlcore_vendor_cmd_smart_config_stop(struct wiphy *wiphy,
  75                                    struct wireless_dev *wdev,
  76                                    const void *data, int data_len)
  77{
  78        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
  79        struct wl1271 *wl = hw->priv;
  80        int ret;
  81
  82        wl1271_debug(DEBUG_CMD, "testmode cmd smart config stop");
  83
  84        mutex_lock(&wl->mutex);
  85
  86        if (unlikely(wl->state != WLCORE_STATE_ON)) {
  87                ret = -EINVAL;
  88                goto out;
  89        }
  90
  91        ret = pm_runtime_get_sync(wl->dev);
  92        if (ret < 0) {
  93                pm_runtime_put_noidle(wl->dev);
  94                goto out;
  95        }
  96
  97        ret = wlcore_smart_config_stop(wl);
  98
  99        pm_runtime_mark_last_busy(wl->dev);
 100        pm_runtime_put_autosuspend(wl->dev);
 101out:
 102        mutex_unlock(&wl->mutex);
 103
 104        return ret;
 105}
 106
 107static int
 108wlcore_vendor_cmd_smart_config_set_group_key(struct wiphy *wiphy,
 109                                             struct wireless_dev *wdev,
 110                                             const void *data, int data_len)
 111{
 112        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
 113        struct wl1271 *wl = hw->priv;
 114        struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR];
 115        int ret;
 116
 117        wl1271_debug(DEBUG_CMD, "testmode cmd smart config set group key");
 118
 119        if (!data)
 120                return -EINVAL;
 121
 122        ret = nla_parse_deprecated(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len,
 123                                   wlcore_vendor_attr_policy, NULL);
 124        if (ret)
 125                return ret;
 126
 127        if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID] ||
 128            !tb[WLCORE_VENDOR_ATTR_GROUP_KEY])
 129                return -EINVAL;
 130
 131        mutex_lock(&wl->mutex);
 132
 133        if (unlikely(wl->state != WLCORE_STATE_ON)) {
 134                ret = -EINVAL;
 135                goto out;
 136        }
 137
 138        ret = pm_runtime_get_sync(wl->dev);
 139        if (ret < 0) {
 140                pm_runtime_put_noidle(wl->dev);
 141                goto out;
 142        }
 143
 144        ret = wlcore_smart_config_set_group_key(wl,
 145                        nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]),
 146                        nla_len(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]),
 147                        nla_data(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]));
 148
 149        pm_runtime_mark_last_busy(wl->dev);
 150        pm_runtime_put_autosuspend(wl->dev);
 151out:
 152        mutex_unlock(&wl->mutex);
 153
 154        return ret;
 155}
 156
 157static const struct wiphy_vendor_command wlcore_vendor_commands[] = {
 158        {
 159                .info = {
 160                        .vendor_id = TI_OUI,
 161                        .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_START,
 162                },
 163                .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
 164                         WIPHY_VENDOR_CMD_NEED_RUNNING,
 165                .doit = wlcore_vendor_cmd_smart_config_start,
 166                .policy = wlcore_vendor_attr_policy,
 167        },
 168        {
 169                .info = {
 170                        .vendor_id = TI_OUI,
 171                        .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_STOP,
 172                },
 173                .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
 174                         WIPHY_VENDOR_CMD_NEED_RUNNING,
 175                .doit = wlcore_vendor_cmd_smart_config_stop,
 176                .policy = wlcore_vendor_attr_policy,
 177        },
 178        {
 179                .info = {
 180                        .vendor_id = TI_OUI,
 181                        .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_SET_GROUP_KEY,
 182                },
 183                .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
 184                         WIPHY_VENDOR_CMD_NEED_RUNNING,
 185                .doit = wlcore_vendor_cmd_smart_config_set_group_key,
 186                .policy = wlcore_vendor_attr_policy,
 187        },
 188};
 189
 190static const struct nl80211_vendor_cmd_info wlcore_vendor_events[] = {
 191        {
 192                .vendor_id = TI_OUI,
 193                .subcmd = WLCORE_VENDOR_EVENT_SC_SYNC,
 194        },
 195        {
 196                .vendor_id = TI_OUI,
 197                .subcmd = WLCORE_VENDOR_EVENT_SC_DECODE,
 198        },
 199};
 200
 201void wlcore_set_vendor_commands(struct wiphy *wiphy)
 202{
 203        wiphy->vendor_commands = wlcore_vendor_commands;
 204        wiphy->n_vendor_commands = ARRAY_SIZE(wlcore_vendor_commands);
 205        wiphy->vendor_events = wlcore_vendor_events;
 206        wiphy->n_vendor_events = ARRAY_SIZE(wlcore_vendor_events);
 207}
 208