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