• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  * Copyright(c) 2016 - 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 /*************************************************************
16  * Description:
17  *
18  * This file is for TXBF interface mechanism
19  *
20  ************************************************************/
21 #include "mp_precomp.h"
22 #include "../phydm_precomp.h"
23 
24 #ifdef PHYDM_BEAMFORMING_SUPPORT
25 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
beamforming_gid_paid(void * adapter,PRT_TCB tcb)26 void beamforming_gid_paid(
27 	void *adapter,
28 	PRT_TCB tcb)
29 {
30 	u8 RA[6] = {0};
31 	u8 *p_header = GET_FRAME_OF_FIRST_FRAG(adapter, tcb);
32 	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(((PADAPTER)adapter));
33 	struct dm_struct *dm = &hal_data->DM_OutSrc;
34 	struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
35 
36 	if (((PADAPTER)adapter)->HardwareType < HARDWARE_TYPE_RTL8192EE)
37 		return;
38 	else if (IS_WIRELESS_MODE_N((PADAPTER)adapter) == false)
39 		return;
40 
41 #if (SUPPORT_MU_BF == 1)
42 	if (tcb->tx_bf_pkt_type == RT_BF_PKT_TYPE_BROADCAST_NDPA) { /* @MU NDPA */
43 #else
44 	if (0) {
45 #endif
46 		/* @Fill G_ID and P_AID */
47 		tcb->G_ID = 63;
48 		if (beam_info->first_mu_bfee_index < BEAMFORMEE_ENTRY_NUM) {
49 			tcb->P_AID = beam_info->beamformee_entry[beam_info->first_mu_bfee_index].p_aid;
50 			RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s End, G_ID=0x%X, P_AID=0x%X\n", __func__, tcb->G_ID, tcb->P_AID));
51 		}
52 	} else {
53 		GET_80211_HDR_ADDRESS1(p_header, &RA);
54 
55 		/* VHT SU PPDU carrying one or more group addressed MPDUs or */
56 		/* Transmitting a VHT NDP intended for multiple recipients */
57 		if (MacAddr_isBcst(RA) || MacAddr_isMulticast(RA) || tcb->macId == MAC_ID_STATIC_FOR_BROADCAST_MULTICAST) {
58 			tcb->G_ID = 63;
59 			tcb->P_AID = 0;
60 		} else if (ACTING_AS_AP(adapter)) {
61 			u16 AID = (u16)(MacIdGetOwnerAssociatedClientAID(adapter, tcb->macId) & 0x1ff); /*@AID[0:8]*/
62 
63 			/*RT_DISP(FBEAM, FBEAM_FUN, ("@%s  tcb->mac_id=0x%X, AID=0x%X\n", __func__, tcb->mac_id, AID));*/
64 			tcb->G_ID = 63;
65 
66 			if (AID == 0) /*@A PPDU sent by an AP to a non associated STA*/
67 				tcb->P_AID = 0;
68 			else { /*Sent by an AP and addressed to a STA associated with that AP*/
69 				u16 BSSID = 0;
70 				GET_80211_HDR_ADDRESS2(p_header, &RA);
71 				BSSID = ((RA[5] & 0xf0) >> 4) ^ (RA[5] & 0xf); /*@BSSID[44:47] xor BSSID[40:43]*/
72 				tcb->P_AID = (AID + BSSID * 32) & 0x1ff; /*@(dec(A) + dec(B)*32) mod 512*/
73 			}
74 		} else if (ACTING_AS_IBSS(((PADAPTER)adapter))) {
75 			tcb->G_ID = 63;
76 			/*P_AID for infrasturcture mode; MACID for ad-hoc mode. */
77 			tcb->P_AID = tcb->macId;
78 		} else if (MgntLinkStatusQuery(adapter)) { /*@Addressed to AP*/
79 			tcb->G_ID = 0;
80 			GET_80211_HDR_ADDRESS1(p_header, &RA);
81 			tcb->P_AID = RA[5]; /*RA[39:47]*/
82 			tcb->P_AID = (tcb->P_AID << 1) | (RA[4] >> 7);
83 		} else {
84 			tcb->G_ID = 63;
85 			tcb->P_AID = 0;
86 		}
87 		/*RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s End, G_ID=0x%X, P_AID=0x%X\n", __func__, tcb->G_ID, tcb->P_AID));*/
88 	}
89 }
90 
91 enum rt_status
92 beamforming_get_report_frame(
93 	void *adapter,
94 	PRT_RFD rfd,
95 	POCTET_STRING p_pdu_os)
96 {
97 	HAL_DATA_TYPE *hal_data = GET_HAL_DATA((PADAPTER)adapter);
98 	struct dm_struct *dm = &hal_data->DM_OutSrc;
99 	struct _RT_BEAMFORMEE_ENTRY *beamform_entry = NULL;
100 	u8 *p_mimo_ctrl_field, p_csi_matrix;
101 	u8 idx, nc, nr, CH_W;
102 	u16 csi_matrix_len = 0;
103 
104 	ACT_PKT_TYPE pkt_type = ACT_PKT_TYPE_UNKNOWN;
105 
106 	/* @Memory comparison to see if CSI report is the same with previous one */
107 	beamform_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, Frame_Addr2(*p_pdu_os), &idx);
108 
109 	if (beamform_entry == NULL) {
110 		PHYDM_DBG(dm, DBG_TXBF, "%s: Cannot find entry by addr\n",
111 			  __func__);
112 		return RT_STATUS_FAILURE;
113 	}
114 
115 	pkt_type = PacketGetActionFrameType(p_pdu_os);
116 
117 	/* @-@ Modified by David */
118 	if (pkt_type == ACT_PKT_VHT_COMPRESSED_BEAMFORMING) {
119 		p_mimo_ctrl_field = p_pdu_os->Octet + 26;
120 		nc = ((*p_mimo_ctrl_field) & 0x7) + 1;
121 		nr = (((*p_mimo_ctrl_field) & 0x38) >> 3) + 1;
122 		CH_W = (((*p_mimo_ctrl_field) & 0xC0) >> 6);
123 		/*p_csi_matrix = p_mimo_ctrl_field + 3 + nc;*/ /* 24+(1+1+3)+2  MAC header+(Category+ActionCode+MIMOControlField) +SNR(nc=2) */
124 		csi_matrix_len = p_pdu_os->Length - 26 - 3 - nc;
125 	} else if (pkt_type == ACT_PKT_HT_COMPRESSED_BEAMFORMING) {
126 		p_mimo_ctrl_field = p_pdu_os->Octet + 26;
127 		nc = ((*p_mimo_ctrl_field) & 0x3) + 1;
128 		nr = (((*p_mimo_ctrl_field) & 0xC) >> 2) + 1;
129 		CH_W = (((*p_mimo_ctrl_field) & 0x10) >> 4);
130 		/*p_csi_matrix = p_mimo_ctrl_field + 6 + nr;*/ /* 24+(1+1+6)+2  MAC header+(Category+ActionCode+MIMOControlField) +SNR(nc=2) */
131 		csi_matrix_len = p_pdu_os->Length - 26 - 6 - nr;
132 	} else
133 		return RT_STATUS_SUCCESS;
134 
135 	PHYDM_DBG(dm, DBG_TXBF,
136 		  "[%s] idx=%d, pkt type=%d, nc=%d, nr=%d, CH_W=%d\n", __func__,
137 		  idx, pkt_type, nc, nr, CH_W);
138 
139 	return RT_STATUS_SUCCESS;
140 }
141 
142 void construct_ht_ndpa_packet(
143 	// 2017/11 MH PHYDM compile. But why need to use windows maco?
144 	// For all linux code, it should be useless?
145 	//void				*adapter = dm->adapter;
146 	ADAPTER * adapter,
147 	//void		*adapter,
148 	u8 *RA,
149 	u8 *buffer,
150 	u32 *p_length,
151 	enum channel_width BW)
152 {
153 	u16 duration = 0;
154 	PMGNT_INFO mgnt_info = &(((PADAPTER)adapter)->MgntInfo);
155 	//PMGNT_INFO				mgnt_info = &((MGNT_INFO)(((PADAPTER)adapter)->MgntInfo));
156 	OCTET_STRING p_ndpa_frame, action_content;
157 	u8 action_hdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c};
158 
159 	PlatformZeroMemory(buffer, 32);
160 
161 	SET_80211_HDR_FRAME_CONTROL(buffer, 0);
162 
163 	SET_80211_HDR_ORDER(buffer, 1);
164 	SET_80211_HDR_TYPE_AND_SUBTYPE(buffer, Type_Action_No_Ack);
165 
166 	SET_80211_HDR_ADDRESS1(buffer, RA);
167 	SET_80211_HDR_ADDRESS2(buffer, ((PADAPTER)adapter)->CurrentAddress);
168 	SET_80211_HDR_ADDRESS3(buffer, ((PMGNT_INFO)mgnt_info)->Bssid);
169 
170 	duration = 2 * a_SifsTime + 40;
171 
172 	if (BW == CHANNEL_WIDTH_40)
173 		duration += 87;
174 	else
175 		duration += 180;
176 
177 	SET_80211_HDR_DURATION(buffer, duration);
178 
179 	/* @HT control field */
180 	SET_HT_CTRL_CSI_STEERING(buffer + sMacHdrLng, 3);
181 	SET_HT_CTRL_NDP_ANNOUNCEMENT(buffer + sMacHdrLng, 1);
182 
183 	FillOctetString(p_ndpa_frame, buffer, sMacHdrLng + sHTCLng);
184 
185 	FillOctetString(action_content, action_hdr, 4);
186 	PacketAppendData(&p_ndpa_frame, action_content);
187 
188 	*p_length = 32;
189 }
190 
191 boolean
192 send_fw_ht_ndpa_packet(
193 	void *dm_void,
194 	u8 *RA,
195 	enum channel_width BW)
196 {
197 	struct dm_struct *dm = (struct dm_struct *)dm_void;
198 	void *adapter = dm->adapter;
199 	PRT_TCB tcb;
200 	PRT_TX_LOCAL_BUFFER p_buf;
201 	boolean ret = true;
202 	u32 buf_len;
203 	u8 *buf_addr;
204 	u8 desc_len = 0, idx = 0, ndp_tx_rate;
205 	void *p_def_adapter = GetDefaultAdapter(((PADAPTER)adapter));
206 	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(((PADAPTER)adapter));
207 	struct _RT_BEAMFORMEE_ENTRY *beamform_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);
208 
209 	PHYDM_DBG(dm, DBG_TXBF, "[%s] Start!\n", __func__);
210 
211 	if (beamform_entry == NULL)
212 		return false;
213 
214 	ndp_tx_rate = beamforming_get_htndp_tx_rate(dm, beamform_entry->comp_steering_num_of_bfer);
215 	PHYDM_DBG(dm, DBG_TXBF, "[%s] ndp_tx_rate =%d\n", __func__,
216 		  ndp_tx_rate);
217 	PlatformAcquireSpinLock(adapter, RT_TX_SPINLOCK);
218 
219 	if (MgntGetFWBuffer(p_def_adapter, &tcb, &p_buf)) {
220 #if (DEV_BUS_TYPE != RT_PCI_INTERFACE)
221 		desc_len = ((PADAPTER)adapter)->HWDescHeadLength - hal_data->USBALLDummyLength;
222 #endif
223 		buf_addr = p_buf->Buffer.VirtualAddress + desc_len;
224 
225 		construct_ht_ndpa_packet(
226 			adapter,
227 			RA,
228 			buf_addr,
229 			&buf_len,
230 			BW);
231 
232 		tcb->PacketLength = buf_len + desc_len;
233 
234 		tcb->bTxEnableSwCalcDur = true;
235 
236 		tcb->BWOfPacket = BW;
237 
238 		if (ACTING_AS_IBSS(((PADAPTER)adapter)) || ACTING_AS_AP(((PADAPTER)adapter)))
239 			tcb->G_ID = 63;
240 
241 		tcb->P_AID = beamform_entry->p_aid;
242 		tcb->DataRate = ndp_tx_rate; /*rate of NDP decide by nr*/
243 
244 		((PADAPTER)adapter)->HalFunc.CmdSendPacketHandler(((PADAPTER)adapter), tcb, p_buf, tcb->PacketLength, DESC_PACKET_TYPE_NORMAL, false);
245 	} else
246 		ret = false;
247 
248 	PlatformReleaseSpinLock(adapter, RT_TX_SPINLOCK);
249 
250 	if (ret)
251 		RT_DISP_DATA(FBEAM, FBEAM_DATA, "", p_buf->Buffer.VirtualAddress, tcb->PacketLength);
252 
253 	return ret;
254 }
255 
256 boolean
257 send_sw_ht_ndpa_packet(
258 	void *dm_void,
259 	u8 *RA,
260 	enum channel_width BW)
261 {
262 	struct dm_struct *dm = (struct dm_struct *)dm_void;
263 	void *adapter = dm->adapter;
264 	PRT_TCB tcb;
265 	PRT_TX_LOCAL_BUFFER p_buf;
266 	boolean ret = true;
267 	u8 idx = 0, ndp_tx_rate = 0;
268 	struct _RT_BEAMFORMEE_ENTRY *beamform_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);
269 
270 	PHYDM_DBG(dm, DBG_TXBF, "[%s] Start!\n", __func__);
271 
272 	ndp_tx_rate = beamforming_get_htndp_tx_rate(dm, beamform_entry->comp_steering_num_of_bfer);
273 	PHYDM_DBG(dm, DBG_TXBF, "[%s] ndp_tx_rate =%d\n", __func__,
274 		  ndp_tx_rate);
275 
276 	PlatformAcquireSpinLock(adapter, RT_TX_SPINLOCK);
277 
278 	if (MgntGetBuffer(adapter, &tcb, &p_buf)) {
279 		construct_ht_ndpa_packet(
280 			adapter,
281 			RA,
282 			p_buf->Buffer.VirtualAddress,
283 			&tcb->PacketLength,
284 			BW);
285 
286 		tcb->bTxEnableSwCalcDur = true;
287 
288 		tcb->BWOfPacket = BW;
289 
290 		MgntSendPacket(adapter, tcb, p_buf, tcb->PacketLength, NORMAL_QUEUE, ndp_tx_rate);
291 	} else
292 		ret = false;
293 
294 	PlatformReleaseSpinLock(adapter, RT_TX_SPINLOCK);
295 
296 	if (ret)
297 		RT_DISP_DATA(FBEAM, FBEAM_DATA, "", p_buf->Buffer.VirtualAddress, tcb->PacketLength);
298 
299 	return ret;
300 }
301 
302 void construct_vht_ndpa_packet(
303 	struct dm_struct *dm,
304 	u8 *RA,
305 	u16 AID,
306 	u8 *buffer,
307 	u32 *p_length,
308 	enum channel_width BW)
309 {
310 	u16 duration = 0;
311 	u8 sequence = 0;
312 	u8 *p_ndpa_frame = buffer;
313 	struct _RT_NDPA_STA_INFO sta_info;
314 	// 2017/11 MH PHYDM compile. But why need to use windows maco?
315 	// For all linux code, it should be useless?
316 	//void				*adapter = dm->adapter;
317 	ADAPTER * adapter = (PADAPTER)(dm->adapter);
318 	u8 idx = 0;
319 	struct _RT_BEAMFORMEE_ENTRY *beamform_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);
320 	/* @Frame control. */
321 	SET_80211_HDR_FRAME_CONTROL(p_ndpa_frame, 0);
322 	SET_80211_HDR_TYPE_AND_SUBTYPE(p_ndpa_frame, Type_NDPA);
323 
324 	SET_80211_HDR_ADDRESS1(p_ndpa_frame, RA);
325 	SET_80211_HDR_ADDRESS2(p_ndpa_frame, beamform_entry->my_mac_addr);
326 
327 	// 2017/11 MH PHYDM compile. But why need to use windows maco?
328 	// For all linux code, it should be useless?
329 	duration = 2 * a_SifsTime + 44;
330 
331 	if (BW == CHANNEL_WIDTH_80)
332 		duration += 40;
333 	else if (BW == CHANNEL_WIDTH_40)
334 		duration += 87;
335 	else
336 		duration += 180;
337 
338 	SET_80211_HDR_DURATION(p_ndpa_frame, duration);
339 
340 	sequence = *(dm->sounding_seq) << 2;
341 	odm_move_memory(dm, p_ndpa_frame + 16, &sequence, 1);
342 
343 	if (phydm_acting_determine(dm, phydm_acting_as_ibss) || phydm_acting_determine(dm, phydm_acting_as_ap) == false)
344 		AID = 0;
345 
346 	sta_info.aid = AID;
347 	sta_info.feedback_type = 0;
348 	sta_info.nc_index = 0;
349 
350 	odm_move_memory(dm, p_ndpa_frame + 17, (u8 *)&sta_info, 2);
351 
352 	*p_length = 19;
353 }
354 
355 boolean
356 send_fw_vht_ndpa_packet(
357 	void *dm_void,
358 	u8 *RA,
359 	u16 AID,
360 	enum channel_width BW)
361 {
362 	struct dm_struct *dm = (struct dm_struct *)dm_void;
363 	void *adapter = dm->adapter;
364 	PRT_TCB tcb;
365 	PRT_TX_LOCAL_BUFFER p_buf;
366 	boolean ret = true;
367 	u32 buf_len;
368 	u8 *buf_addr;
369 	u8 desc_len = 0, idx = 0, ndp_tx_rate = 0;
370 	void *p_def_adapter = GetDefaultAdapter(((PADAPTER)adapter));
371 	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(((PADAPTER)adapter));
372 	struct _RT_BEAMFORMEE_ENTRY *beamform_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);
373 
374 	PHYDM_DBG(dm, DBG_TXBF, "[%s] Start!\n", __func__);
375 
376 	if (beamform_entry == NULL)
377 		return false;
378 
379 	ndp_tx_rate = beamforming_get_vht_ndp_tx_rate(dm, beamform_entry->comp_steering_num_of_bfer);
380 	PHYDM_DBG(dm, DBG_TXBF, "[%s] ndp_tx_rate =%d\n", __func__,
381 		  ndp_tx_rate);
382 
383 	PlatformAcquireSpinLock(adapter, RT_TX_SPINLOCK);
384 
385 	if (MgntGetFWBuffer(p_def_adapter, &tcb, &p_buf)) {
386 #if (DEV_BUS_TYPE != RT_PCI_INTERFACE)
387 		desc_len = ((PADAPTER)adapter)->HWDescHeadLength - hal_data->USBALLDummyLength;
388 #endif
389 		buf_addr = p_buf->Buffer.VirtualAddress + desc_len;
390 
391 		construct_vht_ndpa_packet(
392 			dm,
393 			RA,
394 			AID,
395 			buf_addr,
396 			&buf_len,
397 			BW);
398 
399 		tcb->PacketLength = buf_len + desc_len;
400 
401 		tcb->bTxEnableSwCalcDur = true;
402 
403 		tcb->BWOfPacket = BW;
404 
405 		if (phydm_acting_determine(dm, phydm_acting_as_ibss) || phydm_acting_determine(dm, phydm_acting_as_ap))
406 			tcb->G_ID = 63;
407 
408 		tcb->P_AID = beamform_entry->p_aid;
409 		tcb->DataRate = ndp_tx_rate; /*@decide by nr*/
410 
411 		((PADAPTER)adapter)->HalFunc.CmdSendPacketHandler(adapter, tcb, p_buf, tcb->PacketLength, DESC_PACKET_TYPE_NORMAL, false);
412 	} else
413 		ret = false;
414 
415 	PlatformReleaseSpinLock(adapter, RT_TX_SPINLOCK);
416 
417 	PHYDM_DBG(dm, DBG_TXBF, "[%s] End, ret=%d\n", __func__, ret);
418 
419 	if (ret)
420 		RT_DISP_DATA(FBEAM, FBEAM_DATA, "", p_buf->Buffer.VirtualAddress, tcb->PacketLength);
421 
422 	return ret;
423 }
424 
425 boolean
426 send_sw_vht_ndpa_packet(
427 	void *dm_void,
428 	u8 *RA,
429 	u16 AID,
430 	enum channel_width BW)
431 {
432 	struct dm_struct *dm = (struct dm_struct *)dm_void;
433 	void *adapter = dm->adapter;
434 	PRT_TCB tcb;
435 	PRT_TX_LOCAL_BUFFER p_buf;
436 	boolean ret = true;
437 	u8 idx = 0, ndp_tx_rate = 0;
438 	struct _RT_BEAMFORMEE_ENTRY *beamform_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);
439 
440 	ndp_tx_rate = beamforming_get_vht_ndp_tx_rate(dm, beamform_entry->comp_steering_num_of_bfer);
441 	PHYDM_DBG(dm, DBG_TXBF, "[%s] ndp_tx_rate =%d\n", __func__,
442 		  ndp_tx_rate);
443 
444 	PlatformAcquireSpinLock(adapter, RT_TX_SPINLOCK);
445 
446 	if (MgntGetBuffer(adapter, &tcb, &p_buf)) {
447 		construct_vht_ndpa_packet(
448 			dm,
449 			RA,
450 			AID,
451 			p_buf->Buffer.VirtualAddress,
452 			&tcb->PacketLength,
453 			BW);
454 
455 		tcb->bTxEnableSwCalcDur = true;
456 		tcb->BWOfPacket = BW;
457 
458 		/*rate of NDP decide by nr*/
459 		MgntSendPacket(adapter, tcb, p_buf, tcb->PacketLength, NORMAL_QUEUE, ndp_tx_rate);
460 	} else
461 		ret = false;
462 
463 	PlatformReleaseSpinLock(adapter, RT_TX_SPINLOCK);
464 
465 	if (ret)
466 		RT_DISP_DATA(FBEAM, FBEAM_DATA, "", p_buf->Buffer.VirtualAddress, tcb->PacketLength);
467 
468 	return ret;
469 }
470 
471 #ifdef SUPPORT_MU_BF
472 #if (SUPPORT_MU_BF == 1)
473 /*@
474  * Description: On VHT GID management frame by an MU beamformee.
475  *
476  * 2015.05.20. Created by tynli.
477  */
478 enum rt_status
479 beamforming_get_vht_gid_mgnt_frame(
480 	void *adapter,
481 	PRT_RFD rfd,
482 	POCTET_STRING p_pdu_os)
483 {
484 	HAL_DATA_TYPE *hal_data = GET_HAL_DATA(((PADAPTER)adapter));
485 	struct dm_struct *dm = &hal_data->DM_OutSrc;
486 	enum rt_status rt_status = RT_STATUS_SUCCESS;
487 	u8 *p_buffer = NULL;
488 	u8 *p_raddr = NULL;
489 	u8 mem_status[8] = {0}, user_pos[16] = {0};
490 	u8 idx;
491 	struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
492 	struct _RT_BEAMFORMER_ENTRY *beamform_entry = &beam_info->beamformer_entry[beam_info->mu_ap_index];
493 
494 	PHYDM_DBG(dm, DBG_TXBF, "[%s] On VHT GID mgnt frame!\n", __func__);
495 
496 	/* @Check length*/
497 	if (p_pdu_os->length < (FRAME_OFFSET_VHT_GID_MGNT_USER_POSITION_ARRAY + 16)) {
498 		PHYDM_DBG(dm, DBG_TXBF, "%s: Invalid length (%d)\n", __func__,
499 			  p_pdu_os->length);
500 		return RT_STATUS_INVALID_LENGTH;
501 	}
502 
503 	/* @Check RA*/
504 	p_raddr = (u8 *)(p_pdu_os->Octet) + 4;
505 	if (!eq_mac_addr(p_raddr, adapter->CurrentAddress)) {
506 		PHYDM_DBG(dm, DBG_TXBF, "%s: Drop because of RA error.\n",
507 			  __func__);
508 		return RT_STATUS_PKT_DROP;
509 	}
510 
511 	RT_DISP_DATA(FBEAM, FBEAM_DATA, "On VHT GID Mgnt Frame ==>:\n", p_pdu_os->Octet, p_pdu_os->length);
512 
513 	/*Parsing Membership status array*/
514 	p_buffer = p_pdu_os->Octet + FRAME_OFFSET_VHT_GID_MGNT_MEMBERSHIP_STATUS_ARRAY;
515 	for (idx = 0; idx < 8; idx++) {
516 		mem_status[idx] = GET_VHT_GID_MGNT_INFO_MEMBERSHIP_STATUS(p_buffer + idx);
517 		beamform_entry->gid_valid[idx] = GET_VHT_GID_MGNT_INFO_MEMBERSHIP_STATUS(p_buffer + idx);
518 	}
519 
520 	RT_DISP_DATA(FBEAM, FBEAM_DATA, "mem_status: ", mem_status, 8);
521 
522 	/* Parsing User Position array*/
523 	p_buffer = p_pdu_os->Octet + FRAME_OFFSET_VHT_GID_MGNT_USER_POSITION_ARRAY;
524 	for (idx = 0; idx < 16; idx++) {
525 		user_pos[idx] = GET_VHT_GID_MGNT_INFO_USER_POSITION(p_buffer + idx);
526 		beamform_entry->user_position[idx] = GET_VHT_GID_MGNT_INFO_USER_POSITION(p_buffer + idx);
527 	}
528 
529 	RT_DISP_DATA(FBEAM, FBEAM_DATA, "user_pos: ", user_pos, 16);
530 
531 	/* @Group ID detail printed*/
532 	{
533 		u8 i, j;
534 		u8 tmp_val;
535 		u16 tmp_val2;
536 
537 		for (i = 0; i < 8; i++) {
538 			tmp_val = mem_status[i];
539 			tmp_val2 = ((user_pos[i * 2 + 1] << 8) & 0xFF00) + (user_pos[i * 2] & 0xFF);
540 			for (j = 0; j < 8; j++) {
541 				if ((tmp_val >> j) & BIT(0)) {
542 					PHYDM_DBG(dm, DBG_TXBF, "Use Group ID (%d), User Position (%d)\n",
543 						  (i * 8 + j), (tmp_val2 >> 2 * j) & 0x3);
544 				}
545 			}
546 		}
547 	}
548 
549 	/* @Indicate GID frame to IHV service. */
550 	{
551 		u8 indibuffer[24] = {0};
552 		u8 indioffset = 0;
553 
554 		PlatformMoveMemory(indibuffer + indioffset, beamform_entry->gid_valid, 8);
555 		indioffset += 8;
556 		PlatformMoveMemory(indibuffer + indioffset, beamform_entry->user_position, 16);
557 		indioffset += 16;
558 
559 		PlatformIndicateCustomStatus(
560 			adapter,
561 			RT_CUSTOM_EVENT_VHT_RECV_GID_MGNT_FRAME,
562 			RT_CUSTOM_INDI_TARGET_IHV,
563 			indibuffer,
564 			indioffset);
565 	}
566 
567 	/* @Config HW GID table */
568 	hal_com_txbf_config_gtab(dm);
569 
570 	return rt_status;
571 }
572 
573 /*@
574  * Description: Construct VHT Group ID (GID) management frame.
575  *
576  * 2015.05.20. Created by tynli.
577  */
578 void construct_vht_gid_mgnt_frame(
579 	struct dm_struct *dm,
580 	u8 *RA,
581 	struct _RT_BEAMFORMEE_ENTRY *beamform_entry,
582 	u8 *buffer,
583 	u32 *p_length
584 
585 	)
586 {
587 	struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
588 	void *adapter = beam_info->source_adapter;
589 	OCTET_STRING os_ftm_frame, tmp;
590 
591 	FillOctetString(os_ftm_frame, buffer, 0);
592 	*p_length = 0;
593 
594 	ConstructMaFrameHdr(
595 		adapter,
596 		RA,
597 		ACT_CAT_VHT,
598 		ACT_VHT_GROUPID_MANAGEMENT,
599 		&os_ftm_frame);
600 
601 	/* @Membership status array*/
602 	FillOctetString(tmp, beamform_entry->gid_valid, 8);
603 	PacketAppendData(&os_ftm_frame, tmp);
604 
605 	/* User Position array*/
606 	FillOctetString(tmp, beamform_entry->user_position, 16);
607 	PacketAppendData(&os_ftm_frame, tmp);
608 
609 	*p_length = os_ftm_frame.length;
610 
611 	RT_DISP_DATA(FBEAM, FBEAM_DATA, "construct_vht_gid_mgnt_frame():\n", buffer, *p_length);
612 }
613 
614 boolean
615 send_sw_vht_gid_mgnt_frame(
616 	void *dm_void,
617 	u8 *RA,
618 	u8 idx)
619 {
620 	struct dm_struct *dm = (struct dm_struct *)dm_void;
621 	PRT_TCB tcb;
622 	PRT_TX_LOCAL_BUFFER p_buf;
623 	boolean ret = true;
624 	u8 data_rate = 0;
625 	struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
626 	struct _RT_BEAMFORMEE_ENTRY *beamform_entry = &beam_info->beamformee_entry[idx];
627 	void *adapter = beam_info->source_adapter;
628 
629 	PHYDM_DBG(dm, DBG_TXBF, "[%s] Start!\n", __func__);
630 
631 	PlatformAcquireSpinLock(adapter, RT_TX_SPINLOCK);
632 
633 	if (MgntGetBuffer(adapter, &tcb, &p_buf)) {
634 		construct_vht_gid_mgnt_frame(
635 			dm,
636 			RA,
637 			beamform_entry,
638 			p_buf->Buffer.VirtualAddress,
639 			&tcb->PacketLength);
640 
641 		tcb->bw_of_packet = CHANNEL_WIDTH_20;
642 		data_rate = MGN_6M;
643 		MgntSendPacket(adapter, tcb, p_buf, tcb->PacketLength, NORMAL_QUEUE, data_rate);
644 	} else
645 		ret = false;
646 
647 	PlatformReleaseSpinLock(adapter, RT_TX_SPINLOCK);
648 
649 	if (ret)
650 		RT_DISP_DATA(FBEAM, FBEAM_DATA, "", p_buf->Buffer.VirtualAddress, tcb->PacketLength);
651 
652 	return ret;
653 }
654 
655 /*@
656  * Description: Construct VHT beamforming report poll.
657  *
658  * 2015.05.20. Created by tynli.
659  */
660 void construct_vht_bf_report_poll(
661 	struct dm_struct *dm,
662 	u8 *RA,
663 	u8 *buffer,
664 	u32 *p_length)
665 {
666 	struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
667 	void *adapter = beam_info->source_adapter;
668 	u8 *p_bf_rpt_poll = buffer;
669 
670 	/* @Frame control*/
671 	SET_80211_HDR_FRAME_CONTROL(p_bf_rpt_poll, 0);
672 	SET_80211_HDR_TYPE_AND_SUBTYPE(p_bf_rpt_poll, Type_Beamforming_Report_Poll);
673 
674 	/* @duration*/
675 	SET_80211_HDR_DURATION(p_bf_rpt_poll, 100);
676 
677 	/* RA*/
678 	SET_VHT_BF_REPORT_POLL_RA(p_bf_rpt_poll, RA);
679 
680 	/* TA*/
681 	SET_VHT_BF_REPORT_POLL_TA(p_bf_rpt_poll, adapter->CurrentAddress);
682 
683 	/* @Feedback Segment Retransmission Bitmap*/
684 	SET_VHT_BF_REPORT_POLL_FEEDBACK_SEG_RETRAN_BITMAP(p_bf_rpt_poll, 0xFF);
685 
686 	*p_length = 17;
687 
688 	RT_DISP_DATA(FBEAM, FBEAM_DATA, "construct_vht_bf_report_poll():\n", buffer, *p_length);
689 }
690 
691 boolean
692 send_sw_vht_bf_report_poll(
693 	void *dm_void,
694 	u8 *RA,
695 	boolean is_final_poll)
696 {
697 	struct dm_struct *dm = (struct dm_struct *)dm_void;
698 	PRT_TCB tcb;
699 	PRT_TX_LOCAL_BUFFER p_buf;
700 	boolean ret = true;
701 	u8 idx = 0, data_rate = 0;
702 	struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
703 	struct _RT_BEAMFORMEE_ENTRY *beamform_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);
704 	void *adapter = beam_info->source_adapter;
705 
706 	PHYDM_DBG(dm, DBG_TXBF, "[%s] Start!\n", __func__);
707 
708 	PlatformAcquireSpinLock(adapter, RT_TX_SPINLOCK);
709 
710 	if (MgntGetBuffer(adapter, &tcb, &p_buf)) {
711 		construct_vht_bf_report_poll(
712 			dm,
713 			RA,
714 			p_buf->Buffer.VirtualAddress,
715 			&tcb->PacketLength);
716 
717 		tcb->bTxEnableSwCalcDur = true; /* @<tynli_note> need?*/
718 		tcb->BWOfPacket = CHANNEL_WIDTH_20;
719 
720 		if (is_final_poll)
721 			tcb->TxBFPktType = RT_BF_PKT_TYPE_FINAL_BF_REPORT_POLL;
722 		else
723 			tcb->TxBFPktType = RT_BF_PKT_TYPE_BF_REPORT_POLL;
724 
725 		data_rate = MGN_6M; /* @Legacy OFDM rate*/
726 		MgntSendPacket(adapter, tcb, p_buf, tcb->PacketLength, NORMAL_QUEUE, data_rate);
727 	} else
728 		ret = false;
729 
730 	PlatformReleaseSpinLock(adapter, RT_TX_SPINLOCK);
731 
732 	if (ret)
733 		RT_DISP_DATA(FBEAM, FBEAM_DATA, "send_sw_vht_bf_report_poll:\n",
734 		p_buf->Buffer.VirtualAddress, tcb->PacketLength);
735 
736 	return ret;
737 }
738 
739 /*@
740  * Description: Construct VHT MU NDPA packet.
741  *	<Note> We should combine this function with construct_vht_ndpa_packet() in the future.
742  *
743  * 2015.05.21. Created by tynli.
744  */
745 void construct_vht_mu_ndpa_packet(
746 	struct dm_struct *dm,
747 	enum channel_width BW,
748 	u8 *buffer,
749 	u32 *p_length)
750 {
751 	struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
752 	void *adapter = beam_info->source_adapter;
753 	u16 duration = 0;
754 	u8 sequence = 0;
755 	u8 *p_ndpa_frame = buffer;
756 	struct _RT_NDPA_STA_INFO sta_info;
757 	u8 idx;
758 	u8 dest_addr[6] = {0};
759 	struct _RT_BEAMFORMEE_ENTRY *entry = NULL;
760 
761 	/* @Fill the first MU BFee entry (STA1) MAC addr to destination address then
762 	     HW will change A1 to broadcast addr. 2015.05.28. Suggested by SD1 Chunchu. */
763 	for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {
764 		entry = &(beam_info->beamformee_entry[idx]);
765 		if (entry->is_mu_sta) {
766 			cp_mac_addr(dest_addr, entry->mac_addr);
767 			break;
768 		}
769 	}
770 	if (entry == NULL)
771 		return;
772 
773 	/* @Frame control.*/
774 	SET_80211_HDR_FRAME_CONTROL(p_ndpa_frame, 0);
775 	SET_80211_HDR_TYPE_AND_SUBTYPE(p_ndpa_frame, Type_NDPA);
776 
777 	SET_80211_HDR_ADDRESS1(p_ndpa_frame, dest_addr);
778 	SET_80211_HDR_ADDRESS2(p_ndpa_frame, entry->my_mac_addr);
779 
780 	/*@--------------------------------------------*/
781 	/* @<Note> Need to modify "duration" to MU consideration. */
782 	duration = 2 * a_SifsTime + 44;
783 
784 	if (BW == CHANNEL_WIDTH_80)
785 		duration += 40;
786 	else if (BW == CHANNEL_WIDTH_40)
787 		duration += 87;
788 	else
789 		duration += 180;
790 	/*@--------------------------------------------*/
791 
792 	SET_80211_HDR_DURATION(p_ndpa_frame, duration);
793 
794 	sequence = *(dm->sounding_seq) << 2;
795 	odm_move_memory(dm, p_ndpa_frame + 16, &sequence, 1);
796 
797 	*p_length = 17;
798 
799 	/* @Construct STA info. for multiple STAs*/
800 	for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {
801 		entry = &(beam_info->beamformee_entry[idx]);
802 		if (entry->is_mu_sta) {
803 			sta_info.aid = entry->AID;
804 			sta_info.feedback_type = 1; /* @1'b1: MU*/
805 			sta_info.nc_index = 0;
806 
807 			PHYDM_DBG(dm, DBG_TXBF,
808 				  "[%s] Get beamformee_entry idx(%d), AID =%d\n",
809 				  __func__, idx, entry->AID);
810 
811 			odm_move_memory(dm, p_ndpa_frame + (*p_length), (u8 *)&sta_info, 2);
812 			*p_length += 2;
813 		}
814 	}
815 }
816 
817 boolean
818 send_sw_vht_mu_ndpa_packet(
819 	void *dm_void,
820 	enum channel_width BW)
821 {
822 	struct dm_struct *dm = (struct dm_struct *)dm_void;
823 	PRT_TCB tcb;
824 	PRT_TX_LOCAL_BUFFER p_buf;
825 	boolean ret = true;
826 	u8 ndp_tx_rate = 0;
827 	struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
828 	void *adapter = beam_info->source_adapter;
829 
830 	ndp_tx_rate = MGN_VHT2SS_MCS0;
831 	PHYDM_DBG(dm, DBG_TXBF, "[%s] ndp_tx_rate =%d\n", __func__,
832 		  ndp_tx_rate);
833 
834 	PlatformAcquireSpinLock(adapter, RT_TX_SPINLOCK);
835 
836 	if (MgntGetBuffer(adapter, &tcb, &p_buf)) {
837 		construct_vht_mu_ndpa_packet(
838 			dm,
839 			BW,
840 			p_buf->Buffer.VirtualAddress,
841 			&tcb->PacketLength);
842 
843 		tcb->bTxEnableSwCalcDur = true;
844 		tcb->BWOfPacket = BW;
845 		tcb->TxBFPktType = RT_BF_PKT_TYPE_BROADCAST_NDPA;
846 
847 		/*rate of NDP decide by nr*/
848 		MgntSendPacket(adapter, tcb, p_buf, tcb->PacketLength, NORMAL_QUEUE, ndp_tx_rate);
849 	} else
850 		ret = false;
851 
852 	PlatformReleaseSpinLock(adapter, RT_TX_SPINLOCK);
853 
854 	if (ret)
855 		RT_DISP_DATA(FBEAM, FBEAM_DATA, "", p_buf->Buffer.VirtualAddress, tcb->PacketLength);
856 
857 	return ret;
858 }
859 
860 void dbg_construct_vht_mundpa_packet(
861 	struct dm_struct *dm,
862 	enum channel_width BW,
863 	u8 *buffer,
864 	u32 *p_length)
865 {
866 	struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
867 	void *adapter = beam_info->source_adapter;
868 	u16 duration = 0;
869 	u8 sequence = 0;
870 	u8 *p_ndpa_frame = buffer;
871 	struct _RT_NDPA_STA_INFO sta_info;
872 	u8 idx;
873 	u8 dest_addr[6] = {0};
874 	struct _RT_BEAMFORMEE_ENTRY *entry = NULL;
875 
876 	boolean is_STA1 = false;
877 
878 	/* @Fill the first MU BFee entry (STA1) MAC addr to destination address then
879 	     HW will change A1 to broadcast addr. 2015.05.28. Suggested by SD1 Chunchu. */
880 	for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) {
881 		entry = &(beam_info->beamformee_entry[idx]);
882 		if (entry->is_mu_sta) {
883 			if (is_STA1 == false) {
884 				is_STA1 = true;
885 				continue;
886 			} else {
887 				cp_mac_addr(dest_addr, entry->mac_addr);
888 				break;
889 			}
890 		}
891 	}
892 
893 	/* @Frame control.*/
894 	SET_80211_HDR_FRAME_CONTROL(p_ndpa_frame, 0);
895 	SET_80211_HDR_TYPE_AND_SUBTYPE(p_ndpa_frame, Type_NDPA);
896 
897 	SET_80211_HDR_ADDRESS1(p_ndpa_frame, dest_addr);
898 	SET_80211_HDR_ADDRESS2(p_ndpa_frame, dm->CurrentAddress);
899 
900 	/*@--------------------------------------------*/
901 	/* @<Note> Need to modify "duration" to MU consideration. */
902 	duration = 2 * a_SifsTime + 44;
903 
904 	if (BW == CHANNEL_WIDTH_80)
905 		duration += 40;
906 	else if (BW == CHANNEL_WIDTH_40)
907 		duration += 87;
908 	else
909 		duration += 180;
910 	/*@--------------------------------------------*/
911 
912 	SET_80211_HDR_DURATION(p_ndpa_frame, duration);
913 
914 	sequence = *(dm->sounding_seq) << 2;
915 	odm_move_memory(dm, p_ndpa_frame + 16, &sequence, 1);
916 
917 	*p_length = 17;
918 
919 	/*STA2's STA Info*/
920 	sta_info.aid = entry->aid;
921 	sta_info.feedback_type = 1; /* @1'b1: MU */
922 	sta_info.nc_index = 0;
923 
924 	PHYDM_DBG(dm, DBG_TXBF, "[%s] Get beamformee_entry idx(%d), AID =%d\n",
925 		  __func__, idx, entry->aid);
926 
927 	odm_move_memory(dm, p_ndpa_frame + (*p_length), (u8 *)&sta_info, 2);
928 	*p_length += 2;
929 }
930 
931 boolean
932 dbg_send_sw_vht_mundpa_packet(
933 	void *dm_void,
934 	enum channel_width BW)
935 {
936 	struct dm_struct *dm = (struct dm_struct *)dm_void;
937 	PRT_TCB tcb;
938 	PRT_TX_LOCAL_BUFFER p_buf;
939 	boolean ret = true;
940 	u8 ndp_tx_rate = 0;
941 	struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
942 	void *adapter = beam_info->source_adapter;
943 
944 	ndp_tx_rate = MGN_VHT2SS_MCS0;
945 	PHYDM_DBG(dm, DBG_TXBF, "[%s] ndp_tx_rate =%d\n", __func__,
946 		  ndp_tx_rate);
947 
948 	PlatformAcquireSpinLock(adapter, RT_TX_SPINLOCK);
949 
950 	if (MgntGetBuffer(adapter, &tcb, &p_buf)) {
951 		dbg_construct_vht_mundpa_packet(
952 			dm,
953 			BW,
954 			p_buf->Buffer.VirtualAddress,
955 			&tcb->PacketLength);
956 
957 		tcb->bTxEnableSwCalcDur = true;
958 		tcb->BWOfPacket = BW;
959 		tcb->TxBFPktType = RT_BF_PKT_TYPE_UNICAST_NDPA;
960 
961 		/*rate of NDP decide by nr*/
962 		MgntSendPacket(adapter, tcb, p_buf, tcb->PacketLength, NORMAL_QUEUE, ndp_tx_rate);
963 	} else
964 		ret = false;
965 
966 	PlatformReleaseSpinLock(adapter, RT_TX_SPINLOCK);
967 
968 	if (ret)
969 		RT_DISP_DATA(FBEAM, FBEAM_DATA, "", p_buf->Buffer.VirtualAddress, tcb->PacketLength);
970 
971 	return ret;
972 }
973 
974 #endif /*@#if (SUPPORT_MU_BF == 1)*/
975 #endif /*@#ifdef SUPPORT_MU_BF*/
976 
977 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
978 
979 u32 beamforming_get_report_frame(
980 	void *dm_void,
981 	union recv_frame *precv_frame)
982 {
983 	struct dm_struct *dm = (struct dm_struct *)dm_void;
984 	u32 ret = _SUCCESS;
985 	struct _RT_BEAMFORMEE_ENTRY *beamform_entry = NULL;
986 	u8 *pframe = precv_frame->u.hdr.rx_data;
987 	u32 frame_len = precv_frame->u.hdr.len;
988 	u8 *TA;
989 	u8 idx, offset;
990 
991 	/*@Memory comparison to see if CSI report is the same with previous one*/
992 	TA = get_addr2_ptr(pframe);
993 	beamform_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, TA, &idx);
994 	if (beamform_entry->beamform_entry_cap & BEAMFORMER_CAP_VHT_SU)
995 		offset = 31; /*@24+(1+1+3)+2  MAC header+(Category+ActionCode+MIMOControlField)+SNR(nc=2)*/
996 	else if (beamform_entry->beamform_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)
997 		offset = 34; /*@24+(1+1+6)+2  MAC header+(Category+ActionCode+MIMOControlField)+SNR(nc=2)*/
998 	else
999 		return ret;
1000 
1001 	return ret;
1002 }
1003 
1004 boolean
1005 send_fw_ht_ndpa_packet(
1006 	void *dm_void,
1007 	u8 *RA,
1008 	enum channel_width BW)
1009 {
1010 	struct dm_struct *dm = (struct dm_struct *)dm_void;
1011 	struct _ADAPTER *adapter = dm->adapter;
1012 	struct xmit_frame *pmgntframe;
1013 	struct pkt_attrib *pattrib;
1014 	struct rtw_ieee80211_hdr *pwlanhdr;
1015 	struct xmit_priv *pxmitpriv = &(adapter->xmitpriv);
1016 	struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
1017 	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
1018 	u8 action_hdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c};
1019 	u8 *pframe;
1020 	u16 *fctrl;
1021 	u16 duration = 0;
1022 	u8 a_sifs_time = 0, ndp_tx_rate = 0, idx = 0;
1023 	struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
1024 	struct _RT_BEAMFORMEE_ENTRY *beamform_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);
1025 
1026 	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
1027 
1028 	if (pmgntframe == NULL) {
1029 		PHYDM_DBG(dm, DBG_TXBF, "%s, alloc mgnt frame fail\n",
1030 			  __func__);
1031 		return false;
1032 	}
1033 
1034 	/* update attribute */
1035 	pattrib = &pmgntframe->attrib;
1036 	update_mgntframe_attrib(adapter, pattrib);
1037 
1038 	pattrib->qsel = QSLT_BEACON;
1039 	ndp_tx_rate = beamforming_get_htndp_tx_rate(dm, beamform_entry->comp_steering_num_of_bfer);
1040 	PHYDM_DBG(dm, DBG_TXBF, "[%s] ndp_tx_rate =%d\n", __func__,
1041 		  ndp_tx_rate);
1042 	pattrib->rate = ndp_tx_rate;
1043 	pattrib->bwmode = BW;
1044 	pattrib->order = 1;
1045 	pattrib->subtype = WIFI_ACTION_NOACK;
1046 
1047 	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
1048 
1049 	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
1050 
1051 	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
1052 
1053 	fctrl = &pwlanhdr->frame_ctl;
1054 	*(fctrl) = 0;
1055 
1056 	set_order_bit(pframe);
1057 	set_frame_sub_type(pframe, WIFI_ACTION_NOACK);
1058 
1059 	_rtw_memcpy(pwlanhdr->addr1, RA, ETH_ALEN);
1060 	_rtw_memcpy(pwlanhdr->addr2, beamform_entry->my_mac_addr, ETH_ALEN);
1061 	_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
1062 
1063 	if (pmlmeext->cur_wireless_mode == WIRELESS_11B)
1064 		a_sifs_time = 10;
1065 	else
1066 		a_sifs_time = 16;
1067 
1068 	duration = 2 * a_sifs_time + 40;
1069 
1070 	if (BW == CHANNEL_WIDTH_40)
1071 		duration += 87;
1072 	else
1073 		duration += 180;
1074 
1075 	set_duration(pframe, duration);
1076 
1077 	/* @HT control field */
1078 	SET_HT_CTRL_CSI_STEERING(pframe + 24, 3);
1079 	SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe + 24, 1);
1080 
1081 	_rtw_memcpy(pframe + 28, action_hdr, 4);
1082 
1083 	pattrib->pktlen = 32;
1084 
1085 	pattrib->last_txcmdsz = pattrib->pktlen;
1086 
1087 	dump_mgntframe(adapter, pmgntframe);
1088 
1089 	return true;
1090 }
1091 
1092 boolean
1093 send_sw_ht_ndpa_packet(
1094 	void *dm_void,
1095 	u8 *RA,
1096 	enum channel_width BW)
1097 {
1098 	struct dm_struct *dm = (struct dm_struct *)dm_void;
1099 	struct _ADAPTER *adapter = dm->adapter;
1100 	struct xmit_frame *pmgntframe;
1101 	struct pkt_attrib *pattrib;
1102 	struct rtw_ieee80211_hdr *pwlanhdr;
1103 	struct xmit_priv *pxmitpriv = &(adapter->xmitpriv);
1104 	struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
1105 	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
1106 	u8 action_hdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c};
1107 	u8 *pframe;
1108 	u16 *fctrl;
1109 	u16 duration = 0;
1110 	u8 a_sifs_time = 0, ndp_tx_rate = 0, idx = 0;
1111 	struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
1112 	struct _RT_BEAMFORMEE_ENTRY *beamform_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);
1113 
1114 	ndp_tx_rate = beamforming_get_htndp_tx_rate(dm, beamform_entry->comp_steering_num_of_bfer);
1115 
1116 	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
1117 
1118 	if (pmgntframe == NULL) {
1119 		PHYDM_DBG(dm, DBG_TXBF, "%s, alloc mgnt frame fail\n",
1120 			  __func__);
1121 		return false;
1122 	}
1123 
1124 	/*update attribute*/
1125 	pattrib = &pmgntframe->attrib;
1126 	update_mgntframe_attrib(adapter, pattrib);
1127 	pattrib->qsel = QSLT_MGNT;
1128 	pattrib->rate = ndp_tx_rate;
1129 	pattrib->bwmode = BW;
1130 	pattrib->order = 1;
1131 	pattrib->subtype = WIFI_ACTION_NOACK;
1132 
1133 	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
1134 
1135 	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
1136 
1137 	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
1138 
1139 	fctrl = &pwlanhdr->frame_ctl;
1140 	*(fctrl) = 0;
1141 
1142 	set_order_bit(pframe);
1143 	set_frame_sub_type(pframe, WIFI_ACTION_NOACK);
1144 
1145 	_rtw_memcpy(pwlanhdr->addr1, RA, ETH_ALEN);
1146 	_rtw_memcpy(pwlanhdr->addr2, beamform_entry->my_mac_addr, ETH_ALEN);
1147 	_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
1148 
1149 	if (pmlmeext->cur_wireless_mode == WIRELESS_11B)
1150 		a_sifs_time = 10;
1151 	else
1152 		a_sifs_time = 16;
1153 
1154 	duration = 2 * a_sifs_time + 40;
1155 
1156 	if (BW == CHANNEL_WIDTH_40)
1157 		duration += 87;
1158 	else
1159 		duration += 180;
1160 
1161 	set_duration(pframe, duration);
1162 
1163 	/*@HT control field*/
1164 	SET_HT_CTRL_CSI_STEERING(pframe + 24, 3);
1165 	SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe + 24, 1);
1166 
1167 	_rtw_memcpy(pframe + 28, action_hdr, 4);
1168 
1169 	pattrib->pktlen = 32;
1170 
1171 	pattrib->last_txcmdsz = pattrib->pktlen;
1172 
1173 	dump_mgntframe(adapter, pmgntframe);
1174 
1175 	return true;
1176 }
1177 
1178 boolean
1179 send_fw_vht_ndpa_packet(
1180 	void *dm_void,
1181 	u8 *RA,
1182 	u16 AID,
1183 	enum channel_width BW)
1184 {
1185 	struct dm_struct *dm = (struct dm_struct *)dm_void;
1186 	struct _ADAPTER *adapter = dm->adapter;
1187 	struct xmit_frame *pmgntframe;
1188 	struct pkt_attrib *pattrib;
1189 	struct rtw_ieee80211_hdr *pwlanhdr;
1190 	struct xmit_priv *pxmitpriv = &(adapter->xmitpriv);
1191 	struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
1192 	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
1193 	struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
1194 	u8 *pframe;
1195 	u16 *fctrl;
1196 	u16 duration = 0;
1197 	u8 sequence = 0, a_sifs_time = 0, ndp_tx_rate = 0, idx = 0;
1198 	struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
1199 	struct _RT_BEAMFORMEE_ENTRY *beamform_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);
1200 	struct _RT_NDPA_STA_INFO sta_info;
1201 
1202 	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
1203 
1204 	if (pmgntframe == NULL) {
1205 		PHYDM_DBG(dm, DBG_TXBF, "%s, alloc mgnt frame fail\n",
1206 			  __func__);
1207 		return false;
1208 	}
1209 
1210 	/* update attribute */
1211 	pattrib = &pmgntframe->attrib;
1212 	_rtw_memcpy(pattrib->ra, RA, ETH_ALEN);
1213 	update_mgntframe_attrib(adapter, pattrib);
1214 
1215 	pattrib->qsel = QSLT_BEACON;
1216 	ndp_tx_rate = beamforming_get_vht_ndp_tx_rate(dm, beamform_entry->comp_steering_num_of_bfer);
1217 	PHYDM_DBG(dm, DBG_TXBF, "[%s] ndp_tx_rate =%d\n", __func__,
1218 		  ndp_tx_rate);
1219 	pattrib->rate = ndp_tx_rate;
1220 	pattrib->bwmode = BW;
1221 	pattrib->subtype = WIFI_NDPA;
1222 
1223 	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
1224 
1225 	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
1226 
1227 	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
1228 
1229 	fctrl = &pwlanhdr->frame_ctl;
1230 	*(fctrl) = 0;
1231 
1232 	set_frame_sub_type(pframe, WIFI_NDPA);
1233 
1234 	_rtw_memcpy(pwlanhdr->addr1, RA, ETH_ALEN);
1235 	_rtw_memcpy(pwlanhdr->addr2, beamform_entry->my_mac_addr, ETH_ALEN);
1236 
1237 	if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode))
1238 		a_sifs_time = 16;
1239 	else
1240 		a_sifs_time = 10;
1241 
1242 	duration = 2 * a_sifs_time + 44;
1243 
1244 	if (BW == CHANNEL_WIDTH_80)
1245 		duration += 40;
1246 	else if (BW == CHANNEL_WIDTH_40)
1247 		duration += 87;
1248 	else
1249 		duration += 180;
1250 
1251 	set_duration(pframe, duration);
1252 
1253 	sequence = beam_info->sounding_sequence << 2;
1254 	if (beam_info->sounding_sequence >= 0x3f)
1255 		beam_info->sounding_sequence = 0;
1256 	else
1257 		beam_info->sounding_sequence++;
1258 
1259 	_rtw_memcpy(pframe + 16, &sequence, 1);
1260 
1261 	if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE))
1262 		AID = 0;
1263 
1264 	sta_info.aid = AID;
1265 	sta_info.feedback_type = 0;
1266 	sta_info.nc_index = 0;
1267 
1268 	_rtw_memcpy(pframe + 17, (u8 *)&sta_info, 2);
1269 
1270 	pattrib->pktlen = 19;
1271 
1272 	pattrib->last_txcmdsz = pattrib->pktlen;
1273 
1274 	dump_mgntframe(adapter, pmgntframe);
1275 
1276 	return true;
1277 }
1278 
1279 boolean
1280 send_sw_vht_ndpa_packet(
1281 	void *dm_void,
1282 	u8 *RA,
1283 	u16 AID,
1284 	enum channel_width BW)
1285 {
1286 	struct dm_struct *dm = (struct dm_struct *)dm_void;
1287 	struct _ADAPTER *adapter = dm->adapter;
1288 	struct xmit_frame *pmgntframe;
1289 	struct pkt_attrib *pattrib;
1290 	struct rtw_ieee80211_hdr *pwlanhdr;
1291 	struct xmit_priv *pxmitpriv = &(adapter->xmitpriv);
1292 	struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
1293 	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
1294 	struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
1295 	struct _RT_NDPA_STA_INFO ndpa_sta_info;
1296 	u8 ndp_tx_rate = 0, sequence = 0, a_sifs_time = 0, idx = 0;
1297 	u8 *pframe;
1298 	u16 *fctrl;
1299 	u16 duration = 0;
1300 	struct _RT_BEAMFORMING_INFO *beam_info = &(dm->beamforming_info);
1301 	struct _RT_BEAMFORMEE_ENTRY *beamform_entry = phydm_beamforming_get_bfee_entry_by_addr(dm, RA, &idx);
1302 
1303 	ndp_tx_rate = beamforming_get_vht_ndp_tx_rate(dm, beamform_entry->comp_steering_num_of_bfer);
1304 	PHYDM_DBG(dm, DBG_TXBF, "[%s] ndp_tx_rate =%d\n", __func__,
1305 		  ndp_tx_rate);
1306 
1307 	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
1308 
1309 	if (pmgntframe == NULL) {
1310 		PHYDM_DBG(dm, DBG_TXBF, "%s, alloc mgnt frame fail\n",
1311 			  __func__);
1312 		return false;
1313 	}
1314 
1315 	/*update attribute*/
1316 	pattrib = &pmgntframe->attrib;
1317 	_rtw_memcpy(pattrib->ra, RA, ETH_ALEN);
1318 	update_mgntframe_attrib(adapter, pattrib);
1319 	pattrib->qsel = QSLT_MGNT;
1320 	pattrib->rate = ndp_tx_rate;
1321 	pattrib->bwmode = BW;
1322 	pattrib->subtype = WIFI_NDPA;
1323 
1324 	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
1325 
1326 	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
1327 
1328 	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
1329 
1330 	fctrl = &pwlanhdr->frame_ctl;
1331 	*(fctrl) = 0;
1332 
1333 	set_frame_sub_type(pframe, WIFI_NDPA);
1334 
1335 	_rtw_memcpy(pwlanhdr->addr1, RA, ETH_ALEN);
1336 	_rtw_memcpy(pwlanhdr->addr2, beamform_entry->my_mac_addr, ETH_ALEN);
1337 
1338 	if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode))
1339 		a_sifs_time = 16;
1340 	else
1341 		a_sifs_time = 10;
1342 
1343 	duration = 2 * a_sifs_time + 44;
1344 
1345 	if (BW == CHANNEL_WIDTH_80)
1346 		duration += 40;
1347 	else if (BW == CHANNEL_WIDTH_40)
1348 		duration += 87;
1349 	else
1350 		duration += 180;
1351 
1352 	set_duration(pframe, duration);
1353 
1354 	sequence = beam_info->sounding_sequence << 2;
1355 	if (beam_info->sounding_sequence >= 0x3f)
1356 		beam_info->sounding_sequence = 0;
1357 	else
1358 		beam_info->sounding_sequence++;
1359 
1360 	_rtw_memcpy(pframe + 16, &sequence, 1);
1361 	if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE))
1362 		AID = 0;
1363 
1364 	ndpa_sta_info.aid = AID;
1365 	ndpa_sta_info.feedback_type = 0;
1366 	ndpa_sta_info.nc_index = 0;
1367 
1368 	_rtw_memcpy(pframe + 17, (u8 *)&ndpa_sta_info, 2);
1369 
1370 	pattrib->pktlen = 19;
1371 
1372 	pattrib->last_txcmdsz = pattrib->pktlen;
1373 
1374 	dump_mgntframe(adapter, pmgntframe);
1375 	PHYDM_DBG(dm, DBG_TXBF, "[%s] [%d]\n", __func__, __LINE__);
1376 
1377 	return true;
1378 }
1379 
1380 #endif
1381 
1382 void beamforming_get_ndpa_frame(
1383 	void *dm_void,
1384 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1385 	OCTET_STRING pdu_os
1386 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
1387 	union recv_frame *precv_frame
1388 #endif
1389 	)
1390 {
1391 	struct dm_struct *dm = (struct dm_struct *)dm_void;
1392 	u8 *TA;
1393 	u8 idx, sequence;
1394 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1395 	u8 *p_ndpa_frame = pdu_os.Octet;
1396 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
1397 	u8 *p_ndpa_frame = precv_frame->u.hdr.rx_data;
1398 #endif
1399 	struct _RT_BEAMFORMER_ENTRY *beamformer_entry = NULL; /*@Modified By Jeffery @2014-10-29*/
1400 
1401 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1402 	RT_DISP_DATA(FBEAM, FBEAM_DATA, "beamforming_get_ndpa_frame\n",
1403 	pdu_os.Octet, pdu_os.Length);
1404 	if (IsCtrlNDPA(p_ndpa_frame) == false)
1405 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
1406 	if (get_frame_sub_type(p_ndpa_frame) != WIFI_NDPA)
1407 #endif
1408 		return;
1409 	else if (!(dm->support_ic_type & (ODM_RTL8812 | ODM_RTL8821))) {
1410 		PHYDM_DBG(dm, DBG_TXBF, "[%s] not 8812 or 8821A, return\n",
1411 			  __func__);
1412 		return;
1413 	}
1414 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
1415 	TA = Frame_Addr2(pdu_os);
1416 #elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
1417 	TA = get_addr2_ptr(p_ndpa_frame);
1418 #endif
1419 	/*Remove signaling TA. */
1420 	TA[0] = TA[0] & 0xFE;
1421 
1422 	beamformer_entry = phydm_beamforming_get_bfer_entry_by_addr(dm, TA, &idx); /* @Modified By Jeffery @2014-10-29 */
1423 
1424 	/*@Break options for Clock Reset*/
1425 	if (beamformer_entry == NULL)
1426 		return;
1427 	else if (!(beamformer_entry->beamform_entry_cap & BEAMFORMEE_CAP_VHT_SU))
1428 		return;
1429 	/*@log_success: As long as 8812A receive NDPA and feedback CSI succeed once, clock reset is NO LONGER needed !2015-04-10, Jeffery*/
1430 	/*@clock_reset_times: While BFer entry always doesn't receive our CSI, clock will reset again and again.So clock_reset_times is limited to 5 times.2015-04-13, Jeffery*/
1431 	else if ((beamformer_entry->log_success == 1) || (beamformer_entry->clock_reset_times == 5)) {
1432 		PHYDM_DBG(dm, DBG_TXBF,
1433 			  "[%s] log_seq=%d, pre_log_seq=%d, log_retry_cnt=%d, log_success=%d, clock_reset_times=%d, clock reset is no longer needed.\n",
1434 			  __func__, beamformer_entry->log_seq,
1435 			  beamformer_entry->pre_log_seq,
1436 			  beamformer_entry->log_retry_cnt,
1437 			  beamformer_entry->log_success,
1438 			  beamformer_entry->clock_reset_times);
1439 
1440 		return;
1441 	}
1442 
1443 	sequence = (p_ndpa_frame[16]) >> 2;
1444 
1445 	PHYDM_DBG(dm, DBG_TXBF,
1446 		  "[%s] Start, sequence=%d, log_seq=%d, pre_log_seq=%d, log_retry_cnt=%d, clock_reset_times=%d, log_success=%d\n",
1447 		  __func__, sequence, beamformer_entry->log_seq,
1448 		  beamformer_entry->pre_log_seq,
1449 		  beamformer_entry->log_retry_cnt,
1450 		  beamformer_entry->clock_reset_times,
1451 		  beamformer_entry->log_success);
1452 
1453 	if (beamformer_entry->log_seq != 0 && beamformer_entry->pre_log_seq != 0) {
1454 		/*Success condition*/
1455 		if (beamformer_entry->log_seq != sequence && beamformer_entry->pre_log_seq != beamformer_entry->log_seq) {
1456 			/* @break option for clcok reset, 2015-03-30, Jeffery */
1457 			beamformer_entry->log_retry_cnt = 0;
1458 			/*@As long as 8812A receive NDPA and feedback CSI succeed once, clock reset is no longer needed.*/
1459 			/*That is, log_success is NOT needed to be reset to zero, 2015-04-13, Jeffery*/
1460 			beamformer_entry->log_success = 1;
1461 
1462 		} else { /*@Fail condition*/
1463 
1464 			if (beamformer_entry->log_retry_cnt == 5) {
1465 				beamformer_entry->clock_reset_times++;
1466 				beamformer_entry->log_retry_cnt = 0;
1467 
1468 				PHYDM_DBG(dm, DBG_TXBF,
1469 					  "[%s] Clock Reset!!! clock_reset_times=%d\n",
1470 					  __func__,
1471 					  beamformer_entry->clock_reset_times);
1472 				hal_com_txbf_set(dm, TXBF_SET_SOUNDING_CLK, NULL);
1473 
1474 			} else
1475 				beamformer_entry->log_retry_cnt++;
1476 		}
1477 	}
1478 
1479 	/*Update log_seq & pre_log_seq*/
1480 	beamformer_entry->pre_log_seq = beamformer_entry->log_seq;
1481 	beamformer_entry->log_seq = sequence;
1482 }
1483 
1484 #endif
1485