xref: /wlan-driver/qcacld-3.0/core/hdd/src/wlan_hdd_packet_filter.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
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