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