xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852bs/core/rtw_mbo.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2017 Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  *****************************************************************************/
15 #define _RTW_MBO_C
16 
17 #include <drv_types.h>
18 
19 #ifdef CONFIG_RTW_MBO
20 
21 #ifndef RTW_MBO_DBG
22 #define RTW_MBO_DBG	0
23 #endif
24 #if RTW_MBO_DBG
25 	#define RTW_MBO_INFO(fmt, arg...)	\
26 		RTW_INFO(fmt, arg)
27 	#define RTW_MBO_DUMP(str, data, len)	\
28 		RTW_INFO_DUMP(str, data, len)
29 #else
30 	#define RTW_MBO_INFO(fmt, arg...) do {} while (0)
31 	#define RTW_MBO_DUMP(str, data, len) do {} while (0)
32 #endif
33 
34 /* Cellular Data Connectivity field
35  * 1 : Cellular data connection available
36  * 2 : Cellular data connection not available
37  * 3 : Not Cellular data capable
38  * otherwise : Reserved
39 */
40 int rtw_mbo_cell_data_conn = 2;
41 module_param(rtw_mbo_cell_data_conn, int, 0644);
42 
43 static u8 wfa_mbo_oui[] = {0x50, 0x6F, 0x9A, 0x16};
44 
45 #define rtw_mbo_get_oui(p) ((u8 *)(p) + 2)
46 
47 #define rtw_mbo_get_attr_id(p) ((u8 *)(p))
48 
49 #define rtw_mbo_get_disallow_res(p) ((u8 *)(p) + 3)
50 
51 #define rtw_mbo_set_1byte_ie(p, v, l)	\
52 	rtw_set_fixed_ie((p), 1, (v), (l))
53 
54 #define rtw_mbo_set_2byte_ie(p, v, l)	\
55 	rtw_set_fixed_ie((p), 2, (v), (l))
56 
57 #define rtw_mbo_set_4byte_ie(p, v, l)	\
58 	rtw_set_fixed_ie((p), 4, (v), (l))
59 
60 #define rtw_mbo_set_nbyte_ie(p, sz, v, l)	\
61 	rtw_set_fixed_ie((p), (sz), (v), (l))
62 
63 #define rtw_mbo_subfield_set(p, offset, val) (*(p + offset) = val)
64 
65 #define rtw_mbo_subfields_set(p, offset, buf, len)	\
66 	do {	\
67 		u32 _offset = 0;	\
68 		u8 *_p = p + offset;	\
69 		while(_offset < len) {	\
70 			*(_p + _offset) = *(buf + _offset);	\
71 			_offset++;	\
72 		}	\
73 	} while(0)
74 
75 
rtw_mbo_ie_init(_adapter * padapter,struct mbo_priv * mbopriv)76 void rtw_mbo_ie_init(_adapter *padapter, struct mbo_priv *mbopriv)
77 {
78 	if(!mbopriv)
79 		return;
80 	mbopriv->assoc_disallow = 0;
81 	mbopriv->cellular_aware = 0;
82 	mbopriv->ch_list_num = 0;
83 	mbopriv->mbo_oce_element_len = 6;
84 	mbopriv->mbo_oce_element[0] = 0xdd;
85 	mbopriv->mbo_oce_element[1] = mbopriv->mbo_oce_element_len;
86 	mbopriv->mbo_oce_element[2] = 0x50;
87 	mbopriv->mbo_oce_element[3] = 0x6f;
88 	mbopriv->mbo_oce_element[4] = 0x9a;
89 	mbopriv->mbo_oce_element[5] = 0x16;
90 }
91 
rtw_mbo_fill_non_prefer_channel_list(_adapter * padapter,struct mbo_priv * mbopriv,const u8 * pbuf,u8 len)92 void rtw_mbo_fill_non_prefer_channel_list(_adapter *padapter, struct mbo_priv *mbopriv,
93 										const u8 *pbuf, u8 len)
94 {
95 	u8 op_class = 0;
96 	u8 preference = 0;
97 	int i;
98 
99 	/* invalid length */
100 	if(len != 0 && len < 3)
101 		return;
102 
103 	/* reset non-prefer channel list */
104 	mbopriv->ch_list_num = 0;
105 	op_class = *pbuf;
106 	preference = *(pbuf + len - 2);
107 
108 	if (len == 3 && mbopriv->ch_list_num < MBO_CH_LIST_MAX_NUM) {
109 		mbopriv->ch_list[mbopriv->ch_list_num].op_class = op_class;
110 		mbopriv->ch_list[mbopriv->ch_list_num].preference = preference;
111 		mbopriv->ch_list[mbopriv->ch_list_num].channel = 0;
112 		mbopriv->ch_list_num += 1;
113 		RTW_INFO("[%s:%d]channel = %d, preference = %d\n", __func__, __LINE__, 0, preference);
114 	} else {
115 		for (i = 0; i < len - 3; i++) {
116 			if(mbopriv->ch_list_num >= MBO_CH_LIST_MAX_NUM)
117 				break;
118 			mbopriv->ch_list[mbopriv->ch_list_num].op_class = op_class;
119 			mbopriv->ch_list[mbopriv->ch_list_num].preference = preference;
120 			mbopriv->ch_list[mbopriv->ch_list_num].channel = *(pbuf + 1 + i);
121 			mbopriv->ch_list_num += 1;
122 			RTW_INFO("[%s:%d]channel = %d, preference = %d\n", __func__, __LINE__,
123 									*(pbuf + 1 + i), preference);
124 		}
125 	}
126 }
127 
rtw_mbo_ie_handler(_adapter * padapter,struct mbo_priv * mbopriv,const u8 * pbuf,uint limit_len)128 void rtw_mbo_ie_handler(_adapter *padapter, struct mbo_priv *mbopriv, const u8 *pbuf, uint limit_len)
129 {
130 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
131 	uint total_len = 0;
132 	u8 attribute_id = 0;
133 	u8 attribute_len = 0;
134 	const u8 *p = pbuf;
135 
136 	if(!mbopriv)
137 		return;
138 
139 	rtw_mbo_ie_init(padapter, mbopriv);
140 	_rtw_memcpy(mbopriv->mbo_oce_element + 6, pbuf, limit_len);
141 	mbopriv->mbo_oce_element[1] = limit_len + 4;
142 
143 	while (total_len <= limit_len) {
144 		attribute_id = *p;
145 		attribute_len = *(p + 1);
146 		total_len += attribute_len;
147 		if(total_len > limit_len)
148 			break;
149 
150 		switch (attribute_id) {
151 			case MBO_AP_CAPABILITY:
152 				if(attribute_len == 1){
153 					RTW_INFO("[%s]Find attribute MBO_AP_CAPABILITY\n", __func__);
154 					if(*(p+2) & 0x40)
155 						mbopriv->cellular_aware = 1;
156 				}
157 				break;
158 			case ASSOCIATION_DISALLOW:
159 				if(attribute_len == 1){
160 					RTW_INFO("[%s]Find attribute ASSOCIATION_DISALLOW\n", __func__);
161 					mbopriv->assoc_disallow = *(p+2);
162 				}
163 				break;
164 			case NON_PREFER_CHANNEL_RPT:
165 				RTW_INFO("[%s]Find attribute NON_PREFER_CHANNEL_RPT\n", __func__);
166 				rtw_mbo_fill_non_prefer_channel_list(padapter, mbopriv, p + 2, attribute_len);
167 				break;
168 			case CELLULAR_DATA_CAPABILITY:
169 			case CELLULAR_DATA_CONNECT_PREFER:
170 			case TRANS_REASON_CODE:
171 			case TRANS_REJECT_REASON_CODE:
172 			case ASSOCIATION_RETRY_DELAY:
173 				break;
174 			default:
175 				RTW_ERR("[%s]Unknown MBO attribute %d\n", __func__, attribute_id);
176 		}
177 
178 		p += (attribute_len + 2);
179 	}
180 }
181 
rtw_ap_parse_sta_mbo_element(_adapter * padapter,struct sta_info * psta,u8 * ies_buf,u16 ies_len)182 void rtw_ap_parse_sta_mbo_element(_adapter *padapter,
183 	struct sta_info *psta, u8 *ies_buf, u16 ies_len)
184 {
185 	uint ie_len = 0;
186 	u8 *p;
187 	u8 WIFI_ALLIANCE_OUI[] = {0x50, 0x6f, 0x9a};
188 
189 	ie_len = 0;
190 	for (p = ies_buf; ; p += (ie_len + 2)) {
191 		p = rtw_get_ie(p, _SSN_IE_1_, &ie_len, (ies_len - (ie_len + 2)));
192 		if ((p) && (_rtw_memcmp(p + 2, WIFI_ALLIANCE_OUI, 3)) && (*(p+5) == MBO_OUI_TYPE)) {
193 			/* find MBO-OCE information element */
194 			psta->mbopriv.enable = _TRUE;
195 			rtw_mbo_ie_handler(padapter, &psta->mbopriv, p + 6, ie_len - 4);
196 			break;
197 		}
198 		if ((p == NULL) || (ie_len == 0))
199 			break;
200 	}
201 }
202 
rtw_mbo_ie_get(u8 * pie,u32 * plen,u32 limit)203 static u8 *rtw_mbo_ie_get(u8 *pie, u32 *plen, u32 limit)
204 {
205 	const u8 *p = pie;
206 	u32 tmp, i;
207 
208 	if (limit <= 1)
209 		return NULL;
210 
211 	i = 0;
212 	*plen = 0;
213 	while (1) {
214 		if ((*p == _VENDOR_SPECIFIC_IE_) &&
215 			(_rtw_memcmp(rtw_mbo_get_oui(p), wfa_mbo_oui, 4))) {
216 			*plen = *(p + 1);
217 			/* RTW_MBO_DUMP("VENDOR_SPECIFIC_IE MBO: ", p, *(p + 1)); */
218 			return (u8 *)p;
219 		} else {
220 			tmp = *(p + 1);
221 			p += (tmp + 2);
222 			i += (tmp + 2);
223 		}
224 
225 		if (i >= limit)
226 			break;
227 	}
228 
229 	return NULL;
230 }
231 
rtw_mbo_attrs_get(u8 * pie,u32 limit,u8 attr_id,u32 * attr_len,u8 dbg)232 static u8 *rtw_mbo_attrs_get(u8 *pie,
233 	u32 limit, u8 attr_id,u32 *attr_len, u8 dbg)
234 {
235 	u8 *p = NULL;
236 	u32 offset, plen = 0;
237 
238 	if ((pie == NULL) || (limit <= 1))
239 		goto exit;
240 
241 	if ((p = rtw_mbo_ie_get(pie, &plen, limit)) == NULL)
242 		goto exit;
243 
244 	/* shift 2 + OUI size and move to attributes content */
245 	p = p + 2 + sizeof(wfa_mbo_oui);
246 	plen = plen - 4;
247 
248 	if (dbg)
249 		RTW_MBO_DUMP("Attributes contents: ", p, plen);
250 
251 	if ((p = rtw_get_ie(p, attr_id, attr_len, plen)) == NULL)
252 		goto exit;
253 
254 	if (dbg) {
255 		RTW_MBO_INFO("%s : id=%u(len=%u)\n",
256 			__func__, attr_id, *attr_len);
257 		RTW_MBO_DUMP("contents : ", (p + 2), *attr_len);
258 	}
259 
260 exit:
261 	return p;
262 
263 }
264 
rtw_mbo_attr_sz_get(_adapter * padapter,u8 id)265 static u32 rtw_mbo_attr_sz_get(
266 	_adapter *padapter, u8 id)
267 {
268 	u32 len = 0;
269 
270 	switch (id) {
271 		case RTW_MBO_ATTR_NPREF_CH_RPT_ID:
272 			{
273 				struct rf_ctl_t *prfctl = \
274 					adapter_to_rfctl(padapter);
275 				struct npref_ch_rtp *prpt = \
276 					&(prfctl->ch_rtp);
277 				struct npref_ch* pch;
278 				u32 i, attr_len, offset;
279 
280 				for (i=0; i < prpt->nm_of_rpt; i++) {
281 					pch = &prpt->ch_rpt[i];
282 					/*attr_len = ch list + op class
283 						 + preference + reason */
284 					attr_len = pch->nm_of_ch + 3;
285 					/* offset = id + len field
286 						 + attr_len */
287 					offset = attr_len + 2;
288 					len += offset;
289 				}
290 			}
291 			break;
292 		case RTW_MBO_ATTR_ASSOC_RETRY_DELAY_ID:
293 			len = 4;
294 			break;
295 		case RTW_MBO_ATTR_AP_CAP_ID:
296 		case RTW_MBO_ATTR_CELL_DATA_CAP_ID:
297 		case RTW_MBO_ATTR_ASSOC_DISABLED_ID:
298 		case RTW_MBO_ATTR_TRANS_RES_ID:
299 		case RTW_MBO_ATTR_TRANS_REJ_ID:
300 			len = 3;
301 			break;
302 		default:
303 			break;
304 	}
305 
306 	return len;
307 }
308 
rtw_mbo_build_mbo_ie_hdr(u8 ** pframe,struct pkt_attrib * pattrib,u8 payload_len)309 static void rtw_mbo_build_mbo_ie_hdr(
310 	u8 **pframe, struct pkt_attrib *pattrib, u8 payload_len)
311 {
312 	u8 eid = RTW_MBO_EID;
313 	u8 len = payload_len + 4;
314 
315 	*pframe = rtw_mbo_set_1byte_ie(*pframe, &eid, &(pattrib->pktlen));
316 	*pframe = rtw_mbo_set_1byte_ie(*pframe, &len, &(pattrib->pktlen));
317 	*pframe = rtw_mbo_set_4byte_ie(*pframe,
318 			wfa_mbo_oui, &(pattrib->pktlen));
319 }
320 
rtw_mbo_build_cell_data_cap_attr(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib)321 void rtw_mbo_build_cell_data_cap_attr(
322 	_adapter *padapter, u8 **pframe, struct pkt_attrib *pattrib)
323 {
324 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
325 	u8 attr_id = RTW_MBO_ATTR_CELL_DATA_CAP_ID;
326 	u8 attr_len = 1;
327 	u8 cell_data_con = rtw_mbo_cell_data_conn;
328 
329 	/* used Cellular Data Capabilities from supplicant */
330 	if (!rtw_mbo_wifi_logo_test(padapter) &&
331 		pmlmepriv->pcell_data_cap_ie &&
332 		pmlmepriv->cell_data_cap_len == 1) {
333 		cell_data_con = *pmlmepriv->pcell_data_cap_ie;
334 	}
335 
336 	*pframe = rtw_mbo_set_1byte_ie(*pframe, &attr_id, &(pattrib->pktlen));
337 	*pframe = rtw_mbo_set_1byte_ie(*pframe, &attr_len, &(pattrib->pktlen));
338 	*pframe = rtw_mbo_set_1byte_ie(*pframe,
339 			&cell_data_con, &(pattrib->pktlen));
340 }
341 
342 
rtw_mbo_build_ap_cap_Indication_attr(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib,u8 cap_ind)343 static void rtw_mbo_build_ap_cap_Indication_attr(
344 	_adapter *padapter, u8 **pframe,
345 	struct pkt_attrib *pattrib, u8 cap_ind)
346 {
347 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
348 	u8 attr_id = RTW_MBO_ATTR_AP_CAP_ID;
349 	u8 attr_len = 1;
350 	u8 ap_cap_ind = cap_ind;
351 
352 	*pframe = rtw_mbo_set_1byte_ie(*pframe, &attr_id, &(pattrib->pktlen));
353 	*pframe = rtw_mbo_set_1byte_ie(*pframe, &attr_len, &(pattrib->pktlen));
354 	*pframe = rtw_mbo_set_1byte_ie(*pframe,
355 			&ap_cap_ind, &(pattrib->pktlen));
356 }
357 
rtw_mbo_build_ap_disallowed_attr(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib,u8 code)358 static void rtw_mbo_build_ap_disallowed_attr(
359 	_adapter *padapter, u8 **pframe,
360 	struct pkt_attrib *pattrib, u8 code)
361 {
362 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
363 	u8 attr_id = RTW_MBO_ATTR_ASSOC_DISABLED_ID;
364 	u8 attr_len = 1;
365 	u8 reason = 0;
366 
367 	if (code > 0) {
368 		reason = code;
369 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
370 				&attr_id, &(pattrib->pktlen));
371 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
372 				&attr_len, &(pattrib->pktlen));
373 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
374 				&reason, &(pattrib->pktlen));
375 	}
376 }
377 
rtw_mbo_build_ap_trans_reason_attr(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib,u8 code)378 static void rtw_mbo_build_ap_trans_reason_attr(
379 	_adapter *padapter, u8 **pframe,
380 	struct pkt_attrib *pattrib, u8 code)
381 {
382 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
383 	u8 attr_id = RTW_MBO_ATTR_TRANS_RES_ID;
384 	u8 attr_len = 1;
385 	u8 reason = 0;
386 
387 	reason = code;
388 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
389 				&attr_id, &(pattrib->pktlen));
390 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
391 				&attr_len, &(pattrib->pktlen));
392 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
393 				&reason, &(pattrib->pktlen));
394 	}
395 
rtw_mbo_build_ap_assoc_retry_delay_attr(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib,u16 code)396 static void rtw_mbo_build_ap_assoc_retry_delay_attr(
397 	_adapter *padapter, u8 **pframe,
398 	struct pkt_attrib *pattrib, u16 code)
399 {
400 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
401 	u8 attr_id = RTW_MBO_ATTR_ASSOC_RETRY_DELAY_ID;
402 	u8 attr_len = 2;
403 	u16 delay = 0;
404 
405 	delay = code;
406 	*pframe = rtw_mbo_set_1byte_ie(*pframe, &attr_id, &(pattrib->pktlen));
407 	*pframe = rtw_mbo_set_1byte_ie(*pframe, &attr_len, &(pattrib->pktlen));
408 	*pframe = rtw_mbo_set_2byte_ie(*pframe,
409 			(u8 *)&delay, &(pattrib->pktlen));
410 }
411 
rtw_mbo_update_cell_data_cap(_adapter * padapter,u8 * pie,u32 ie_len)412 static void rtw_mbo_update_cell_data_cap(
413 	_adapter *padapter, u8 *pie, u32 ie_len)
414 {
415 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
416 	u8 *mbo_attr;
417 	u32	mbo_attrlen;
418 
419 	if ((pie == NULL) || (ie_len == 0))
420 		return;
421 
422 	mbo_attr = rtw_mbo_attrs_get(pie, ie_len,
423 		RTW_MBO_ATTR_CELL_DATA_CAP_ID, &mbo_attrlen, 0);
424 
425 	if ((mbo_attr == NULL) || (mbo_attrlen == 0) ) {
426 		RTW_INFO("MBO : Cellular Data Capabilities not found!\n");
427 		return;
428 	}
429 
430 	rtw_buf_update(&pmlmepriv->pcell_data_cap_ie,
431 		&pmlmepriv->cell_data_cap_len, (mbo_attr + 2), mbo_attrlen);
432 	RTW_MBO_DUMP("rtw_mbo_update_cell_data_cap : ",
433 		pmlmepriv->pcell_data_cap_ie, pmlmepriv->cell_data_cap_len);
434 }
435 
rtw_mbo_update_ie_data(_adapter * padapter,u8 * pie,u32 ie_len)436 void rtw_mbo_update_ie_data(
437 	_adapter *padapter, u8 *pie, u32 ie_len)
438 {
439 	rtw_mbo_update_cell_data_cap(padapter, pie, ie_len);
440 }
441 
rtw_mbo_current_op_class_get(_adapter * padapter)442 static u8 rtw_mbo_current_op_class_get(_adapter *padapter)
443 {
444 	struct rf_ctl_t *prfctl = adapter_to_rfctl(padapter);
445 	struct p2p_channels *pch_list =  &(prfctl->channel_list);
446 	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
447 	struct p2p_reg_class *preg_class;
448 	int class_idx, ch_idx;
449 	u8 cur_op_class = 0;
450 
451 	for(class_idx =0; class_idx < pch_list->reg_classes; class_idx++) {
452 		preg_class =  &pch_list->reg_class[class_idx];
453 		for (ch_idx = 0; ch_idx <= preg_class->channels; ch_idx++) {
454 			if (pmlmeext->chandef.chan ==  \
455 				preg_class->channel[ch_idx]) {
456 				cur_op_class = preg_class->reg_class;
457 				RTW_MBO_INFO("%s : current ch : %d,"
458 					" op class : %d\n",
459 					__func__, pmlmeext->chandef.chan,
460 					cur_op_class);
461 				break;
462 			}
463 		}
464 	}
465 
466 	return cur_op_class;
467 }
468 
rtw_mbo_supp_op_classes_get(_adapter * padapter,u8 * pclasses)469 static void rtw_mbo_supp_op_classes_get(_adapter *padapter, u8 *pclasses)
470 {
471 	struct rf_ctl_t *prfctl = adapter_to_rfctl(padapter);
472 	struct p2p_channels *pch_list =  &(prfctl->channel_list);
473 	int class_idx;
474 
475 	if (pclasses == NULL)
476 		return;
477 
478 	RTW_MBO_INFO("%s : support op class \n", __func__);
479 	for(class_idx = 0; class_idx < pch_list->reg_classes; class_idx++) {
480 		*(pclasses + class_idx) = \
481 			pch_list->reg_class[class_idx].reg_class;
482 		RTW_MBO_INFO("%u ,", *(pclasses + class_idx));
483 	}
484 
485 	RTW_MBO_INFO("%s : \n", __func__);
486 }
487 
rtw_mbo_build_supp_op_class_elem(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib)488 void rtw_mbo_build_supp_op_class_elem(
489 	_adapter *padapter, u8 **pframe, struct pkt_attrib *pattrib)
490 {
491 	struct rf_ctl_t *prfctl = adapter_to_rfctl(padapter);
492 	u8 payload[32] = {0};
493 	u8 delimiter_130 = 130;	/*0x82*/
494 	u8 reg_class_nm, len;
495 
496 	if ((reg_class_nm = prfctl->channel_list.reg_classes) == 0)
497 		return;
498 
499 	payload[0] = rtw_mbo_current_op_class_get(padapter);
500 	rtw_mbo_supp_op_classes_get(padapter, &payload[1]);
501 
502 	/* IEEE 802.11 Std Current Operating Class Extension Sequence */
503 	payload[reg_class_nm + 1] = delimiter_130;
504 	payload[reg_class_nm + 2] = 0x00;
505 
506 	RTW_MBO_DUMP("op class :", payload, reg_class_nm);
507 
508 	/* Current Operating Class field + Operating Class field
509 		+ OneHundredAndThirty Delimiter field */
510 	len = reg_class_nm + 3;
511 	*pframe = rtw_set_ie(*pframe, EID_SupRegulatory, len ,
512 					payload, &(pattrib->pktlen));
513 }
514 
rtw_mbo_construct_npref_ch_rpt_attr(_adapter * padapter,u8 * pbuf,u32 buf_len,u32 * plen)515 static u8 rtw_mbo_construct_npref_ch_rpt_attr(
516 	_adapter *padapter, u8 *pbuf, u32 buf_len, u32 *plen)
517 {
518 	struct rf_ctl_t *prfctl = adapter_to_rfctl(padapter);
519 	struct npref_ch_rtp *prpt = &(prfctl->ch_rtp);
520 	struct npref_ch* pch;
521 	u32 attr_len, offset;
522 	int i;
523 	u8 *p = pbuf;
524 
525 	if (prpt->nm_of_rpt == 0) {
526 		*plen = 0;
527 		return _FALSE;
528 	}
529 
530 	for (i=0; i < prpt->nm_of_rpt; i++) {
531 		pch = &prpt->ch_rpt[i];
532 		/* attr_len = ch list + op class + preference + reason */
533 		attr_len = pch->nm_of_ch + 3;
534 		/* offset = id + len field + attr_len */
535 		offset = attr_len + 2;
536 		rtw_mbo_subfield_set(p, 0, RTW_MBO_ATTR_NPREF_CH_RPT_ID);
537 		rtw_mbo_subfield_set(p, 1, attr_len);
538 		rtw_mbo_subfield_set(p, 2, pch->op_class);
539 		rtw_mbo_subfields_set(p, 3, pch->chs, pch->nm_of_ch);
540 		rtw_mbo_subfield_set(p, (offset - 2), pch->preference);
541 		rtw_mbo_subfield_set(p, (offset - 1), pch->reason);
542 		p +=  offset;
543 		*plen += offset;
544 
545 		if (*plen >=  buf_len) {
546 			RTW_ERR("MBO : construct non-preferred-ch rpt fail!\n");
547 			return _FALSE;
548 		}
549 	}
550 
551 	return _TRUE;
552 }
553 
rtw_mbo_build_npref_ch_rpt_attr(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib)554 void rtw_mbo_build_npref_ch_rpt_attr(
555 	_adapter *padapter, u8 **pframe, struct pkt_attrib *pattrib)
556 {
557 	struct rf_ctl_t *prfctl = adapter_to_rfctl(padapter);
558 	struct npref_ch_rtp *prpt = &(prfctl->ch_rtp);
559 	u32 tmp_sz = 0, body_len = 0;
560 	u8 *ptmp;
561 
562 	tmp_sz = prpt->nm_of_rpt * sizeof(struct npref_ch);
563 	ptmp = rtw_zmalloc(tmp_sz);
564 	if (ptmp == NULL)
565 		return;
566 
567 	if (rtw_mbo_construct_npref_ch_rpt_attr(
568 		padapter, ptmp, tmp_sz, &body_len) == _FALSE) {
569 		rtw_mfree(ptmp, tmp_sz);
570 		return;
571 	}
572 
573 	RTW_MBO_DUMP("Non-preferred Channel Report :", ptmp, body_len);
574 	*pframe = rtw_mbo_set_nbyte_ie(*pframe, body_len,
575 			ptmp, &(pattrib->pktlen));
576 
577 	rtw_mfree(ptmp, tmp_sz);
578 }
579 
rtw_mbo_build_trans_reject_reason_attr(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib,u8 * pres)580 void rtw_mbo_build_trans_reject_reason_attr(
581 	_adapter *padapter, u8 **pframe,
582 	struct pkt_attrib *pattrib, u8 *pres)
583 {
584 	u8 attr_id = RTW_MBO_ATTR_TRANS_REJ_ID;
585 	u8 attr_len = 1;
586 	u32 len = 0;
587 
588 	len = rtw_mbo_attr_sz_get(padapter, RTW_MBO_ATTR_TRANS_REJ_ID);
589 	if ((len == 0) || (len > 3)) {
590 		RTW_ERR("MBO : build Transition Rejection Reason"
591 			" attribute fail(len=%u)\n", len);
592 		return;
593 	}
594 
595 	rtw_mbo_build_mbo_ie_hdr(pframe, pattrib, len);
596 	*pframe = rtw_mbo_set_1byte_ie(*pframe, &attr_id, &(pattrib->pktlen));
597 	*pframe = rtw_mbo_set_1byte_ie(*pframe, &attr_len, &(pattrib->pktlen));
598 	*pframe = rtw_mbo_set_1byte_ie(*pframe, pres, &(pattrib->pktlen));
599 }
600 
rtw_mbo_disallowed_network(struct wlan_network * pnetwork)601 u8 rtw_mbo_disallowed_network(struct wlan_network *pnetwork)
602 {
603 	u8 *p, *attr_id, *res;
604 	u32 attr_len = 0;
605 	u8 disallow = _FALSE;
606 
607 	if ((pnetwork == NULL) || \
608 		((p = rtw_mbo_attrs_get(
609 			pnetwork->network.IEs,
610 		pnetwork->network.IELength,
611 		RTW_MBO_ATTR_ASSOC_DISABLED_ID,
612 			&attr_len, 0)) == NULL)) {
613 		goto exit;
614 	}
615 
616 	RTW_MBO_DUMP("Association Disallowed attribute :",p , attr_len + 2);
617 	RTW_INFO("MBO : block "MAC_FMT" assoc disallowed reason %d\n",
618 		MAC_ARG(pnetwork->network.MacAddress),
619 		*(rtw_mbo_get_disallow_res(p)));
620 
621 	disallow = _TRUE;
622 exit:
623 	return disallow;
624 }
625 
rtw_mbo_build_extended_cap(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib)626 void rtw_mbo_build_extended_cap(
627 	_adapter *padapter, u8 **pframe, struct pkt_attrib *pattrib)
628 {
629 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
630 
631 	if (!rtw_mbo_wifi_logo_test(padapter))
632 		return;
633 
634 	rtw_wnm_add_btm_ext_cap(pmlmepriv->ext_capab_ie_data,
635 				&(pmlmepriv->ext_capab_ie_len));
636 	rtw_mbo_add_internw_ext_cap(pmlmepriv->ext_capab_ie_data,
637 				&(pmlmepriv->ext_capab_ie_len));
638 	*pframe = rtw_set_ie(*pframe,
639 				WLAN_EID_EXT_CAP,
640 				pmlmepriv->ext_capab_ie_len,
641 				pmlmepriv->ext_capab_ie_data,
642 				&(pattrib->pktlen));
643 }
644 
rtw_mbo_non_pref_chans_dump(struct npref_ch * pch)645 static void rtw_mbo_non_pref_chans_dump(struct npref_ch* pch)
646 {
647 	int i;
648 	u8 buf[128] = {0};
649 
650 	for (i=0; i < pch->nm_of_ch; i++)
651 		rtw_sprintf(buf, 128, "%s,%d", buf, pch->chs[i]);
652 
653 	RTW_MBO_INFO("%s : op_class=%01x, ch=%s, preference=%d, reason=%d\n",
654 		__func__, pch->op_class, buf, pch->preference, pch->reason);
655 }
656 
rtw_mbo_non_pref_chan_exist(struct npref_ch * pch,u8 ch)657 static u8 rtw_mbo_non_pref_chan_exist(struct npref_ch* pch, u8 ch)
658 {
659 	u32 i;
660 	u8 found = _FALSE;
661 
662 	for (i=0; i < pch->nm_of_ch; i++) {
663 		if (pch->chs[i] == ch) {
664 			found = _TRUE;
665 			break;
666 		}
667 	}
668 
669 	return found;
670 }
671 
rtw_mbo_non_pref_chan_get(_adapter * padapter,u8 op_class,u8 prefe,u8 res)672 static struct npref_ch* rtw_mbo_non_pref_chan_get(
673 	_adapter *padapter, u8 op_class, u8  prefe, u8  res)
674 {
675 	struct rf_ctl_t *prfctl = adapter_to_rfctl(padapter);
676 	struct npref_ch_rtp *prpt = &(prfctl->ch_rtp);
677 	struct npref_ch* pch = NULL;
678 	int i;
679 
680 	if (prpt->nm_of_rpt == 0)
681 		return pch;
682 
683 	for (i=0; i < prpt->nm_of_rpt; i++) {
684 		if ((prpt->ch_rpt[i].op_class == op_class) &&
685 			(prpt->ch_rpt[i].preference == prefe) &&
686 			(prpt->ch_rpt[i].reason == res)) {
687 			pch = &prpt->ch_rpt[i];
688 			break;
689 		}
690 	}
691 
692 	return pch;
693 }
694 
rtw_mbo_non_pref_chan_set(struct npref_ch * pch,u8 op_class,u8 ch,u8 prefe,u8 res,u8 update)695 static void rtw_mbo_non_pref_chan_set(
696 	struct npref_ch* pch, u8 op_class,
697 	u8 ch, u8  prefe, u8  res, u8 update)
698 {
699 	u32 offset = pch->nm_of_ch;
700 
701 	if (update) {
702 		if (rtw_mbo_non_pref_chan_exist(pch, ch) == _FALSE) {
703 			pch->chs[offset] = ch;
704 			pch->nm_of_ch++;
705 		}
706 	} else {
707 		pch->op_class = op_class;
708 		pch->chs[0] = ch;
709 		pch->preference = prefe;
710 		pch->reason = res;
711 		pch->nm_of_ch = 1;
712 	}
713 }
714 
rtw_mbo_non_pref_chans_update(_adapter * padapter,u8 op_class,u8 ch,u8 prefe,u8 res)715 static void  rtw_mbo_non_pref_chans_update(
716 	_adapter *padapter, u8 op_class, u8 ch, u8  prefe, u8  res)
717 {
718 	struct rf_ctl_t *prfctl = adapter_to_rfctl(padapter);
719 	struct npref_ch_rtp *pch_rpt = &(prfctl->ch_rtp);
720 	struct npref_ch* pch;
721 
722 	if (pch_rpt->nm_of_rpt >= RTW_MBO_MAX_CH_RPT_NUM) {
723 		RTW_ERR("MBO : %d non_pref_chan entries supported!",
724 			RTW_MBO_MAX_CH_RPT_NUM);
725 		return;
726 	}
727 
728 	if (pch_rpt->nm_of_rpt == 0) {
729 		pch = &pch_rpt->ch_rpt[0];
730 		rtw_mbo_non_pref_chan_set(pch, op_class,
731 				ch, prefe, res, _FALSE);
732 		pch_rpt->nm_of_rpt = 1;
733 		return;
734 	}
735 
736 	pch = rtw_mbo_non_pref_chan_get(padapter, op_class, prefe, res);
737 	if (pch == NULL) {
738 		pch = &pch_rpt->ch_rpt[pch_rpt->nm_of_rpt];
739 		rtw_mbo_non_pref_chan_set(pch, op_class,
740 				ch, prefe, res, _FALSE);
741 		pch_rpt->nm_of_rpt++;
742 	} else {
743 		rtw_mbo_non_pref_chan_set(pch, op_class,
744 				ch, prefe, res, _TRUE);
745 	}
746 
747 	rtw_mbo_non_pref_chans_dump(pch);
748 }
749 
rtw_mbo_non_pref_chans_set(_adapter * padapter,char * param,ssize_t sz)750 static void  rtw_mbo_non_pref_chans_set(
751 	_adapter *padapter, char *param, ssize_t sz)
752 {
753 	char *pnext;
754 	u32 op_class, ch, prefe, res;
755 	int i = 0;
756 
757 	do {
758 		pnext = strsep(&param, " ");
759 		if (pnext == NULL)
760 			break;
761 
762 		sscanf(pnext, "%d:%d:%d:%d", &op_class, &ch, &prefe, &res);
763 		rtw_mbo_non_pref_chans_update(padapter, op_class,
764 					ch, prefe, res);
765 
766 		if ((i++) > 10) {
767 			RTW_ERR("MBO : overflow %d \n", i);
768 			break;
769 		}
770 
771 	} while (param != (char*)'\0');
772 
773 }
774 
rtw_mbo_non_pref_chans_del(_adapter * padapter,char * param,ssize_t sz)775 static void  rtw_mbo_non_pref_chans_del(
776 	_adapter *padapter, char *param, ssize_t sz)
777 {
778 	struct rf_ctl_t *prfctl = adapter_to_rfctl(padapter);
779 	struct npref_ch_rtp *prpt = &(prfctl->ch_rtp);
780 
781 	RTW_INFO("%s : delete non_pref_chan %s\n", __func__, param);
782 	_rtw_memset(prpt, 0, sizeof(struct npref_ch_rtp));
783 }
784 
rtw_mbo_proc_non_pref_chans_set(struct file * pfile,const char __user * buffer,size_t count,loff_t * pos,void * pdata)785 ssize_t rtw_mbo_proc_non_pref_chans_set(
786 	struct file *pfile, const char __user *buffer,
787 	size_t count, loff_t *pos, void *pdata)
788 {
789 	struct net_device *dev = pdata;
790 	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
791 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
792 	u8 tmp[128] = {0};
793 
794 	if (count < 1)
795 		return -EFAULT;
796 
797 	if (count > sizeof(tmp)) {
798 		rtw_warn_on(1);
799 		return -EFAULT;
800 	}
801 
802 	if (buffer && !copy_from_user(tmp, buffer, count)) {
803 		if (strncmp(tmp, "add", 3) == 0) {
804 			rtw_mbo_non_pref_chans_set(padapter,
805 					&tmp[4], (count - 4));
806 		} else if (strncmp(tmp, "delete", 6) == 0) {
807 			rtw_mbo_non_pref_chans_del(padapter,
808 					&tmp[7], (count - 7));
809 		} else {
810 			RTW_ERR("MBO : Invalid format : echo [add|delete]"
811 			" <oper_class>:<chan>:<preference>:<reason>\n");
812 			return -EFAULT;
813 		}
814 	}
815 
816 #ifdef CONFIG_RTW_WNM
817 	if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE) &&
818 		check_fwstate(pmlmepriv, WIFI_STATION_STATE))
819 		rtw_wnm_issue_action(padapter,
820 				RTW_WLAN_ACTION_WNM_NOTIF_REQ, 0, 0);
821 #endif
822 
823 	return count;
824 }
825 
rtw_mbo_proc_non_pref_chans_get(struct seq_file * m,void * v)826 int rtw_mbo_proc_non_pref_chans_get(
827 	struct seq_file *m, void *v)
828 {
829 	struct net_device *dev = m->private;
830 	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
831 	struct rf_ctl_t *prfctl = adapter_to_rfctl(padapter);
832 	struct npref_ch_rtp *prpt = &(prfctl->ch_rtp);
833 	struct npref_ch* pch;
834 	int i,j;
835 	u8 buf[32] = {0};
836 
837 	RTW_PRINT_SEL(m, "op_class                     ch    preference    reason \n");
838 	RTW_PRINT_SEL(m, "=======================================================\n");
839 
840 	if (prpt->nm_of_rpt == 0) {
841 		RTW_PRINT_SEL(m, " empty table \n");
842 		return 0;
843 	}
844 
845 	for (i=0; i < prpt->nm_of_rpt; i++) {
846 		pch = &prpt->ch_rpt[i];
847 		buf[0]='\0';
848 		for (j=0; j < pch->nm_of_ch; j++) {
849 			if (j == 0)
850 				rtw_sprintf(buf, 32, "%02u", pch->chs[j]);
851 			else
852 				rtw_sprintf(buf, 32, "%s,%02u", buf, pch->chs[j]);
853 		}
854 
855 		RTW_PRINT_SEL(m, "    %04u    %20s           %02u        %02u\n",
856 			pch->op_class, buf, pch->preference, pch->reason);
857 	}
858 
859 	return 0;
860 }
861 
rtw_mbo_proc_cell_data_set(struct file * pfile,const char __user * buffer,size_t count,loff_t * pos,void * pdata)862 ssize_t rtw_mbo_proc_cell_data_set(
863 	struct file *pfile, const char __user *buffer,
864 	size_t count, loff_t *pos, void *pdata)
865 {
866 	struct net_device *dev = pdata;
867 	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
868 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
869 	int mbo_cell_data = 0;
870 	u8 tmp[8] = {0};
871 
872 	if (count < 1)
873 		return -EFAULT;
874 
875 	if (count > sizeof(tmp))
876 		return -EFAULT;
877 
878 	if (buffer && !copy_from_user(tmp, buffer, count)) {
879 		int num = sscanf(tmp, "%d", &mbo_cell_data);
880 		if (num == 1) {
881 			rtw_mbo_cell_data_conn = mbo_cell_data;
882 		#ifdef CONFIG_RTW_WNM
883 			if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE) &&
884 				check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
885 				rtw_wnm_issue_action(padapter,
886 					RTW_WLAN_ACTION_WNM_NOTIF_REQ, 0, 0);
887 			}
888 		#endif
889 		}
890 	}
891 
892 	return count;
893 }
894 
rtw_mbo_proc_cell_data_get(struct seq_file * m,void * v)895 int rtw_mbo_proc_cell_data_get(
896 	struct seq_file *m, void *v)
897 {
898 #if 0
899 	struct net_device *dev = m->private;
900 	_adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
901 #endif
902 
903 	RTW_PRINT_SEL(m, "Cellular Data Connectivity : %d\n",
904 			rtw_mbo_cell_data_conn);
905 	return 0;
906 }
907 
908 
rtw_mbo_disassoc(_adapter * padapter,u8 * da,u8 reason,u8 wait_ack)909 static void rtw_mbo_disassoc(_adapter *padapter, u8 *da,
910 			u8 reason, u8 wait_ack)
911 {
912 	struct xmit_frame *pmgntframe;
913         struct pkt_attrib *pattrib;
914         struct rtw_ieee80211_hdr *pwlanhdr;
915         struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
916         struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
917         struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
918         u8 *pframe;
919         u16 *fctrl;
920         int ret = _FAIL;
921 
922 	if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter)))
923 		return;
924 
925 	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
926 	if (pmgntframe == NULL)
927 		return;
928 
929 	/* update attribute */
930 	pattrib = &pmgntframe->attrib;
931 	update_mgntframe_attrib(padapter, pattrib);
932 	pattrib->retry_ctrl = _FALSE;
933         pattrib->key_type = IEEE80211W_RIGHT_KEY;
934 
935 	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
936 	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
937 	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
938 	fctrl = &(pwlanhdr->frame_ctl);
939 	*(fctrl) = 0;
940 
941 	_rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN);
942 	_rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
943 	_rtw_memcpy(pwlanhdr->addr3,
944 		get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
945 
946 	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
947 	pmlmeext->mgnt_seq++;
948 	set_frame_sub_type(pframe, WIFI_DISASSOC);
949 
950 	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
951 	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
952 
953 	reason = cpu_to_le16(reason);
954 	pframe = rtw_set_fixed_ie(pframe, _RSON_CODE_ ,
955 			(unsigned char *)&reason, &(pattrib->pktlen));
956 
957 	pattrib->last_txcmdsz = pattrib->pktlen;
958 	if (wait_ack)
959 		dump_mgntframe_and_wait_ack(padapter, pmgntframe);
960 	else
961 		dump_mgntframe(padapter, pmgntframe);
962 	RTW_MBO_INFO("%s : reason %u\n", __func__, reason);
963 }
964 
rtw_mbo_construct_user_btm_req(_adapter * padapter,struct btm_req_hdr * phdr,u8 * purl,u32 url_len,struct wnm_btm_cant * pbtm_cant)965 static void rtw_mbo_construct_user_btm_req(
966 	_adapter *padapter, struct btm_req_hdr *phdr,
967 	u8 *purl, u32 url_len, struct wnm_btm_cant *pbtm_cant)
968 {
969 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
970 	struct mbo_attr_info *pmbo_attr = &(pmlmepriv->mbo_attr);
971 	struct mbo_user_btm_req_pkt *puser = &(pmbo_attr->user_raw);
972 	struct wnm_btm_cant *puser_cant = NULL;
973 
974 	if (phdr) {
975 		puser->hdr.req_mode = phdr->req_mode;
976 		puser->hdr.disassoc_timer = phdr->disassoc_timer;
977 		puser->hdr.validity_interval = phdr->validity_interval;
978 		puser->hdr.term_duration.tsf = phdr->term_duration.tsf;
979 		puser->hdr.term_duration.duration = \
980 			phdr->term_duration.duration;
981 		puser->hdr.term_duration.id = 0x4;
982 		puser->hdr.term_duration.len = 0xa;
983 		RTW_MBO_INFO("%s : req-mode=0x%x, disassoc_timer=%u, "
984 			"validity_interval=%u, tsf=%llu, "
985 			"duration=%u\n", __func__,
986 			puser->hdr.req_mode, puser->hdr.disassoc_timer,
987 			puser->hdr.validity_interval,
988 			puser->hdr.term_duration.tsf,
989 			puser->hdr.term_duration.duration);
990 	}
991 
992 	if (purl && url_len) {
993 		/* TODO */
994 	}
995 
996 	if (pbtm_cant) {
997 		struct wnm_btm_cant *pbtm_tb = NULL;
998 		u8 i, idx, found = _FALSE;
999 
1000 		for (i = 0; i < RTW_MAX_NB_RPT_NUM; i++) {
1001 			puser_cant = &puser->btm_cants[i];
1002 			if (_rtw_memcmp(pbtm_cant->nb_rpt.bssid,
1003 				puser_cant->nb_rpt.bssid, ETH_ALEN)) {
1004 				puser_cant->nb_rpt.bss_info = \
1005 					pbtm_cant->nb_rpt.bss_info;
1006 				puser_cant->nb_rpt.reg_class = \
1007 					pbtm_cant->nb_rpt.reg_class;
1008 				puser_cant->nb_rpt.ch_num = \
1009 					pbtm_cant->nb_rpt.ch_num;
1010 				puser_cant->nb_rpt.phy_type = \
1011 					pbtm_cant->nb_rpt.phy_type;
1012 				puser_cant->preference = \
1013 					pbtm_cant->preference;
1014 				idx = i;
1015 				found = _TRUE;
1016 				break;
1017 			}
1018 		}
1019 
1020 		if (!found) {
1021 			if (puser->candidate_cnt >= RTW_MAX_NB_RPT_NUM)
1022 				puser->candidate_cnt = 0;
1023 			puser_cant = &puser->btm_cants[puser->candidate_cnt];
1024 			puser_cant->nb_rpt.id = \
1025 				RTW_WLAN_ACTION_WNM_NB_RPT_ELEM;
1026 			puser_cant->nb_rpt.len = 0x10;
1027 			_rtw_memcpy(puser_cant->nb_rpt.bssid,
1028 				pbtm_cant->nb_rpt.bssid, ETH_ALEN);
1029 			puser_cant->nb_rpt.bss_info = \
1030 				pbtm_cant->nb_rpt.bss_info;
1031 			puser_cant->nb_rpt.reg_class = \
1032 				pbtm_cant->nb_rpt.reg_class;
1033 			puser_cant->nb_rpt.ch_num = \
1034 				pbtm_cant->nb_rpt.ch_num;
1035 			puser_cant->nb_rpt.phy_type = \
1036 				pbtm_cant->nb_rpt.phy_type;
1037 			puser_cant->preference = \
1038 				pbtm_cant->preference;
1039 			idx = puser->candidate_cnt;
1040 			puser->candidate_cnt++;
1041 		}
1042 
1043 		RTW_MBO_INFO("%s:%s idx=%u, bssid("MAC_FMT"),"
1044 			" bss_info(0x%04X), reg_class(0x%02X),"
1045 			" ch(%d), phy_type(0x%02X), preference(0x%02X)\n",
1046 			__func__, (found)?"update":"new", idx,
1047 			MAC_ARG(puser_cant->nb_rpt.bssid),
1048 			puser_cant->nb_rpt.bss_info,
1049 			puser_cant->nb_rpt.reg_class,
1050 			puser_cant->nb_rpt.ch_num,
1051 			puser_cant->nb_rpt.phy_type,
1052 			puser_cant->preference);
1053 
1054 	} /* end of if (pbtm_cant) */
1055 }
1056 
rtw_mbo_reset_user_btm_req_preference(_adapter * padapter)1057 static void rtw_mbo_reset_user_btm_req_preference(_adapter *padapter)
1058 {
1059 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
1060 	struct mbo_attr_info *pmbo_attr = &(pmlmepriv->mbo_attr);
1061 	struct mbo_user_btm_req_pkt *puser = &(pmbo_attr->user_raw);
1062 	struct wnm_btm_cant *puser_cant = NULL;
1063 	u8 i;
1064 
1065 	for (i = 0; i < RTW_MAX_NB_RPT_NUM; i++) {
1066 		puser_cant = &puser->btm_cants[i];
1067 		if (_rtw_memcmp(adapter_mac_addr(padapter),
1068 			puser_cant->nb_rpt.bssid, ETH_ALEN)) {
1069 			puser_cant->preference = 0;
1070 			RTW_MBO_INFO("%s : reset "MAC_FMT" BTM preference\n",
1071 				__func__, MAC_ARG(puser_cant->nb_rpt.bssid));
1072 			break;
1073 		}
1074 	}
1075 
1076 }
1077 
rtw_mbo_proc_attr_set(struct file * pfile,const char __user * buffer,size_t count,loff_t * pos,void * pdata)1078 ssize_t rtw_mbo_proc_attr_set(
1079 	struct file *pfile, const char __user *buffer,
1080 	size_t count, loff_t *pos, void *pdata)
1081 {
1082 	struct net_device *dev = pdata;
1083 	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
1084 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
1085 	struct mbo_attr_info *pmbo_attr = &(pmlmepriv->mbo_attr);
1086 	struct mbo_user_btm_req_pkt *puser = &(pmbo_attr->user_raw);
1087 	u32 id, val;
1088 	u8 tmp[64] = {0};
1089 
1090 	if (count < 1)
1091 		return -EFAULT;
1092 
1093 	if (count > sizeof(tmp))
1094 		return -EFAULT;
1095 
1096 	if (buffer && !copy_from_user(tmp, buffer, count)) {
1097 		int num = sscanf(tmp, "%d %d", &id, &val);
1098 		switch (id) {
1099 			case RTW_MBO_ATTR_AP_CAP_ID:
1100 				pmbo_attr->ap_cap_ind = val;
1101 				break;
1102 			case RTW_MBO_ATTR_CELL_DATA_CAP_ID:
1103 				pmbo_attr->cell_data_cap = val;
1104 				break;
1105 			case RTW_MBO_ATTR_ASSOC_DISABLED_ID:
1106 				pmbo_attr->assoc_disallow = val;
1107 				break;
1108 			case RTW_MBO_ATTR_TRANS_RES_ID:
1109 				pmbo_attr->reason = val;
1110 				break;
1111 			case RTW_MBO_ATTR_ASSOC_RETRY_DELAY_ID:
1112 				pmbo_attr->delay = val;
1113 				break;
1114 			case RTW_MBO_TEST_CMD_REST:
1115 				RTW_INFO("%s : RTW_MBO_TEST_CMD_REST\n",
1116 					__func__);
1117 				_rtw_memset(pmbo_attr, 0,
1118 					sizeof(struct mbo_attr_info));
1119 				pmbo_attr->mbo_spec_test = 1;
1120 				break;
1121 			case RTW_MBO_TEST_CMD_BTM_REQ_SET:
1122 				if (count >= 10) {
1123 					struct btm_req_hdr btm_hdr;
1124 					u32 disassoc_imnt, term_bit;
1125 					u32 term_tsf, term_duration;
1126 
1127 					_rtw_memset(&btm_hdr, 0,
1128 							sizeof(btm_hdr));
1129 
1130 					num = sscanf(tmp, "%d %u %u %u %u",
1131 						&id, &disassoc_imnt,
1132 						&term_bit, &term_tsf,
1133 						&term_duration);
1134 
1135 					if (num < 5)
1136 						break;
1137 
1138 					if (disassoc_imnt > 0)
1139 						btm_hdr.req_mode |= \
1140 							DISASSOC_IMMINENT;
1141 
1142 					if (term_bit > 0)
1143 						btm_hdr.req_mode |= \
1144 						BSS_TERMINATION_INCLUDED;
1145 
1146 					btm_hdr.term_duration.tsf = term_tsf;
1147 					btm_hdr.term_duration.duration = \
1148 							term_duration;
1149 
1150 					rtw_mbo_construct_user_btm_req(
1151 						padapter, &btm_hdr, NULL, 0,
1152 						NULL);
1153 				}
1154 				break;
1155 			case RTW_MBO_TEST_CMD_BTM_REQ_SEND:
1156 				if (count >= 12) {
1157 					u8 mac_str[18] = {0};
1158 					u8 dst_mac[ETH_ALEN] = {0};
1159 					u32 cand_list = 0, disassoc_timer = 0;
1160 
1161 					num = sscanf(tmp, "%d %s %u %u",
1162 						&id, mac_str, &cand_list,
1163 						&disassoc_timer);
1164 
1165 					if (num < 4)
1166 						break;
1167 
1168 					if (sscanf(mac_str, MAC_SFMT,
1169 						MAC_SARG(
1170 						dst_mac)) != 6) {
1171 						break;
1172 					}
1173 
1174 					puser->append_mbo_ie = _TRUE;
1175 					puser->hdr.dialog_token++;
1176 					puser->hdr.validity_interval = 0xf;
1177 					if (cand_list > 0)
1178 						puser->hdr.req_mode |= \
1179 						PREFERRED_CANDIDATE_LIST_INCLUDED;
1180 
1181 
1182 					puser->hdr.disassoc_timer = \
1183 						disassoc_timer;
1184 
1185 					if ((puser->hdr.req_mode & \
1186 						DISASSOC_IMMINENT) == \
1187 						DISASSOC_IMMINENT) {
1188 						rtw_mbo_reset_user_btm_req_preference(padapter);
1189 						if (pmbo_attr->delay == 0)
1190 							pmbo_attr->delay = 1;
1191 						if (puser->hdr.disassoc_timer == 0)
1192 							puser->hdr.disassoc_timer = 1000;
1193 					}
1194 
1195 					if ((puser->hdr.req_mode & \
1196 						BSS_TERMINATION_INCLUDED) == \
1197 						BSS_TERMINATION_INCLUDED) {
1198 						 puser->append_mbo_ie = _FALSE;
1199 					}
1200 
1201 					if (!puser->candidate_cnt) {
1202 						struct wnm_btm_cant cant;
1203 						_rtw_memset(&cant, 0,
1204 								sizeof(cant));
1205 						_rtw_memcpy(cant.nb_rpt.bssid,
1206 							adapter_mac_addr(padapter),
1207 							ETH_ALEN);
1208 						cant.nb_rpt.reg_class = 115;
1209 						cant.nb_rpt.ch_num = 36;
1210 						cant.preference = 0;
1211 						rtw_mbo_construct_user_btm_req(
1212 							padapter, NULL,
1213 							NULL, 0, &cant);
1214 					}
1215 
1216 					rtw_wnm_issue_btm_req(padapter, dst_mac,
1217 						&puser->hdr, NULL, 0,
1218 						(u8 *)&puser->btm_cants,
1219 						puser->candidate_cnt);
1220 
1221 					if ((puser->hdr.term_duration.duration)
1222 						&& (puser->hdr.req_mode & \
1223 						BSS_TERMINATION_INCLUDED) == \
1224 						BSS_TERMINATION_INCLUDED) {
1225 						rtw_mbo_disassoc(padapter,
1226 							dst_mac, 3, _TRUE);
1227 					}
1228 
1229 					if ((puser->hdr.req_mode & \
1230 						DISASSOC_IMMINENT) == \
1231 						DISASSOC_IMMINENT) {
1232 						rtw_mbo_disassoc(padapter,
1233 							dst_mac, 3, _TRUE);
1234 					}
1235 				} /* end of if (count >= 12) */
1236 
1237 				break;
1238 			case RTW_MBO_TEST_CMD_NB_BSS_ADD:
1239 				if (count >= 12) {
1240 					u8 bss_str[18];
1241 					struct wnm_btm_cant cant;
1242 					u32 op, op_ch, perf;
1243 
1244 					num = sscanf(tmp, "%d %s %u %u %u",
1245 						&id, bss_str, &op, &op_ch,
1246 						&perf);
1247 					if (num < 5)
1248 						break;
1249 					_rtw_memset(&cant, 0, sizeof(cant));
1250 					if (sscanf(bss_str, MAC_SFMT,
1251 						MAC_SARG(
1252 						cant.nb_rpt.bssid)) != 6) {
1253 						break;
1254 					}
1255 
1256 					cant.nb_rpt.reg_class = op;
1257 					cant.nb_rpt.ch_num = op_ch;
1258 					cant.preference = perf;
1259 					rtw_mbo_construct_user_btm_req(
1260 						padapter, NULL, NULL, 0,
1261 						&cant);
1262 				} /* end of if (count >= 12) */
1263 				break;
1264 			default:
1265 				break;
1266 		}
1267 	}
1268 
1269 	return count;
1270 }
1271 
rtw_mbo_proc_attr_get(struct seq_file * m,void * v)1272 int rtw_mbo_proc_attr_get(
1273 	struct seq_file *m, void *v)
1274 {
1275 	struct net_device *dev = m->private;
1276 	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
1277 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
1278 	struct mbo_attr_info *pmbo_attr = &(pmlmepriv->mbo_attr);
1279 
1280 	RTW_PRINT_SEL(m, "AP Capability Indication : %d\n",
1281 				pmbo_attr->ap_cap_ind);
1282 	RTW_PRINT_SEL(m, "Cellular Data Capabilities : %d\n",
1283 				pmbo_attr->cell_data_cap);
1284 	RTW_PRINT_SEL(m, "Association Disallowed : %d\n",
1285 				pmbo_attr->assoc_disallow);
1286 	return 0;
1287 }
1288 
rtw_mbo_non_pref_chan_subelem_parsing(_adapter * padapter,u8 * subelem,size_t subelem_len)1289 static void rtw_mbo_non_pref_chan_subelem_parsing(
1290 	_adapter *padapter, u8 *subelem, size_t subelem_len)
1291 {
1292 	u8 *pnon_pref_chans;
1293 	u32 non_pref_chan_offset, op_subelem_len;
1294 	u32 oui_offset = 3;
1295 	/* wpa_supplicant don't apped OUI Type */
1296 	u32 oui_type_offset = 0;
1297 
1298 	RTW_MBO_DUMP("Non-preferred Channel subelem : ",
1299 			subelem , subelem_len);
1300 
1301 	/* Subelem :
1302 		Vendor Specific | Length | WFA OUI | OUI Type | MBO Attributes */
1303 	non_pref_chan_offset = 2 + oui_offset + oui_type_offset;
1304 	pnon_pref_chans = subelem + non_pref_chan_offset;
1305 	op_subelem_len = subelem_len - non_pref_chan_offset;
1306 
1307 	/* wpa_supplicant don't indicate non_pref_chan length,
1308 		so we cannot get how many non_pref_chan in a wnm notification */
1309 	RTW_MBO_DUMP("Non-preferred Channel : ",
1310 			pnon_pref_chans, op_subelem_len);
1311 }
1312 
rtw_mbo_wnm_notification_parsing(_adapter * padapter,const u8 * pdata,size_t data_len)1313 void rtw_mbo_wnm_notification_parsing(
1314 	_adapter *padapter, const u8 *pdata, size_t data_len)
1315 {
1316 	u8 *paction;
1317 	u8 category, action, dialog, type;
1318 	u32 len;
1319 
1320 	if ((pdata == NULL) || (data_len == 0))
1321 		return;
1322 
1323 	RTW_MBO_DUMP("WNM notification data : ", pdata, data_len);
1324 	paction = (u8 *)pdata + sizeof(struct rtw_ieee80211_hdr_3addr);
1325 	category = paction[0];
1326 	action = paction[1];
1327 	dialog = paction[2];
1328 	type = paction[3];
1329 
1330 	if ((action == RTW_WLAN_ACTION_WNM_NOTIF_REQ) &&
1331 		(type == WLAN_EID_VENDOR_SPECIFIC)) {
1332 		rtw_mbo_non_pref_chan_subelem_parsing(padapter, &paction[4],
1333 			(data_len - sizeof(struct rtw_ieee80211_hdr_3addr)));
1334 	}
1335 }
1336 
rtw_mbo_build_wnm_notification(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib)1337 void rtw_mbo_build_wnm_notification(
1338 	_adapter *padapter, u8 **pframe, struct pkt_attrib *pattrib)
1339 {
1340 	struct rf_ctl_t *prfctl = adapter_to_rfctl(padapter);
1341 	struct npref_ch_rtp *prpt = &(prfctl->ch_rtp);
1342 	struct npref_ch* pch;
1343 	u8 subelem_id = WLAN_EID_VENDOR_SPECIFIC;
1344 	u8 non_pref_ch_oui[] = {0x50, 0x6F, 0x9A, 0x2};
1345 	u8 cell_data_cap_oui[] = {0x50, 0x6F, 0x9A, 0x3};
1346 	u8 cell_data_con = rtw_mbo_cell_data_conn;
1347 	u8 len, cell_data_con_len = 0, *pcont = *pframe;
1348 	int i;
1349 
1350 	if (rtw_mbo_cell_data_conn > 0) {
1351 		len = 0x5;
1352 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
1353 				&subelem_id, &(pattrib->pktlen));
1354 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
1355 				&len, &(pattrib->pktlen));
1356 		*pframe = rtw_mbo_set_4byte_ie(*pframe,
1357 				cell_data_cap_oui, &(pattrib->pktlen));
1358 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
1359 				&cell_data_con, &(pattrib->pktlen));
1360 		RTW_MBO_INFO("%s : Cellular Data Capabilities subelemen\n",
1361 				__func__);
1362 		RTW_MBO_DUMP(":", pcont, len + 2);
1363 		pcont += len + 2 ;
1364 	}
1365 
1366 	if (prpt->nm_of_rpt == 0) {
1367 		len = 0x4;
1368 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
1369 				&subelem_id, &(pattrib->pktlen));
1370 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
1371 				&len, &(pattrib->pktlen));
1372 		*pframe = rtw_mbo_set_4byte_ie(*pframe,
1373 				non_pref_ch_oui, &(pattrib->pktlen));
1374 		RTW_MBO_INFO("%s :Non-preferred Channel Report subelement"
1375 				" without data\n", __func__);
1376 		return;
1377 	}
1378 
1379 	for (i=0; i < prpt->nm_of_rpt; i++) {
1380 		pch = &prpt->ch_rpt[i];
1381 		/* OUI(3B)  + OUT-type(1B) + op-class(1B) + ch list(nB)
1382 			+ Preference(1B) + reason(1B) */
1383 		len = pch->nm_of_ch + 7;
1384 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
1385 				&subelem_id, &(pattrib->pktlen));
1386 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
1387 				&len, &(pattrib->pktlen));
1388 		*pframe = rtw_mbo_set_4byte_ie(*pframe,
1389 				non_pref_ch_oui, &(pattrib->pktlen));
1390 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
1391 				&pch->op_class, &(pattrib->pktlen));
1392 		*pframe = rtw_mbo_set_nbyte_ie(*pframe,
1393 				pch->nm_of_ch, pch->chs, &(pattrib->pktlen));
1394 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
1395 				&pch->preference, &(pattrib->pktlen));
1396 		*pframe = rtw_mbo_set_1byte_ie(*pframe,
1397 				&pch->reason, &(pattrib->pktlen));
1398 		RTW_MBO_INFO("%s :Non-preferred Channel Report"
1399 				" subelement\n", __func__);
1400 		RTW_MBO_DUMP(":", pcont, len);
1401 		pcont = *pframe;
1402 	}
1403 }
1404 
rtw_mbo_build_probe_req_ies(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib)1405 void rtw_mbo_build_probe_req_ies(
1406 	_adapter *padapter, u8 **pframe, struct pkt_attrib *pattrib)
1407 {
1408 	u32 len =0;
1409 
1410 	rtw_mbo_build_extended_cap(padapter, pframe, pattrib);
1411 
1412 	len = rtw_mbo_attr_sz_get(padapter, RTW_MBO_ATTR_CELL_DATA_CAP_ID);
1413 	if ((len == 0) || (len > 3)) {
1414 		RTW_ERR("MBO : build Cellular Data Capabilities"
1415 			" attribute fail(len=%u)\n", len);
1416 		return;
1417 	}
1418 
1419 	rtw_mbo_build_mbo_ie_hdr(pframe, pattrib, len);
1420 	rtw_mbo_build_cell_data_cap_attr(padapter, pframe, pattrib);
1421 }
1422 
rtw_mbo_build_assoc_req_ies(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib)1423 void rtw_mbo_build_assoc_req_ies(
1424 	_adapter *padapter, u8 **pframe, struct pkt_attrib *pattrib)
1425 {
1426 	u32 len = 0;
1427 
1428 	rtw_mbo_build_supp_op_class_elem(padapter, pframe, pattrib);
1429 
1430 	len += rtw_mbo_attr_sz_get(padapter, RTW_MBO_ATTR_CELL_DATA_CAP_ID);
1431 	len += rtw_mbo_attr_sz_get(padapter, RTW_MBO_ATTR_NPREF_CH_RPT_ID);
1432 	if ((len == 0)|| (len < 3)) {
1433 		RTW_ERR("MBO : build assoc MBO IE fail(len=%u)\n", len);
1434 		return;
1435 	}
1436 
1437 	rtw_mbo_build_mbo_ie_hdr(pframe, pattrib, len);
1438 	rtw_mbo_build_cell_data_cap_attr(padapter, pframe, pattrib);
1439 	rtw_mbo_build_npref_ch_rpt_attr(padapter, pframe, pattrib);
1440 }
1441 
rtw_mbo_build_ap_capability(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib)1442 static void rtw_mbo_build_ap_capability(
1443 	_adapter *padapter, u8 **pframe,
1444 	struct pkt_attrib *pattrib)
1445 {
1446 	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
1447 	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
1448 	WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network);
1449 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
1450 	struct mbo_attr_info *pmbo_attr = &(pmlmepriv->mbo_attr);
1451 	u8 *pcap = NULL;
1452 	u32 cap_len = 0, flen = 0;
1453 
1454 	if ((pcap = rtw_mbo_attrs_get(
1455 		(cur_network->IEs + _FIXED_IE_LENGTH_),
1456 		(cur_network->IELength - _FIXED_IE_LENGTH_),
1457 		RTW_MBO_ATTR_AP_CAP_ID, &cap_len, 0)) != NULL)
1458 		return;
1459 
1460 	flen += rtw_mbo_attr_sz_get(padapter, RTW_MBO_ATTR_AP_CAP_ID);
1461 	if (pmbo_attr->assoc_disallow > 0)
1462 		flen += rtw_mbo_attr_sz_get(padapter,
1463 				RTW_MBO_ATTR_ASSOC_DISABLED_ID);
1464 	if (flen > 0) {
1465 		rtw_mbo_build_mbo_ie_hdr(pframe, pattrib, flen);
1466 		rtw_mbo_build_ap_cap_Indication_attr(padapter, pframe,
1467 				pattrib, pmbo_attr->ap_cap_ind);
1468 
1469 		if (pmbo_attr->assoc_disallow > 0) {
1470 			rtw_mbo_build_ap_disallowed_attr(padapter, pframe,
1471 				pattrib, pmbo_attr->assoc_disallow);
1472 		}
1473 	} /*  end of if (flen > 0) */
1474 
1475 }
1476 
rtw_mbo_attr_info_init(_adapter * padapter)1477 void rtw_mbo_attr_info_init(_adapter *padapter)
1478 {
1479 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
1480 	struct mbo_attr_info *pmbo_attr = &(pmlmepriv->mbo_attr);
1481 
1482 	_rtw_memset(pmbo_attr, 0, sizeof(struct mbo_attr_info));
1483 }
1484 
rtw_mbo_process_assoc_req(_adapter * padapter,u8 * pie,int ie_len)1485 void rtw_mbo_process_assoc_req(
1486 	_adapter *padapter, u8 *pie, int ie_len)
1487 {
1488 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
1489 	struct mbo_attr_info *pmbo_attr = &(pmlmepriv->mbo_attr);
1490 	u8 non_pref_ch = 0, ch_op_pref = 1;
1491 	u8 *pattr = NULL, *ptr = NULL;
1492 	u32 attr_len = 0, ch_nums = 0;
1493 	int i, j;
1494 
1495 	if (!pie || !ie_len)
1496 		return;
1497 
1498 	if ((pattr = rtw_mbo_attrs_get(pie, ie_len,
1499 		RTW_MBO_ATTR_NPREF_CH_RPT_ID, &attr_len, 1)) == NULL)
1500 		return;
1501 
1502 	if (attr_len < 3)
1503 		return;
1504 
1505 	ch_nums = (attr_len - 3);
1506 
1507 	/* shfit to non-preferred ch rpt field */
1508 	ptr = pattr + 3;
1509 	RTW_MBO_DUMP("non-preferred ch rpt :", ptr, ch_nums);
1510 
1511 	ch_op_pref = *(ptr + ch_nums);
1512 	RTW_MBO_INFO("%s : ch_op_pref=0x%02x\n", __func__, ch_op_pref);
1513 
1514 	if (ch_op_pref >= 2) {
1515 		RTW_MBO_INFO("%s : unknow ch operating preference(0x%02x)\n",
1516 			__func__, ch_op_pref);
1517 		return;
1518 	}
1519 
1520 	for (i = 0; i < ch_nums; i++) {
1521 		if (i >= RTW_MBO_MAX_CH_LIST_NUM)
1522 			break;
1523 		non_pref_ch = *(ptr + i);
1524 		RTW_MBO_INFO("%s : non-pref ch %u found in assoc-req\n",
1525 			__func__, non_pref_ch);
1526 
1527 		if (rtw_mbo_wifi_spec_test(padapter)) {
1528 			struct mbo_user_btm_req_pkt *puser_raw = \
1529 				&(pmbo_attr->user_raw);
1530 			struct wnm_btm_cant *pcant = NULL;
1531 
1532 			for (j = 0; j < RTW_MAX_NB_RPT_NUM; j++) {
1533 				pcant = &puser_raw->btm_cants[j];
1534 				if ((pcant->nb_rpt.ch_num == non_pref_ch) && \
1535 					(ch_op_pref == 0)) {
1536 					RTW_MBO_INFO("%s : reset "
1537 					"preference(%u) for non-preference ch\n",
1538 					__func__, pcant->preference);
1539 					pcant->preference = 0;
1540 				}
1541 			}
1542 		}
1543 
1544 	} /* end of for-loop ch_nums */
1545 
1546 }
1547 
rtw_mbo_build_beacon_ies(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib)1548 void rtw_mbo_build_beacon_ies(
1549 	_adapter *padapter, u8 **pframe, struct pkt_attrib *pattrib)
1550 {
1551 	rtw_mbo_build_ap_capability(padapter, pframe, pattrib);
1552 }
1553 
rtw_mbo_build_probe_rsp_ies(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib)1554 void rtw_mbo_build_probe_rsp_ies(
1555 	_adapter *padapter, u8 **pframe, struct pkt_attrib *pattrib)
1556 {
1557 	rtw_mbo_build_ap_capability(padapter, pframe, pattrib);
1558 }
1559 
rtw_mbo_build_assoc_rsp_ies(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib)1560 void rtw_mbo_build_assoc_rsp_ies(
1561 	_adapter *padapter, u8 **pframe, struct pkt_attrib *pattrib)
1562 {
1563 	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
1564 	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
1565 	WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network);
1566 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
1567 	struct mbo_attr_info *pmbo_attr = &(pmlmepriv->mbo_attr);
1568 	u8 *pcap = NULL;
1569 	u32 len = 0, cap_len = 0 ;
1570 
1571 	#if 1
1572 	if ((pcap = rtw_mbo_attrs_get(
1573 		(cur_network->IEs + _FIXED_IE_LENGTH_),
1574 		(cur_network->IELength - _FIXED_IE_LENGTH_),
1575 		RTW_MBO_ATTR_AP_CAP_ID, &cap_len, 0)) != NULL)
1576 		return;
1577 	#endif
1578 
1579 	len += rtw_mbo_attr_sz_get(padapter, RTW_MBO_ATTR_AP_CAP_ID);
1580 	if (pmbo_attr->assoc_disallow > 0)
1581 		len += rtw_mbo_attr_sz_get(padapter,
1582 			RTW_MBO_ATTR_ASSOC_DISABLED_ID);
1583 
1584 	if (len > 0) {
1585 		rtw_mbo_build_mbo_ie_hdr(pframe, pattrib, len);
1586 		rtw_mbo_build_ap_cap_Indication_attr(
1587 			padapter, pframe, pattrib, pmbo_attr->ap_cap_ind);
1588 		if (pmbo_attr->assoc_disallow > 0) {
1589 			rtw_mbo_build_ap_disallowed_attr(padapter, pframe,
1590 				pattrib, pmbo_attr->assoc_disallow);
1591 		}
1592 	}
1593 
1594 }
1595 
rtw_mbo_build_wnm_btmreq_reason_ies(_adapter * padapter,u8 ** pframe,struct pkt_attrib * pattrib)1596 void rtw_mbo_build_wnm_btmreq_reason_ies(
1597 	_adapter *padapter, u8 **pframe, struct pkt_attrib *pattrib)
1598 {
1599 	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
1600 	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
1601 	WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network);
1602 	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
1603 	struct mbo_attr_info *pmbo_attr = &(pmlmepriv->mbo_attr);
1604 	struct mbo_user_btm_req_pkt *puser = &(pmbo_attr->user_raw);
1605 	u8 *pcap = NULL;
1606 	u32 len = 0, cap_len = 0 ;
1607 
1608 	if (!puser->append_mbo_ie)
1609 		return;
1610 
1611 	len += rtw_mbo_attr_sz_get(padapter, RTW_MBO_ATTR_AP_CAP_ID);
1612 	len += rtw_mbo_attr_sz_get(padapter, RTW_MBO_ATTR_TRANS_RES_ID);
1613 	len += rtw_mbo_attr_sz_get(padapter, RTW_MBO_ATTR_ASSOC_RETRY_DELAY_ID);
1614 
1615 	rtw_mbo_build_mbo_ie_hdr(pframe, pattrib, len);
1616 
1617 	rtw_mbo_build_ap_cap_Indication_attr(
1618 			padapter, pframe, pattrib, pmbo_attr->ap_cap_ind);
1619 
1620 	rtw_mbo_build_ap_trans_reason_attr(padapter, pframe,
1621 			pattrib, pmbo_attr->reason);
1622 
1623 	rtw_mbo_build_ap_assoc_retry_delay_attr(padapter, pframe,
1624 			pattrib, pmbo_attr->delay);
1625 }
1626 #endif /* CONFIG_RTW_MBO */
1627