xref: /wlan-dirver/qca-wifi-host-cmn/iot_sim/core/iot_sim_utils.c (revision 97f44cd39e4ff816eaa1710279d28cf6b9e65ad9)
1 /*
2  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <wlan_iot_sim_utils_api.h>
18 #include <qdf_module.h>
19 #include <qdf_delayed_work.h>
20 #include "../../core/iot_sim_cmn_api_i.h"
21 #include <wlan_objmgr_pdev_obj.h>
22 #include <wlan_objmgr_vdev_obj.h>
23 #include <wlan_objmgr_peer_obj.h>
24 
25 #define IEEE80211_FRAME_BODY_OFFSET 0x18
26 #define IEEE80211_TSF_LEN       (8)
27 
28 /*
29  * iot_sim_apply_content_change_rule - function to apply content change rule
30  *				       packet from upper stack will be modified
31  *				       as per the user content.
32  * @piot_sim_rule: iot_sim rule structure
33  * @nbuf: skb coming from upper stack
34  * @fixed_param_length: length of fixed parameters in frame body
35  *
36  * Return: QDF_STATUS_SUCCESS on successful content update or otherwise
37  *	   QDF_STATUS_E_NOSUPPORT, no content change rule found for this frame
38  */
39 QDF_STATUS
40 iot_sim_update_beacon_template_struct(qdf_nbuf_t nbuf,
41 				      struct beacon_tmpl_params *param)
42 {
43 	struct ie_header *ie = NULL;
44 	uint16_t offset = 0, ie_len = 0;
45 	struct ieee80211_ath_channelswitch_ie *csa = NULL;
46 	struct ieee80211_extendedchannelswitch_ie *ecsa = NULL;
47 	struct extn_ie_header *extn_ie = NULL;
48 
49 	if (!param)
50 		return QDF_STATUS_E_NULL_VALUE;
51 
52 	/**
53 	 * Skip fixed field
54 	 */
55 	offset += IEEE80211_TSF_LEN; /* TSF field */
56 	offset += 2; /* Beacon interval */
57 	offset += 2; /* Capability Information */
58 
59 	ie_len = wbuf_get_pktlen(nbuf) -
60 		 sizeof(struct ieee80211_frame) - offset;
61 	ie = (struct ie_header *)((uint8_t *)qdf_nbuf_data(nbuf) +
62 				  sizeof(struct ieee80211_frame) + offset);
63 
64 	while (ie_len >= sizeof(struct ie_header)) {
65 		ie_len -= sizeof(struct ie_header);
66 		if (!ie->ie_len) {
67 			ie += 1;
68 			continue;
69 		}
70 
71 		if (ie_len < ie->ie_len) {
72 			iot_sim_err("Incomplete corrupted IE:%x", ie->ie_id);
73 			return QDF_STATUS_E_INVAL;
74 		}
75 
76 		switch (ie->ie_id) {
77 		case WLAN_ELEMID_TIM:
78 			if (ie->ie_len < WLAN_TIM_IE_MIN_LENGTH) {
79 				iot_sim_err("Invalid TIM IE Length");
80 				goto err;
81 			}
82 			param->tim_ie_offset = ((uint8_t *)ie -
83 						(uint8_t *)qdf_nbuf_data(nbuf));
84 			break;
85 		case WLAN_ELEMID_CHANSWITCHANN:
86 			if (ie->ie_len != WLAN_CSA_IE_MAX_LEN) {
87 				iot_sim_err("Invalid CSA IE Length");
88 				goto err;
89 			}
90 			csa =
91 			(struct ieee80211_ath_channelswitch_ie *)ie;
92 			param->csa_switch_count_offset =
93 				(((uint8_t *)&csa->tbttcount) -
94 				 (uint8_t *)qdf_nbuf_data(nbuf));
95 			break;
96 		case WLAN_ELEMID_EXTCHANSWITCHANN:
97 			if (ie->ie_len != WLAN_XCSA_IE_MAX_LEN) {
98 				iot_sim_err("Invalid ECSA IE Length");
99 				goto err;
100 			}
101 			ecsa =
102 			(struct ieee80211_extendedchannelswitch_ie *)ie;
103 			param->ext_csa_switch_count_offset =
104 				(((uint8_t *)&ecsa->tbttcount) -
105 				 (uint8_t *)qdf_nbuf_data(nbuf));
106 			break;
107 		case WLAN_ELEMID_EXTN_ELEM:
108 			extn_ie = (struct extn_ie_header *)ie;
109 			switch (extn_ie->ie_extn_id) {
110 			case WLAN_EXTN_ELEMID_ESP:
111 				param->esp_ie_offset =
112 					((uint8_t *)ie -
113 					 (uint8_t *)qdf_nbuf_data(nbuf));
114 				break;
115 			case WLAN_EXTN_ELEMID_MUEDCA:
116 				param->mu_edca_ie_offset =
117 					((uint8_t *)ie -
118 					 (uint8_t *)qdf_nbuf_data(nbuf));
119 				break;
120 			default:
121 				break;
122 			}
123 			break;
124 		case WLAN_ELEMID_MULTIPLE_BSSID:
125 			offset = ((uint8_t *)ie -
126 				 (uint8_t *)qdf_nbuf_data(nbuf));
127 			param->mbssid_ie_offset = offset;
128 			break;
129 		default:
130 			break;
131 		}
132 		/* Consume info element */
133 		ie_len -= ie->ie_len;
134 		/* Go to next IE */
135 		ie = (struct ie_header *)((uint8_t *)ie +
136 					  sizeof(struct ie_header) +
137 					  ie->ie_len);
138 	}
139 	param->tmpl_len = wbuf_get_pktlen(nbuf);
140 	param->tmpl_len_aligned = roundup(param->tmpl_len,
141 					  sizeof(uint32_t));
142 	param->frm = (uint8_t *)qdf_nbuf_data(nbuf);
143 	return QDF_STATUS_SUCCESS;
144 err:
145 	return QDF_STATUS_E_INVAL;
146 }
147 
148 QDF_STATUS
149 iot_sim_apply_content_change_rule(struct wlan_objmgr_pdev *pdev,
150 				  struct iot_sim_rule *piot_sim_rule,
151 				  qdf_nbuf_t nbuf,
152 				  int fixed_param_length,
153 				  struct beacon_tmpl_params *param)
154 {
155 	uint8_t *buf = NULL;
156 	qdf_size_t buf_len = 0;
157 	int offset = 0;
158 	QDF_STATUS status = QDF_STATUS_SUCCESS;
159 
160 	if (!piot_sim_rule->frm_content || !piot_sim_rule->len)
161 		return QDF_STATUS_E_NOSUPPORT;
162 
163 	buf_len = qdf_nbuf_len(nbuf);
164 	buf = qdf_nbuf_data(nbuf);
165 
166 	if (piot_sim_rule->offset ==
167 			IEEE80211_FRAME_BODY_OFFSET) {
168 		offset = IEEE80211_FRAME_BODY_OFFSET;
169 	} else if (piot_sim_rule->offset == 0) {
170 		offset = 0;
171 	} else if (buf[piot_sim_rule->offset] ==
172 			piot_sim_rule->frm_content[0]) {
173 		offset = piot_sim_rule->offset;
174 	}  else {
175 		offset = IEEE80211_FRAME_BODY_OFFSET +
176 			fixed_param_length;
177 		while (((offset + 1) < buf_len) &&
178 		       (buf[offset] < piot_sim_rule->frm_content[0])) {
179 			offset += buf[offset + 1] + 2;
180 		}
181 	}
182 
183 	if (offset <= buf_len) {
184 		buf += offset;
185 		qdf_mem_copy(buf, piot_sim_rule->frm_content,
186 			     piot_sim_rule->len);
187 		qdf_nbuf_set_pktlen(nbuf, offset +
188 				piot_sim_rule->len);
189 		iot_sim_debug("iot_sim: Content updated");
190 	} else {
191 		iot_sim_err("Failed to modify content");
192 	}
193 
194 	if (IEEE80211_IS_BEACON((struct ieee80211_frame *)qdf_nbuf_data(nbuf)))
195 		status = iot_sim_update_beacon_template_struct(nbuf, param);
196 		if (QDF_IS_STATUS_ERROR(status))
197 			iot_sim_err("Failed to update beacon param");
198 
199 	return QDF_STATUS_SUCCESS;
200 }
201 
202 /*
203  * iot_sim_apply_delay_drop_rule - function to apply delay or drop rule.
204  *                                 If drop rule is set, buffer will be freed
205  *                                 here and proper return value will be sent to
206  *			           tgt layer. In case of delay rule, delayed
207  *                                 workqueue will be scheduled for rx frame
208  *                                 processing
209  *
210  * @piot_sim_rule: iot_sim rule structure
211  * @nbuf: skb coming from upper stack
212  *
213  * Return: QDF_STATUS_SUCCESS on successful drop
214  *	   QDF_STATUS_E_NULL_VALUE, when drop rule is applied
215  */
216 QDF_STATUS
217 iot_sim_apply_delay_drop_rule(struct iot_sim_rule *piot_sim_rule,
218 			      qdf_nbuf_t nbuf,
219 			      struct mgmt_rx_event_params *param,
220 			      struct iot_sim_context *isc,
221 			      struct qdf_mac_addr *mac_addr)
222 {
223 	struct mgmt_rx_event_params *rx_param;
224 	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(isc->pdev_obj);
225 	struct wlan_objmgr_peer **peer = &piot_sim_rule->peer;
226 
227 	if (!piot_sim_rule->drop &&
228 	    !piot_sim_rule->delay_dur)
229 		return QDF_STATUS_E_NOSUPPORT;
230 
231 	if (piot_sim_rule->drop && nbuf) {
232 		qdf_nbuf_free(nbuf);
233 		iot_sim_debug("iot_sim: Drop rule applied");
234 	} else if (piot_sim_rule->delay_dur) {
235 		if (nbuf == piot_sim_rule->sec_buf) {
236 			iot_sim_debug("iot_sim: rx frame process after delay");
237 			return QDF_STATUS_E_NOSUPPORT;
238 		}
239 
240 		if (piot_sim_rule->nbuf_list[0]) {
241 			if (!qdf_delayed_work_stop(piot_sim_rule->
242 						   dwork)) {
243 				piot_sim_rule->nbuf_list[1] = nbuf;
244 				return QDF_STATUS_SUCCESS;
245 			}
246 
247 			if (*peer) {
248 				wlan_objmgr_peer_release_ref(*peer,
249 							     WLAN_IOT_SIM_ID);
250 				*peer = NULL;
251 			}
252 
253 			qdf_nbuf_free(piot_sim_rule->nbuf_list[0]);
254 			qdf_mem_free(piot_sim_rule->rx_param->rx_params);
255 			qdf_mem_free(piot_sim_rule->rx_param);
256 		}
257 
258 		rx_param = qdf_mem_malloc(sizeof(struct mgmt_rx_event_params));
259 		if (!rx_param) {
260 			iot_sim_err("rx_param alloc failed");
261 			return QDF_STATUS_E_NOSUPPORT;
262 		}
263 
264 		qdf_mem_copy(rx_param, param,
265 			     sizeof(struct mgmt_rx_event_params));
266 		rx_param->rx_params = qdf_mem_malloc(RX_STATUS_SIZE);
267 		if (!rx_param->rx_params) {
268 			iot_sim_err("rx_param->rx_params alloc failed");
269 			qdf_mem_free(rx_param);
270 			return QDF_STATUS_E_NOSUPPORT;
271 		}
272 
273 		*peer = wlan_objmgr_get_peer(psoc, param->pdev_id,
274 					     (uint8_t *)mac_addr,
275 					     WLAN_IOT_SIM_ID);
276 		qdf_mem_copy(rx_param->rx_params,
277 			     param->rx_params, RX_STATUS_SIZE);
278 		piot_sim_rule->rx_param = rx_param;
279 		piot_sim_rule->nbuf_list[0] = nbuf;
280 		if (!qdf_delayed_work_start(piot_sim_rule->dwork,
281 					    piot_sim_rule->delay_dur)) {
282 			iot_sim_err("delayed_work_start failed");
283 			qdf_mem_free(rx_param->rx_params);
284 			qdf_mem_free(rx_param);
285 			if (*peer) {
286 				wlan_objmgr_peer_release_ref(*peer,
287 							     WLAN_IOT_SIM_ID);
288 				*peer = NULL;
289 			}
290 			return QDF_STATUS_E_NOSUPPORT;
291 		}
292 
293 		iot_sim_err("iot_sim: Delay rule applied");
294 	}
295 
296 	return QDF_STATUS_SUCCESS;
297 }
298 
299 /*
300  * iot_sim_frame_update - Function to parse input packet coming from upper
301  *			  stack in Tx direction and to tgt layer in Rx
302  *			  direction. This function will also check if rule
303  *			  for that frame type/subtype is set or not and call
304  *			  specific operation functions.
305  *
306  * @pdev: pdev object
307  * @nbuf: input packet
308  * @param: beacon template cmd parameter
309  * @tx: tx or not
310  * @rx_param: mgmt_rx_event_params
311  *
312  * Return: QDF_STATUS_SUCCESS in general
313  *	   QDF_STATUS_E_NOSUPPORT, no content change rule found for this frame
314  */
315 QDF_STATUS iot_sim_frame_update(struct wlan_objmgr_pdev *pdev, qdf_nbuf_t nbuf,
316 				struct beacon_tmpl_params *param,
317 				bool tx, struct mgmt_rx_event_params *rx_param)
318 {
319 	uint8_t type, subtype, seq = 0;
320 	struct iot_sim_context *isc;
321 	uint8_t *buf = qdf_nbuf_data(nbuf), *frm = NULL;
322 	int fixed_param_len = 0;
323 	bool is_action_frm = false;
324 	uint8_t cat, cat_index;
325 	int auth_seq_index = 0;
326 	struct iot_sim_rule *piot_sim_rule = NULL;
327 	QDF_STATUS status = QDF_STATUS_SUCCESS;
328 	struct iot_sim_rule_per_peer *peer_rule;
329 	struct ieee80211_frame *wh = (struct ieee80211_frame *)buf;
330 	struct qdf_mac_addr *mac_addr;
331 	bool deauth_disassoc = false;
332 
333 	isc = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_IOT_SIM_COMP);
334 	if (!isc) {
335 		iot_sim_err("pdev IOT_SIM object is NULL!");
336 		return QDF_STATUS_SUCCESS;
337 	}
338 
339 	type = (buf[0] & IEEE80211_FC0_TYPE_MASK) >> IEEE80211_FC0_TYPE_SHIFT;
340 	subtype = (buf[0] & IEEE80211_FC0_SUBTYPE_MASK);
341 
342 	if (type == IEEE80211_FC0_TYPE_MGT &&
343 	    subtype == IEEE80211_FC0_SUBTYPE_AUTH) {
344 	/* Authentication frame */
345 		auth_seq_index = IEEE80211_FRAME_BODY_OFFSET + 2;
346 		seq = le16toh(*(u_int16_t *)(buf + auth_seq_index));
347 	} else if (type == IEEE80211_FC0_TYPE_MGT &&
348 		   (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP ||
349 		    subtype == IEEE80211_FC0_SUBTYPE_BEACON))
350 	/* Probe response frame */
351 		fixed_param_len = 12;
352 	else if (type == IEEE80211_FC0_TYPE_MGT &&
353 		 (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_RESP ||
354 		  subtype == IEEE80211_FC0_SUBTYPE_REASSOC_RESP))
355 	/* Assoc/Reassoc response frame */
356 		fixed_param_len = 6;
357 	else if (type == IEEE80211_FC0_TYPE_MGT &&
358 		 (subtype == IEEE80211_FC0_SUBTYPE_DEAUTH ||
359 		  subtype == IEEE80211_FC0_SUBTYPE_DISASSOC))
360 		deauth_disassoc = true;
361 	else if (type == IEEE80211_FC0_TYPE_MGT &&
362 		 subtype == IEEE80211_FC0_SUBTYPE_ACTION) {
363 	/* Action frame */
364 		frm = buf + IEEE80211_FRAME_BODY_OFFSET;
365 
366 		is_action_frm = true;
367 		if (iot_sim_get_index_for_action_frm(frm, &cat,
368 						     &cat_index, !tx)) {
369 			iot_sim_err("get_index_for_action_frm failed");
370 			return QDF_STATUS_SUCCESS;
371 		}
372 	}
373 
374 	subtype >>= IEEE80211_FC0_SUBTYPE_SHIFT;
375 	iot_sim_debug("iot_sim: type:%d subtype:%d seq:%d, action:%u dir:%s",
376 		      type, subtype, seq, is_action_frm,
377 		      tx ? "TX" : "RX");
378 
379 	if (tx)
380 		mac_addr = (struct qdf_mac_addr *)wh->i_addr1;
381 	else
382 		mac_addr = (struct qdf_mac_addr *)wh->i_addr2;
383 
384 	peer_rule = iot_sim_find_peer_from_mac(isc, mac_addr);
385 	if (!peer_rule)
386 		peer_rule = &isc->bcast_peer;
387 
388 	if (!peer_rule)
389 		goto no_peer_rule;
390 
391 	qdf_spin_lock_bh(&isc->iot_sim_lock);
392 
393 	if (!peer_rule->rule_per_seq[seq])
394 		goto norule;
395 
396 	if (is_action_frm)
397 		piot_sim_rule = peer_rule->rule_per_seq[seq]->
398 			rule_per_action_frm[cat][cat_index];
399 	else
400 		piot_sim_rule = peer_rule->rule_per_seq[seq]->
401 			rule_per_type[type][subtype];
402 
403 	if (!piot_sim_rule)
404 		goto norule;
405 
406 	if (tx) {
407 		if (IEEE80211_IS_BEACON((struct ieee80211_frame *)
408 					qdf_nbuf_data(nbuf))) {
409 			if (isc->bcn_buf)
410 				qdf_nbuf_free(isc->bcn_buf);
411 			isc->bcn_buf = qdf_nbuf_copy(nbuf);
412 			status =
413 			   iot_sim_apply_content_change_rule(pdev,
414 							     piot_sim_rule,
415 							     isc->bcn_buf,
416 							     fixed_param_len,
417 							     param);
418 		} else {
419 			status =
420 			   iot_sim_apply_content_change_rule(pdev,
421 							     piot_sim_rule,
422 							     nbuf,
423 							     fixed_param_len,
424 							     param);
425 		}
426 
427 		if (status == QDF_STATUS_E_NOSUPPORT) {
428 			if (deauth_disassoc && piot_sim_rule->drop) {
429 				status = QDF_STATUS_E_NULL_VALUE;
430 				iot_sim_debug("iot_sim: frame to be dropped");
431 			} else
432 				goto norule;
433 		}
434 	} else {
435 		status = iot_sim_apply_delay_drop_rule(piot_sim_rule,
436 						       nbuf, rx_param,
437 						       isc, mac_addr);
438 		if (QDF_IS_STATUS_SUCCESS(status))
439 			status = QDF_STATUS_E_NULL_VALUE;
440 		else
441 			status = QDF_STATUS_SUCCESS;
442 	}
443 
444 	qdf_spin_unlock_bh(&isc->iot_sim_lock);
445 	return status;
446 
447 norule:
448 	iot_sim_debug("Rule not set for this frame");
449 	qdf_spin_unlock_bh(&isc->iot_sim_lock);
450 	return QDF_STATUS_SUCCESS;
451 no_peer_rule:
452 	iot_sim_debug("Rule not set for this peer");
453 	return QDF_STATUS_SUCCESS;
454 }
455