summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CORE/HDD/inc/wlan_hdd_cfg80211.h39
-rw-r--r--CORE/HDD/src/wlan_hdd_cfg80211.c243
2 files changed, 282 insertions, 0 deletions
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index 5c9808f8723d..eb7adad18a17 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -176,6 +176,9 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX = 42,
QCA_NL80211_VENDOR_SUBCMD_APFIND = 52,
+ /* OCB Set Schedule */
+ QCA_NL80211_VENDOR_SUBCMD_OCB_SET_SCHED = 53,
+
QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54,
};
@@ -854,6 +857,42 @@ enum qca_wlan_vendor_attr_get_concurrency_matrix {
QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_AFTER_LAST - 1,
};
+/* OCB Commands */
+enum qca_wlan_vendor_attr_ocb_set_sched
+{
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_INVALID = 0,
+
+ /* Number of channels in schedule */
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_NUM_CHANS,
+
+ /* Attribute for nested array of channel attributes */
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN,
+
+ /* Attributes for each channel */
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_IDX,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_FREQ,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_TX_PWR,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_TX_RATE,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_DUR,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_START_GUARD_INT,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_END_GUARD_INT,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_NUM_QOS,
+
+ /* Attribute for nested array of QoS params*/
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM,
+
+ /* Attributes for each QoS Access Category */
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_AC,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_AIFSN,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_CWMIN,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_CWMAX,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_MAX =
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_AFTER_LAST - 1,
+};
+
/* Feature defines */
#define WIFI_FEATURE_INFRA 0x0001 /* Basic infrastructure mode */
#define WIFI_FEATURE_INFRA_5G 0x0002 /* Support for 5 GHz Band */
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 16aba7134411..63a35cda5ae9 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -4622,6 +4622,241 @@ out:
}
#endif
+static const struct
+nla_policy
+qca_wlan_vendor_ocb_set_sched_policy[
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_MAX + 1] =
+{
+ [QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_NUM_CHANS] =
+ { .type = NLA_U32 },
+
+ /* Attributes for each channel */
+ [QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_IDX] =
+ { .type = NLA_U32 },
+ [QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_FREQ] =
+ { .type = NLA_U32 },
+ [QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_TX_PWR] =
+ { .type = NLA_U32 },
+ [QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_TX_RATE] =
+ { .type = NLA_U32 },
+ [QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_DUR] =
+ { .type = NLA_U32 },
+ [QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_START_GUARD_INT] =
+ { .type = NLA_U32 },
+ [QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_END_GUARD_INT] =
+ { .type = NLA_U32 },
+ [QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_NUM_QOS] =
+ { .type = NLA_U32 },
+
+ /* Attributes for QoS Params */
+ [QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_AC] =
+ { .type = NLA_U8 },
+ [QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_AIFSN] =
+ { .type = NLA_U8 },
+ [QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_CWMIN] =
+ { .type = NLA_U8 },
+ [QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_CWMAX] =
+ { .type = NLA_U8 },
+};
+
+static int wlan_hdd_cfg80211_ocb_set_schedule(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data,
+ int data_len)
+{
+ hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+ struct net_device *dev = wdev->netdev;
+ hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_MAX + 1];
+ struct nlattr *channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_MAX + 1];
+ struct nlattr *qos_param[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_MAX + 1];
+ struct nlattr *channels;
+ struct nlattr *qos_params;
+ int status;
+ sir_ocb_set_sched_request_t *sched_req = NULL;
+ sir_ocb_sched_t *sched = NULL;
+ int rem1, rem2;
+ int chan_idx;
+ int ac;
+ int rc = -EINVAL;
+
+ status = wlan_hdd_validate_context(hdd_ctx);
+ if (0 != status) {
+ hddLog(LOGE, FL("HDD context is not valid"));
+ return -EINVAL;
+ }
+
+ if (adapter->device_mode != WLAN_HDD_OCB) {
+ hddLog(LOGE, FL("Device not in OCB mode!"));
+ return -EINVAL;
+ }
+
+ /* Parse the netlink message */
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_MAX,
+ data,
+ data_len, qca_wlan_vendor_ocb_set_sched_policy)) {
+ hddLog(LOGE, FL("OCB_SET_SCHEDULE_MAX is not present"));
+ return -EINVAL;
+ }
+
+ sched_req = vos_mem_malloc(sizeof(*sched_req));
+ if (sched_req == NULL) {
+ hddLog(LOGE, FL("Unable to allocate memory!"));
+ return -ENOMEM;
+
+ }
+ vos_mem_set((void *)sched_req, sizeof(*sched_req), 0);
+
+ sched_req->session_id = adapter->sessionId;
+ sched = &sched_req->sched;
+
+ /* Get the number of channels in schedule */
+ if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_NUM_CHANS]) {
+ hddLog(LOGE, FL("NUM_CHANS is not present"));
+ goto fail;
+ }
+
+ sched->num_channels = nla_get_u32(
+ tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_NUM_CHANS]);
+
+ /* Get the parameters for each channel in schedule */
+ if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN]) {
+ hddLog(LOGE, FL("CHAN not present"));
+ goto fail;
+ }
+
+ nla_for_each_nested(channels,
+ tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN],
+ rem1) {
+ if (nla_parse(channel,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_MAX,
+ nla_data(channels), nla_len(channels), NULL)) {
+ hddLog(LOGE, FL("nla_parse failed"));
+ goto fail;
+ }
+
+ /* Parse and fetch parameters for each channel */
+ /* Channel index */
+ if (!channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_IDX]) {
+ hddLog(LOGE, FL("CHAN_IDX not present"));
+ goto fail;
+ }
+ chan_idx = nla_get_u32(
+ channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_IDX]);
+
+ /* Channel Number */
+ if (!channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_FREQ]) {
+ hddLog(LOGE, FL("CHAN_FREQ not present"));
+ goto fail;
+ }
+ sched->channels[chan_idx].chan_freq = nla_get_u32(
+ channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_FREQ]);
+
+ /* TX Power */
+ if (!channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_TX_PWR]) {
+ hddLog(LOGE, FL("CHAN_TX_PWR not present"));
+ goto fail;
+ }
+ sched->channels[chan_idx].tx_power = nla_get_u32(
+ channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_TX_PWR]);
+
+ /* TX Rate */
+ if (!channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_TX_RATE]) {
+ hddLog(LOGE, FL("CHAN_TX_RATE not present"));
+ goto fail;
+ }
+ sched->channels[chan_idx].tx_rate = nla_get_u32(
+ channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_TX_RATE]);
+
+ /* Duration */
+ if (!channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_DUR]) {
+ hddLog(LOGE, FL("DUR not present"));
+ goto fail;
+ }
+ sched->channels[chan_idx].duration = nla_get_u32(
+ channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_DUR]);
+
+ /* Start Guard Interval */
+ if (!channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_START_GUARD_INT]) {
+ hddLog(LOGE, FL("START_GUARD_INT not present"));
+ goto fail;
+ }
+ sched->channels[chan_idx].start_guard_interval = nla_get_u32(
+ channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_START_GUARD_INT]);
+
+ /* End Guard Interval */
+ if (!channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_END_GUARD_INT]) {
+ hddLog(LOGE, FL("END_GUARD_INT not present"));
+ goto fail;
+ }
+ sched->channels[chan_idx].end_guard_interval = nla_get_u32(
+ channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_END_GUARD_INT]);
+
+ /* QoS Params */
+ if (!channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM]) {
+ hddLog(LOGE, FL("QOS_PARAM not present"));
+ goto fail;
+ }
+
+ nla_for_each_nested(qos_params,
+ channel[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM],
+ rem2) {
+ if (nla_parse(qos_param,
+ QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_MAX,
+ nla_data(qos_params), nla_len(qos_params), NULL)) {
+ hddLog(LOGE, FL("nla_parse failed"));
+ goto fail;
+ }
+
+ /* Access Category Index */
+ if (!qos_param[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_AC]) {
+ hddLog(LOGE, FL("QOS_PARAM_AC not present"));
+ goto fail;
+ }
+ ac = nla_get_u8(
+ qos_param[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_AC]);
+ if (ac >= NUM_AC) {
+ hddLog(LOGE, FL("QOS_PARAM_AIFSN is out of range"));
+ goto fail;
+ }
+
+ /* AIFSN */
+ if (!qos_param[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_AIFSN]) {
+ hddLog(LOGE, FL("QOS_PARAM_AIFSN not present"));
+ goto fail;
+ }
+ sched->channels[chan_idx].qos_params[ac].aifsn = nla_get_u8(
+ qos_param[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_AIFSN]);
+
+ /* CWMIN */
+ if (!qos_param[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_CWMIN]) {
+ hddLog(LOGE, FL("QOS_PARAM_CWMIN not present"));
+ goto fail;
+ }
+ sched->channels[chan_idx].qos_params[ac].cwmin = nla_get_u8(
+ qos_param[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_CWMIN]);
+
+ /* CWMAX */
+ if (!qos_param[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_CWMAX]) {
+ hddLog(LOGE, FL("QOS_PARAM_CWMAX not present"));
+ goto fail;
+ }
+ sched->channels[chan_idx].qos_params[ac].aifsn = nla_get_u8(
+ qos_param[QCA_WLAN_VENDOR_ATTR_OCB_SET_SCHED_CHAN_QOS_PARAM_CWMAX]);
+ }
+ }
+
+ /* TODO-OCB: Refactor common code path from WEXT and use here */
+
+ rc = 0;
+
+fail:
+ if (sched_req) {
+ vos_mem_free(sched_req);
+ }
+ return rc;
+}
+
const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] =
{
{
@@ -4830,6 +5065,14 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] =
.doit = (void *)wlan_hdd_cfg80211_do_acs
},
#endif
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_SET_SCHED,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = (void *)wlan_hdd_cfg80211_ocb_set_schedule
+ },
};