1  /*
2   * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved.
3   * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4   *
5   * Permission to use, copy, modify, and/or distribute this software for
6   * any purpose with or without fee is hereby granted, provided that the
7   * above copyright notice and this permission notice appear in all
8   * copies.
9   *
10   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11   * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12   * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13   * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14   * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15   * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16   * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17   * PERFORMANCE OF THIS SOFTWARE.
18   */
19  
20  /**
21   * DOC: wlan_hdd_concurrency_matrix.c
22   *
23   * WLAN concurrency matrix functions
24   *
25   */
26  
27  #include "osif_sync.h"
28  #include <wlan_hdd_includes.h>
29  #include <linux/netdevice.h>
30  #include <linux/skbuff.h>
31  #include <linux/etherdevice.h>
32  #include <linux/if_ether.h>
33  #include <wlan_hdd_concurrency_matrix.h>
34  
35  #define CDS_MAX_FEATURE_SET   8
36  #define MAX_CONCURRENT_MATRIX \
37  	QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX
38  #define MATRIX_CONFIG_PARAM_SET_SIZE_MAX \
39  	QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_CONFIG_PARAM_SET_SIZE_MAX
40  
41  const struct nla_policy
42  wlan_hdd_get_concurrency_matrix_policy[MAX_CONCURRENT_MATRIX + 1] = {
43  	[MATRIX_CONFIG_PARAM_SET_SIZE_MAX] = {.type = NLA_U32},
44  };
45  
46  /**
47   * __wlan_hdd_cfg80211_get_concurrency_matrix() - to retrieve concurrency matrix
48   * @wiphy: pointer phy adapter
49   * @wdev: pointer to wireless device structure
50   * @data: pointer to data buffer
51   * @data_len: length of data
52   *
53   * This routine will give concurrency matrix
54   *
55   * Return: int status code
56   */
57  static int
__wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)58  __wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy,
59  					   struct wireless_dev *wdev,
60  					   const void *data,
61  					   int data_len)
62  {
63  	uint32_t feature_set_matrix[CDS_MAX_FEATURE_SET] = {0};
64  	uint8_t i, feature_sets, max_feature_sets;
65  	struct nlattr *tb[MAX_CONCURRENT_MATRIX + 1];
66  	struct sk_buff *reply_skb;
67  	uint32_t skb_len = NLMSG_HDRLEN;
68  	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
69  	int ret;
70  
71  	hdd_enter_dev(wdev->netdev);
72  
73  	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
74  		hdd_err("Command not allowed in FTM mode");
75  		return -EPERM;
76  	}
77  
78  	ret = wlan_hdd_validate_context(hdd_ctx);
79  	if (ret)
80  		return ret;
81  
82  	if (wlan_cfg80211_nla_parse(tb, MAX_CONCURRENT_MATRIX, data, data_len,
83  				    wlan_hdd_get_concurrency_matrix_policy)) {
84  		hdd_err("Invalid ATTR");
85  		return -EINVAL;
86  	}
87  
88  	/* Parse and fetch max feature set */
89  	if (!tb[MATRIX_CONFIG_PARAM_SET_SIZE_MAX]) {
90  		hdd_err("Attr max feature set size failed");
91  		return -EINVAL;
92  	}
93  	max_feature_sets = nla_get_u32(tb[MATRIX_CONFIG_PARAM_SET_SIZE_MAX]);
94  	hdd_debug("Max feature set size: %d", max_feature_sets);
95  
96  	/* Fill feature combination matrix */
97  	feature_sets = 0;
98  	feature_set_matrix[feature_sets++] = WIFI_FEATURE_INFRA |
99  						WIFI_FEATURE_P2P;
100  	feature_set_matrix[feature_sets++] = WIFI_FEATURE_INFRA |
101  						WIFI_FEATURE_NAN;
102  	/* Add more feature combinations here */
103  
104  	feature_sets = QDF_MIN(feature_sets, max_feature_sets);
105  	hdd_debug("Number of feature sets: %d", feature_sets);
106  	hdd_debug("Feature set matrix");
107  	for (i = 0; i < feature_sets; i++)
108  		hdd_debug("[%d] 0x%02X", i, feature_set_matrix[i]);
109  
110  	skb_len += sizeof(u32) + sizeof(u32) * feature_sets;
111  	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len);
112  	if (!reply_skb) {
113  		hdd_err("Feature set matrix: buffer alloc fail");
114  		return -ENOMEM;
115  	}
116  
117  	if (nla_put_u32(reply_skb,
118  		QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET_SIZE,
119  		feature_sets) ||
120  	    nla_put(reply_skb,
121  		    QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET,
122  		    sizeof(u32) * feature_sets,
123  		    feature_set_matrix)) {
124  		hdd_err("nla put fail");
125  		wlan_cfg80211_vendor_free_skb(reply_skb);
126  		return -EINVAL;
127  	}
128  	return wlan_cfg80211_vendor_cmd_reply(reply_skb);
129  }
130  
131  #undef MAX_CONCURRENT_MATRIX
132  #undef MATRIX_CONFIG_PARAM_SET_SIZE_MAX
133  
wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)134  int wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy,
135  					     struct wireless_dev *wdev,
136  					     const void *data,
137  					     int data_len)
138  {
139  	struct osif_psoc_sync *psoc_sync;
140  	int errno;
141  
142  	errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
143  	if (errno)
144  		return errno;
145  
146  	errno = __wlan_hdd_cfg80211_get_concurrency_matrix(wiphy, wdev,
147  							   data, data_len);
148  
149  	osif_psoc_sync_op_stop(psoc_sync);
150  
151  	return errno;
152  }
153  
154