1 /*
2 * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2023 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_packet_filter.c
22 *
23 * WLAN Host Device Driver implementation
24 *
25 */
26
27 /* Include Files */
28 #include "wlan_hdd_packet_filter_api.h"
29 #include "wlan_hdd_packet_filter_rules.h"
30
31 int
hdd_enable_default_pkt_filters(struct hdd_context * hdd_ctx,uint8_t vdev_id)32 hdd_enable_default_pkt_filters(struct hdd_context *hdd_ctx, uint8_t vdev_id)
33 {
34 uint8_t filters = 0, i = 0, filter_id = 1;
35
36 if (hdd_ctx->user_configured_pkt_filter_rules) {
37 hdd_info("user has defined pkt filter run hence skipping default packet filter rule");
38 return 0;
39 }
40
41 filters = ucfg_pmo_get_pkt_filter_bitmap(hdd_ctx->psoc);
42
43 while (filters != 0) {
44 if (filters & 0x1) {
45 hdd_err("setting filter[%d], of id = %d",
46 i+1, filter_id);
47 packet_filter_default_rules[i].filter_id = filter_id;
48 wlan_hdd_set_filter(hdd_ctx,
49 &packet_filter_default_rules[i],
50 vdev_id);
51 filter_id++;
52 }
53 filters = filters >> 1;
54 i++;
55 }
56
57 return 0;
58 }
59
60 int
hdd_disable_default_pkt_filters(struct hdd_context * hdd_ctx,uint8_t vdev_id)61 hdd_disable_default_pkt_filters(struct hdd_context *hdd_ctx, uint8_t vdev_id)
62 {
63 uint8_t filters = 0, i = 0, filter_id = 1;
64 struct pkt_filter_cfg packet_filter_default_rules = {0};
65
66 if (hdd_ctx->user_configured_pkt_filter_rules) {
67 hdd_info("user has defined pkt filter run hence skipping default packet filter rule");
68 return 0;
69 }
70
71 filters = ucfg_pmo_get_pkt_filter_bitmap(hdd_ctx->psoc);
72
73 while (filters != 0) {
74 if (filters & 0x1) {
75 hdd_err("Clearing filter[%d], of id = %d",
76 i+1, filter_id);
77 packet_filter_default_rules.filter_action =
78 HDD_RCV_FILTER_CLEAR;
79 packet_filter_default_rules.filter_id = filter_id;
80 wlan_hdd_set_filter(hdd_ctx,
81 &packet_filter_default_rules,
82 vdev_id);
83 filter_id++;
84 }
85 filters = filters >> 1;
86 i++;
87 }
88
89 return 0;
90 }
91
wlan_hdd_set_filter(struct hdd_context * hdd_ctx,struct pkt_filter_cfg * request,uint8_t vdev_id)92 int wlan_hdd_set_filter(struct hdd_context *hdd_ctx,
93 struct pkt_filter_cfg *request,
94 uint8_t vdev_id)
95 {
96 struct pmo_rcv_pkt_fltr_cfg *pmo_set_pkt_fltr_req = NULL;
97 struct pmo_rcv_pkt_fltr_clear_param *pmo_clr_pkt_fltr_param = NULL;
98 int i = 0;
99 QDF_STATUS status = QDF_STATUS_SUCCESS;
100
101 if (!ucfg_pmo_is_pkt_filter_enabled(hdd_ctx->psoc)) {
102 hdd_warn("Packet filtering disabled in ini");
103 return 0;
104 }
105
106 /* Debug display of request components. */
107 hdd_debug("Packet Filter Request : FA %d params %d",
108 request->filter_action, request->num_params);
109
110 switch (request->filter_action) {
111 case HDD_RCV_FILTER_SET:
112 hdd_debug("Set Packet Filter Request for Id: %d",
113 request->filter_id);
114
115 pmo_set_pkt_fltr_req =
116 qdf_mem_malloc(sizeof(*pmo_set_pkt_fltr_req));
117 if (!pmo_set_pkt_fltr_req)
118 return QDF_STATUS_E_NOMEM;
119
120 pmo_set_pkt_fltr_req->filter_id = request->filter_id;
121 if (request->num_params >= HDD_MAX_CMP_PER_PACKET_FILTER) {
122 hdd_err("Number of Params exceed Max limit %d",
123 request->num_params);
124 status = QDF_STATUS_E_INVAL;
125 goto out;
126 }
127 pmo_set_pkt_fltr_req->num_params = request->num_params;
128 pmo_set_pkt_fltr_req->coalesce_time = 0;
129 pmo_set_pkt_fltr_req->filter_type = PMO_RCV_FILTER_TYPE_FILTER_PKT;
130 for (i = 0; i < request->num_params; i++) {
131 pmo_set_pkt_fltr_req->params_data[i].protocol_layer =
132 request->params_data[i].protocol_layer;
133 pmo_set_pkt_fltr_req->params_data[i].compare_flag =
134 request->params_data[i].compare_flag;
135 pmo_set_pkt_fltr_req->params_data[i].data_offset =
136 request->params_data[i].data_offset;
137 pmo_set_pkt_fltr_req->params_data[i].data_length =
138 request->params_data[i].data_length;
139 pmo_set_pkt_fltr_req->params_data[i].reserved = 0;
140
141 if (request->params_data[i].data_offset >
142 SIR_MAX_FILTER_TEST_DATA_OFFSET) {
143 hdd_err("Invalid data offset %u for param %d (max = %d)",
144 request->params_data[i].data_offset,
145 i,
146 SIR_MAX_FILTER_TEST_DATA_OFFSET);
147 status = QDF_STATUS_E_INVAL;
148 goto out;
149 }
150
151 if (request->params_data[i].data_length >
152 SIR_MAX_FILTER_TEST_DATA_LEN) {
153 hdd_err("Error invalid data length %d",
154 request->params_data[i].data_length);
155 status = QDF_STATUS_E_INVAL;
156 goto out;
157 }
158
159 hdd_debug("Proto %d Comp Flag %d Filter Type %d",
160 request->params_data[i].protocol_layer,
161 request->params_data[i].compare_flag,
162 pmo_set_pkt_fltr_req->filter_type);
163
164 hdd_debug("Data Offset %d Data Len %d",
165 request->params_data[i].data_offset,
166 request->params_data[i].data_length);
167
168 if (sizeof(
169 pmo_set_pkt_fltr_req->params_data[i].compare_data)
170 < (request->params_data[i].data_length)) {
171 hdd_err("Error invalid data length %d",
172 request->params_data[i].data_length);
173 status = QDF_STATUS_E_INVAL;
174 goto out;
175 }
176
177 memcpy(
178 &pmo_set_pkt_fltr_req->params_data[i].compare_data,
179 request->params_data[i].compare_data,
180 request->params_data[i].data_length);
181 memcpy(&pmo_set_pkt_fltr_req->params_data[i].data_mask,
182 request->params_data[i].data_mask,
183 request->params_data[i].data_length);
184
185 hdd_debug("CData %d CData %d CData %d CData %d CData %d CData %d",
186 request->params_data[i].compare_data[0],
187 request->params_data[i].compare_data[1],
188 request->params_data[i].compare_data[2],
189 request->params_data[i].compare_data[3],
190 request->params_data[i].compare_data[4],
191 request->params_data[i].compare_data[5]);
192
193 hdd_debug("MData %d MData %d MData %d MData %d MData %d MData %d",
194 request->params_data[i].data_mask[0],
195 request->params_data[i].data_mask[1],
196 request->params_data[i].data_mask[2],
197 request->params_data[i].data_mask[3],
198 request->params_data[i].data_mask[4],
199 request->params_data[i].data_mask[5]);
200 }
201
202
203 status= ucfg_pmo_set_pkt_filter(hdd_ctx->psoc,
204 pmo_set_pkt_fltr_req,
205 vdev_id);
206 if (QDF_IS_STATUS_ERROR(status)) {
207 hdd_err("Failure to execute Set Filter");
208 status = QDF_STATUS_E_INVAL;
209 goto out;
210 }
211
212 break;
213
214 case HDD_RCV_FILTER_CLEAR:
215 hdd_debug("Clear Packet Filter Request for Id: %d",
216 request->filter_id);
217
218 pmo_clr_pkt_fltr_param = qdf_mem_malloc(
219 sizeof(*pmo_clr_pkt_fltr_param));
220 if (!pmo_clr_pkt_fltr_param)
221 return QDF_STATUS_E_NOMEM;
222
223 pmo_clr_pkt_fltr_param->filter_id = request->filter_id;
224 status = ucfg_pmo_clear_pkt_filter(hdd_ctx->psoc,
225 pmo_clr_pkt_fltr_param,
226 vdev_id);
227 if (QDF_IS_STATUS_ERROR(status)) {
228 hdd_err("Failure to execute Clear Filter");
229 status = QDF_STATUS_E_INVAL;
230 goto out;
231 }
232 break;
233
234 default:
235 hdd_err("Packet Filter Request: Invalid %d",
236 request->filter_action);
237 return -EINVAL;
238 }
239
240 out:
241 if (pmo_set_pkt_fltr_req)
242 qdf_mem_free(pmo_set_pkt_fltr_req);
243 if (pmo_clr_pkt_fltr_param)
244 qdf_mem_free(pmo_clr_pkt_fltr_param);
245
246 return status;
247 }
248