Merge branch 'for-linus' of git://neil.brown.name/md
[sfrench/cifs-2.6.git] / drivers / staging / rt3070 / sta / aironet.c
1 /*
2  *************************************************************************
3  * Ralink Tech Inc.
4  * 5F., No.36, Taiyuan St., Jhubei City,
5  * Hsinchu County 302,
6  * Taiwan, R.O.C.
7  *
8  * (c) Copyright 2002-2007, Ralink Technology, Inc.
9  *
10  * This program is free software; you can redistribute it and/or modify  *
11  * it under the terms of the GNU General Public License as published by  *
12  * the Free Software Foundation; either version 2 of the License, or     *
13  * (at your option) any later version.                                   *
14  *                                                                       *
15  * This program is distributed in the hope that it will be useful,       *
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  * GNU General Public License for more details.                          *
19  *                                                                       *
20  * You should have received a copy of the GNU General Public License     *
21  * along with this program; if not, write to the                         *
22  * Free Software Foundation, Inc.,                                       *
23  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
24  *                                                                       *
25  *************************************************************************
26
27         Module Name:
28         aironet.c
29
30         Abstract:
31
32         Revision History:
33         Who                     When                    What
34         --------        ----------              ----------------------------------------------
35         Paul Lin        04-06-15                Initial
36 */
37 #include "../rt_config.h"
38
39 /*
40         ==========================================================================
41         Description:
42                 association     state machine init,     including state transition and timer init
43         Parameters:
44                 S -     pointer to the association state machine
45         ==========================================================================
46  */
47 VOID    AironetStateMachineInit(
48         IN      PRTMP_ADAPTER           pAd,
49         IN      STATE_MACHINE           *S,
50         OUT     STATE_MACHINE_FUNC      Trans[])
51 {
52         StateMachineInit(S,     Trans, MAX_AIRONET_STATE, MAX_AIRONET_MSG, (STATE_MACHINE_FUNC)Drop, AIRONET_IDLE, AIRONET_MACHINE_BASE);
53         StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_MSG, (STATE_MACHINE_FUNC)AironetMsgAction);
54         StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_SCAN_REQ, (STATE_MACHINE_FUNC)AironetRequestAction);
55         StateMachineSetAction(S, AIRONET_SCANNING, MT2_AIRONET_SCAN_DONE, (STATE_MACHINE_FUNC)AironetReportAction);
56 }
57
58 /*
59         ==========================================================================
60         Description:
61                 This is state machine function.
62                 When receiving EAPOL packets which is  for 802.1x key management.
63                 Use     both in WPA, and WPAPSK case.
64                 In this function, further dispatch to different functions according     to the received packet.  3 categories are :
65                   1.  normal 4-way pairwisekey and 2-way groupkey handshake
66                   2.  MIC error (Countermeasures attack)  report packet from STA.
67                   3.  Request for pairwise/group key update     from STA
68         Return:
69         ==========================================================================
70 */
71 VOID    AironetMsgAction(
72         IN      PRTMP_ADAPTER   pAd,
73         IN      MLME_QUEUE_ELEM *Elem)
74 {
75         USHORT                                                  Length;
76         UCHAR                                                   Index, i;
77         PUCHAR                                                  pData;
78         PAIRONET_RM_REQUEST_FRAME               pRMReq;
79         PRM_REQUEST_ACTION                              pReqElem;
80
81         DBGPRINT(RT_DEBUG_TRACE, ("-----> AironetMsgAction\n"));
82
83         // 0. Get Aironet IAPP header first
84         pRMReq = (PAIRONET_RM_REQUEST_FRAME) &Elem->Msg[LENGTH_802_11];
85         pData  = (PUCHAR) &Elem->Msg[LENGTH_802_11];
86
87         // 1. Change endian format form network to little endian
88         Length = be2cpu16(pRMReq->IAPP.Length);
89
90         // 2.0 Sanity check, this should only happen when CCX 2.0 support is enabled
91         if (pAd->StaCfg.CCXEnable != TRUE)
92                 return;
93
94         // 2.1 Radio measurement must be on
95         if (pAd->StaCfg.CCXControl.field.RMEnable != 1)
96                 return;
97
98         // 2.2. Debug print all bit information
99         DBGPRINT(RT_DEBUG_TRACE, ("IAPP ID & Length %d\n", Length));
100         DBGPRINT(RT_DEBUG_TRACE, ("IAPP Type %x\n", pRMReq->IAPP.Type));
101         DBGPRINT(RT_DEBUG_TRACE, ("IAPP SubType %x\n", pRMReq->IAPP.SubType));
102         DBGPRINT(RT_DEBUG_TRACE, ("IAPP Dialog Token %x\n", pRMReq->IAPP.Token));
103         DBGPRINT(RT_DEBUG_TRACE, ("IAPP Activation Delay %x\n", pRMReq->Delay));
104         DBGPRINT(RT_DEBUG_TRACE, ("IAPP Measurement Offset %x\n", pRMReq->Offset));
105
106         // 3. Check IAPP frame type, it must be 0x32 for Cisco Aironet extension
107         if (pRMReq->IAPP.Type != AIRONET_IAPP_TYPE)
108         {
109                 DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP type for Cisco Aironet extension\n"));
110                 return;
111         }
112
113         // 4. Check IAPP frame subtype, it must be 0x01 for Cisco Aironet extension request.
114         //    Since we are acting as client only, we will disregards reply subtype.
115         if (pRMReq->IAPP.SubType != AIRONET_IAPP_SUBTYPE_REQUEST)
116         {
117                 DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP subtype for Cisco Aironet extension\n"));
118                 return;
119         }
120
121         // 5. Verify Destination MAC and Source MAC, both should be all zeros.
122         if (! MAC_ADDR_EQUAL(pRMReq->IAPP.DA, ZERO_MAC_ADDR))
123         {
124                 DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP DA for Cisco Aironet extension, it's not Zero\n"));
125                 return;
126         }
127
128         if (! MAC_ADDR_EQUAL(pRMReq->IAPP.SA, ZERO_MAC_ADDR))
129         {
130                 DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP SA for Cisco Aironet extension, it's not Zero\n"));
131                 return;
132         }
133
134         // 6. Reinit all report related fields
135         NdisZeroMemory(pAd->StaCfg.FrameReportBuf, 2048);
136         NdisZeroMemory(pAd->StaCfg.BssReportOffset, sizeof(USHORT) * MAX_LEN_OF_BSS_TABLE);
137         NdisZeroMemory(pAd->StaCfg.MeasurementRequest, sizeof(RM_REQUEST_ACTION) * 4);
138
139         // 7. Point to the start of first element report element
140         pAd->StaCfg.FrameReportLen   = LENGTH_802_11 + sizeof(AIRONET_IAPP_HEADER);
141         DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen));
142         pAd->StaCfg.LastBssIndex     = 0xff;
143         pAd->StaCfg.RMReqCnt         = 0;
144         pAd->StaCfg.ParallelReq      = FALSE;
145         pAd->StaCfg.ParallelDuration = 0;
146         pAd->StaCfg.ParallelChannel  = 0;
147         pAd->StaCfg.IAPPToken        = pRMReq->IAPP.Token;
148         pAd->StaCfg.CurrentRMReqIdx  = 0;
149         pAd->StaCfg.CLBusyBytes      = 0;
150         // Reset the statistics
151         for (i = 0; i < 8; i++)
152                 pAd->StaCfg.RPIDensity[i] = 0;
153
154         Index = 0;
155
156         // 8. Save dialog token for report
157         pAd->StaCfg.IAPPToken = pRMReq->IAPP.Token;
158
159         // Save Activation delay & measurement offset, Not really needed
160
161         // 9. Point to the first request element
162         pData += sizeof(AIRONET_RM_REQUEST_FRAME);
163         //    Length should exclude the CISCO Aironet SNAP header
164         Length -= (sizeof(AIRONET_RM_REQUEST_FRAME) - LENGTH_802_1_H);
165
166         // 10. Start Parsing the Measurement elements.
167         //    Be careful about multiple MR elements within one frames.
168         while (Length > 0)
169         {
170                 pReqElem = (PRM_REQUEST_ACTION) pData;
171                 switch (pReqElem->ReqElem.Eid)
172                 {
173                         case IE_MEASUREMENT_REQUEST:
174                                 // From the example, it seems we only need to support one request in one frame
175                                 // There is no multiple request in one frame.
176                                 // Besides, looks like we need to take care the measurement request only.
177                                 // The measurement request is always 4 bytes.
178
179                                 // Start parsing this type of request.
180                                 // 0. Eid is IE_MEASUREMENT_REQUEST
181                                 // 1. Length didn't include Eid and Length field, it always be 8.
182                                 // 2. Measurement Token, we nned to save it for the corresponding report.
183                                 // 3. Measurement Mode, Although there are definitions, but we din't see value other than
184                                 //    0 from test specs examples.
185                                 // 4. Measurement Type, this is what we need to do.
186                                 switch (pReqElem->ReqElem.Type)
187                                 {
188                                         case MSRN_TYPE_CHANNEL_LOAD_REQ:
189                                         case MSRN_TYPE_NOISE_HIST_REQ:
190                                         case MSRN_TYPE_BEACON_REQ:
191                                                 // Check the Enable non-serving channel measurement control
192                                                 if (pAd->StaCfg.CCXControl.field.DCRMEnable == 0)
193                                                 {
194                                                         // Check channel before enqueue the action
195                                                         if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel)
196                                                                 break;
197                                                 }
198                                                 else
199                                                 {
200                                                         // If off channel measurement, check the TU duration limit
201                                                         if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel)
202                                                                 if (pReqElem->Measurement.Duration > pAd->StaCfg.CCXControl.field.TuLimit)
203                                                                         break;
204                                                 }
205
206                                                 // Save requests and execute actions later
207                                                 NdisMoveMemory(&pAd->StaCfg.MeasurementRequest[Index], pReqElem, sizeof(RM_REQUEST_ACTION));
208                                                 Index += 1;
209                                                 break;
210
211                                         case MSRN_TYPE_FRAME_REQ:
212                                                 // Since it's option, we will support later
213                                                 // FrameRequestAction(pAd, pData);
214                                                 break;
215
216                                         default:
217                                                 break;
218                                 }
219
220                                 // Point to next Measurement request
221                                 pData  += sizeof(RM_REQUEST_ACTION);
222                                 Length -= sizeof(RM_REQUEST_ACTION);
223                                 break;
224
225                         // We accept request only, all others are dropped
226                         case IE_MEASUREMENT_REPORT:
227                         case IE_AP_TX_POWER:
228                         case IE_MEASUREMENT_CAPABILITY:
229                         default:
230                                 return;
231                 }
232         }
233
234         // 11. Update some flags and index
235         pAd->StaCfg.RMReqCnt = Index;
236
237         if (Index)
238         {
239                 MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL);
240                 RT28XX_MLME_HANDLER(pAd);
241         }
242
243         DBGPRINT(RT_DEBUG_TRACE, ("<----- AironetMsgAction\n"));
244 }
245
246 /*
247         ========================================================================
248
249         Routine Description:
250
251         Arguments:
252
253         Return Value:
254                 None
255
256         Note:
257
258         ========================================================================
259 */
260 VOID    AironetRequestAction(
261         IN      PRTMP_ADAPTER   pAd,
262         IN      MLME_QUEUE_ELEM *Elem)
263 {
264         PRM_REQUEST_ACTION      pReq;
265
266         // 1. Point to next request element
267         pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx];
268
269         // 2. Parse measurement type and call appropriate functions
270         if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ)
271                 // Channel Load measurement request
272                 ChannelLoadRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
273         else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ)
274                 // Noise Histogram measurement request
275                 NoiseHistRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
276         else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ)
277                 // Beacon measurement request
278                 BeaconRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
279         else
280                 // Unknown. Do nothing and return, this should never happen
281                 return;
282
283         // 3. Peek into the next request, if it's parallel, we will update the scan time to the largest one
284         if ((pAd->StaCfg.CurrentRMReqIdx + 1) < pAd->StaCfg.RMReqCnt)
285         {
286                 pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx + 1];
287                 // Check for parallel bit
288                 if ((pReq->ReqElem.Mode & 0x01) && (pReq->Measurement.Channel == pAd->StaCfg.CCXScanChannel))
289                 {
290                         // Update parallel mode request information
291                         pAd->StaCfg.ParallelReq = TRUE;
292                         pAd->StaCfg.CCXScanTime = ((pReq->Measurement.Duration > pAd->StaCfg.CCXScanTime) ?
293                         (pReq->Measurement.Duration) : (pAd->StaCfg.CCXScanTime));
294                 }
295         }
296
297         // 4. Call RT28XX_MLME_HANDLER to execute the request mlme commands, Scan request is the only one used
298         RT28XX_MLME_HANDLER(pAd);
299
300 }
301
302
303 /*
304         ========================================================================
305
306         Routine Description:
307                 Prepare channel load report action, special scan operation added
308                 to support
309
310         Arguments:
311                 pAd     Pointer to our adapter
312                 pData           Start from element ID
313
314         Return Value:
315                 None
316
317         Note:
318
319         ========================================================================
320 */
321 VOID    ChannelLoadRequestAction(
322         IN      PRTMP_ADAPTER   pAd,
323         IN      UCHAR                   Index)
324 {
325         PRM_REQUEST_ACTION                              pReq;
326         MLME_SCAN_REQ_STRUCT                    ScanReq;
327         UCHAR                                                   ZeroSsid[32];
328         NDIS_STATUS                                             NStatus;
329         PUCHAR                                                  pOutBuffer = NULL;
330         PHEADER_802_11                                  pNullFrame;
331
332         DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction ----->\n"));
333
334         pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index];
335         NdisZeroMemory(ZeroSsid, 32);
336
337         // Prepare for special scan request
338         // The scan definition is different with our Active, Passive scan definition.
339         // For CCX2, Active means send out probe request with broadcast BSSID.
340         // Passive means no probe request sent, only listen to the beacons.
341         // The channel scanned is fixed as specified, no need to scan all channels.
342         // The scan wait time is specified in the request too.
343         // Passive scan Mode
344
345         // Control state machine is not idle, reject the request
346         if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0))
347                 return;
348
349         // Fill out stuff for scan request
350         ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_CHANNEL_LOAD);
351         MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
352         pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
353
354         // Reset some internal control flags to make sure this scan works.
355         BssTableInit(&pAd->StaCfg.CCXBssTab);
356         pAd->StaCfg.ScanCnt        = 0;
357         pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel;
358         pAd->StaCfg.CCXScanTime    = pReq->Measurement.Duration;
359
360         DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel));
361
362         // If it's non serving channel scan, send out a null frame with PSM bit on.
363         if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel)
364         {
365                 // Use MLME enqueue method
366                 NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
367                 if (NStatus     != NDIS_STATUS_SUCCESS)
368                         return;
369
370                 pNullFrame = (PHEADER_802_11) pOutBuffer;;
371                 // Make the power save Null frame with PSM bit on
372                 MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid);
373                 pNullFrame->Duration    = 0;
374                 pNullFrame->FC.Type     = BTYPE_DATA;
375                 pNullFrame->FC.PwrMgmt  = PWR_SAVE;
376
377                 // Send using priority queue
378                 MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11));
379                 MlmeFreeMemory(pAd, pOutBuffer);
380                 DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n"));
381                 RTMPusecDelay(5000);
382         }
383
384         pAd->StaCfg.CCXReqType     = MSRN_TYPE_CHANNEL_LOAD_REQ;
385         pAd->StaCfg.CLBusyBytes    = 0;
386         // Enable Rx with promiscuous reception
387         RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010);
388
389         // Set channel load measurement flag
390         RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT);
391
392         pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
393
394         DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction <-----\n"));
395 }
396
397 /*
398         ========================================================================
399
400         Routine Description:
401                 Prepare noise histogram report action, special scan operation added
402                 to support
403
404         Arguments:
405                 pAd     Pointer to our adapter
406                 pData           Start from element ID
407
408         Return Value:
409                 None
410
411         Note:
412
413         ========================================================================
414 */
415 VOID    NoiseHistRequestAction(
416         IN      PRTMP_ADAPTER   pAd,
417         IN      UCHAR                   Index)
418 {
419         PRM_REQUEST_ACTION                              pReq;
420         MLME_SCAN_REQ_STRUCT                    ScanReq;
421         UCHAR                                                   ZeroSsid[32], i;
422         NDIS_STATUS                                             NStatus;
423         PUCHAR                                                  pOutBuffer = NULL;
424         PHEADER_802_11                                  pNullFrame;
425
426         DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction ----->\n"));
427
428         pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index];
429         NdisZeroMemory(ZeroSsid, 32);
430
431         // Prepare for special scan request
432         // The scan definition is different with our Active, Passive scan definition.
433         // For CCX2, Active means send out probe request with broadcast BSSID.
434         // Passive means no probe request sent, only listen to the beacons.
435         // The channel scanned is fixed as specified, no need to scan all channels.
436         // The scan wait time is specified in the request too.
437         // Passive scan Mode
438
439         // Control state machine is not idle, reject the request
440         if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0))
441                 return;
442
443         // Fill out stuff for scan request
444         ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_NOISE);
445         MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
446         pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
447
448         // Reset some internal control flags to make sure this scan works.
449         BssTableInit(&pAd->StaCfg.CCXBssTab);
450         pAd->StaCfg.ScanCnt        = 0;
451         pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel;
452         pAd->StaCfg.CCXScanTime    = pReq->Measurement.Duration;
453         pAd->StaCfg.CCXReqType     = MSRN_TYPE_NOISE_HIST_REQ;
454
455         DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel));
456
457         // If it's non serving channel scan, send out a null frame with PSM bit on.
458         if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel)
459         {
460                 // Use MLME enqueue method
461                 NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
462                 if (NStatus     != NDIS_STATUS_SUCCESS)
463                         return;
464
465                 pNullFrame = (PHEADER_802_11) pOutBuffer;
466                 // Make the power save Null frame with PSM bit on
467                 MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid);
468                 pNullFrame->Duration    = 0;
469                 pNullFrame->FC.Type     = BTYPE_DATA;
470                 pNullFrame->FC.PwrMgmt  = PWR_SAVE;
471
472                 // Send using priority queue
473                 MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11));
474                 MlmeFreeMemory(pAd, pOutBuffer);
475                 DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n"));
476                 RTMPusecDelay(5000);
477         }
478
479         // Reset the statistics
480         for (i = 0; i < 8; i++)
481                 pAd->StaCfg.RPIDensity[i] = 0;
482
483         // Enable Rx with promiscuous reception
484         RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010);
485
486         // Set channel load measurement flag
487         RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT);
488
489         pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
490
491         DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction <-----\n"));
492 }
493
494 /*
495         ========================================================================
496
497         Routine Description:
498                 Prepare Beacon report action, special scan operation added
499                 to support
500
501         Arguments:
502                 pAd     Pointer to our adapter
503                 pData           Start from element ID
504
505         Return Value:
506                 None
507
508         Note:
509
510         ========================================================================
511 */
512 VOID    BeaconRequestAction(
513         IN      PRTMP_ADAPTER   pAd,
514         IN      UCHAR                   Index)
515 {
516         PRM_REQUEST_ACTION                              pReq;
517         NDIS_STATUS                                             NStatus;
518         PUCHAR                                                  pOutBuffer = NULL;
519         PHEADER_802_11                                  pNullFrame;
520         MLME_SCAN_REQ_STRUCT                    ScanReq;
521         UCHAR                                                   ZeroSsid[32];
522
523         DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction ----->\n"));
524
525         pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index];
526         NdisZeroMemory(ZeroSsid, 32);
527
528         // Prepare for special scan request
529         // The scan definition is different with our Active, Passive scan definition.
530         // For CCX2, Active means send out probe request with broadcast BSSID.
531         // Passive means no probe request sent, only listen to the beacons.
532         // The channel scanned is fixed as specified, no need to scan all channels.
533         // The scan wait time is specified in the request too.
534         if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_PASSIVE)
535         {
536                 // Passive scan Mode
537                 DBGPRINT(RT_DEBUG_TRACE, ("Passive Scan Mode!\n"));
538
539                 // Control state machine is not idle, reject the request
540                 if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0))
541                         return;
542
543                 // Fill out stuff for scan request
544                 ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_PASSIVE);
545                 MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
546                 pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
547
548                 // Reset some internal control flags to make sure this scan works.
549                 BssTableInit(&pAd->StaCfg.CCXBssTab);
550                 pAd->StaCfg.ScanCnt        = 0;
551                 pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel;
552                 pAd->StaCfg.CCXScanTime    = pReq->Measurement.Duration;
553                 pAd->StaCfg.CCXReqType     = MSRN_TYPE_BEACON_REQ;
554                 DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration));
555
556                 // If it's non serving channel scan, send out a null frame with PSM bit on.
557                 if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel)
558                 {
559                         // Use MLME enqueue method
560                         NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
561                         if (NStatus     != NDIS_STATUS_SUCCESS)
562                                 return;
563
564                         pNullFrame = (PHEADER_802_11) pOutBuffer;
565                         // Make the power save Null frame with PSM bit on
566                         MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid);
567                         pNullFrame->Duration    = 0;
568                         pNullFrame->FC.Type     = BTYPE_DATA;
569                         pNullFrame->FC.PwrMgmt  = PWR_SAVE;
570
571                         // Send using priority queue
572                         MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11));
573                         MlmeFreeMemory(pAd, pOutBuffer);
574                         DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n"));
575                         RTMPusecDelay(5000);
576                 }
577
578                 pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
579         }
580         else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_ACTIVE)
581         {
582                 // Active scan Mode
583                 DBGPRINT(RT_DEBUG_TRACE, ("Active Scan Mode!\n"));
584
585                 // Control state machine is not idle, reject the request
586                 if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE)
587                         return;
588
589                 // Fill out stuff for scan request
590                 ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_ACTIVE);
591                 MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
592                 pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
593
594                 // Reset some internal control flags to make sure this scan works.
595                 BssTableInit(&pAd->StaCfg.CCXBssTab);
596                 pAd->StaCfg.ScanCnt        = 0;
597                 pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel;
598                 pAd->StaCfg.CCXScanTime    = pReq->Measurement.Duration;
599                 pAd->StaCfg.CCXReqType     = MSRN_TYPE_BEACON_REQ;
600                 DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration));
601
602                 // If it's non serving channel scan, send out a null frame with PSM bit on.
603                 if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel)
604                 {
605                         // Use MLME enqueue method
606                         NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
607                         if (NStatus     != NDIS_STATUS_SUCCESS)
608                                 return;
609
610                         pNullFrame = (PHEADER_802_11) pOutBuffer;
611                         // Make the power save Null frame with PSM bit on
612                         MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid);
613                         pNullFrame->Duration    = 0;
614                         pNullFrame->FC.Type     = BTYPE_DATA;
615                         pNullFrame->FC.PwrMgmt  = PWR_SAVE;
616
617                         // Send using priority queue
618                         MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11));
619                         MlmeFreeMemory(pAd, pOutBuffer);
620                         DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n"));
621                         RTMPusecDelay(5000);
622                 }
623
624                 pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
625         }
626         else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_BEACON_TABLE)
627         {
628                 // Beacon report Mode, report all the APS in current bss table
629                 DBGPRINT(RT_DEBUG_TRACE, ("Beacon Report Mode!\n"));
630
631                 // Copy current BSS table to CCX table, we can omit this step later on.
632                 NdisMoveMemory(&pAd->StaCfg.CCXBssTab, &pAd->ScanTab, sizeof(BSS_TABLE));
633
634                 // Create beacon report from Bss table
635                 AironetCreateBeaconReportFromBssTable(pAd);
636
637                 // Set state to scanning
638                 pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
639
640                 // Enqueue report request
641                 // Cisco scan request is finished, prepare beacon report
642                 MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL);
643         }
644         else
645         {
646                 // Wrong scan Mode
647                 DBGPRINT(RT_DEBUG_TRACE, ("Wrong Scan Mode!\n"));
648         }
649
650         DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction <-----\n"));
651 }
652
653 /*
654         ========================================================================
655
656         Routine Description:
657
658         Arguments:
659
660         Return Value:
661                 None
662
663         Note:
664
665         ========================================================================
666 */
667 VOID    AironetReportAction(
668         IN      PRTMP_ADAPTER   pAd,
669         IN      MLME_QUEUE_ELEM *Elem)
670 {
671         PRM_REQUEST_ACTION      pReq;
672         ULONG                           Now32;
673
674     NdisGetSystemUpTime(&Now32);
675         pAd->StaCfg.LastBeaconRxTime = Now32;
676
677         pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx];
678
679         DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction ----->\n"));
680
681         // 1. Parse measurement type and call appropriate functions
682         if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ)
683                 // Channel Load measurement request
684                 ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
685         else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ)
686                 // Noise Histogram measurement request
687                 NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
688         else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ)
689                 // Beacon measurement request
690                 BeaconReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
691         else
692                 // Unknown. Do nothing and return
693                 ;
694
695         // 2. Point to the correct index of action element, start from 0
696         pAd->StaCfg.CurrentRMReqIdx++;
697
698         // 3. Check for parallel actions
699         if (pAd->StaCfg.ParallelReq == TRUE)
700         {
701                 pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx];
702
703                 // Process next action right away
704                 if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ)
705                         // Channel Load measurement request
706                         ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
707                 else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ)
708                         // Noise Histogram measurement request
709                         NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
710
711                 pAd->StaCfg.ParallelReq = FALSE;
712                 pAd->StaCfg.CurrentRMReqIdx++;
713         }
714
715         if (pAd->StaCfg.CurrentRMReqIdx >= pAd->StaCfg.RMReqCnt)
716         {
717                 // 4. There is no more unprocessed measurement request, go for transmit this report
718                 AironetFinalReportAction(pAd);
719                 pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE;
720         }
721         else
722         {
723                 pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx];
724
725                 if (pReq->Measurement.Channel != pAd->CommonCfg.Channel)
726                 {
727                         RTMPusecDelay(100000);
728                 }
729
730                 // 5. There are more requests to be measure
731                 MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL);
732                 RT28XX_MLME_HANDLER(pAd);
733         }
734
735         DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction <-----\n"));
736 }
737
738 /*
739         ========================================================================
740
741         Routine Description:
742
743         Arguments:
744
745         Return Value:
746                 None
747
748         Note:
749
750         ========================================================================
751 */
752 VOID    AironetFinalReportAction(
753         IN      PRTMP_ADAPTER   pAd)
754 {
755         PUCHAR                                  pDest;
756         PAIRONET_IAPP_HEADER    pIAPP;
757         PHEADER_802_11                  pHeader;
758         UCHAR                                   AckRate = RATE_2;
759         USHORT                                  AckDuration = 0;
760         NDIS_STATUS                             NStatus;
761         PUCHAR                                  pOutBuffer = NULL;
762         ULONG                                   FrameLen = 0;
763
764         DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction ----->\n"));
765
766         // 0. Set up the frame pointer, Frame was inited at the end of message action
767         pDest = &pAd->StaCfg.FrameReportBuf[LENGTH_802_11];
768
769         // 1. Update report IAPP fields
770         pIAPP = (PAIRONET_IAPP_HEADER) pDest;
771
772         // 2. Copy Cisco SNAP header
773         NdisMoveMemory(pIAPP->CiscoSnapHeader, SNAP_AIRONET, LENGTH_802_1_H);
774
775         // 3. network order for this 16bit length
776         pIAPP->Length  = cpu2be16(pAd->StaCfg.FrameReportLen - LENGTH_802_11 - LENGTH_802_1_H);
777
778         // 3.1 sanity check the report length, ignore it if there is nothing to report
779         if (be2cpu16(pIAPP->Length) <= 18)
780                 return;
781
782         // 4. Type must be 0x32
783         pIAPP->Type    = AIRONET_IAPP_TYPE;
784
785         // 5. SubType for report must be 0x81
786         pIAPP->SubType = AIRONET_IAPP_SUBTYPE_REPORT;
787
788         // 6. DA is not used and must be zero, although the whole frame was cleared at the start of function
789         //    We will do it again here. We can use BSSID instead
790         COPY_MAC_ADDR(pIAPP->DA, pAd->CommonCfg.Bssid);
791
792         // 7. SA is the client reporting which must be our MAC
793         COPY_MAC_ADDR(pIAPP->SA, pAd->CurrentAddress);
794
795         // 8. Copy the saved dialog token
796         pIAPP->Token = pAd->StaCfg.IAPPToken;
797
798         // 9. Make the Report frame 802.11 header
799         //    Reuse function in wpa.c
800         pHeader = (PHEADER_802_11) pAd->StaCfg.FrameReportBuf;
801         pAd->Sequence ++;
802         WpaMacHeaderInit(pAd, pHeader, 0, pAd->CommonCfg.Bssid);
803
804         // ACK size     is 14 include CRC, and its rate is based on real time information
805         AckRate     = pAd->CommonCfg.ExpectedACKRate[pAd->CommonCfg.MlmeRate];
806         AckDuration = RTMPCalcDuration(pAd, AckRate, 14);
807         pHeader->Duration = pAd->CommonCfg.Dsifs + AckDuration;
808
809         // Use MLME enqueue method
810         NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);  //Get an unused nonpaged memory
811         if (NStatus     != NDIS_STATUS_SUCCESS)
812                 return;
813
814         // 10. Prepare report frame with dynamic outbuffer. Just simply copy everything.
815         MakeOutgoingFrame(pOutBuffer,                       &FrameLen,
816                           pAd->StaCfg.FrameReportLen, pAd->StaCfg.FrameReportBuf,
817                               END_OF_ARGS);
818
819         // 11. Send using priority queue
820         MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
821         MlmeFreeMemory(pAd, pOutBuffer);
822
823         pAd->StaCfg.CCXReqType = MSRN_TYPE_UNUSED;
824
825         DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction <-----\n"));
826 }
827
828 /*
829         ========================================================================
830
831         Routine Description:
832
833         Arguments:
834
835         Return Value:
836                 None
837
838         Note:
839
840         ========================================================================
841 */
842 VOID    ChannelLoadReportAction(
843         IN      PRTMP_ADAPTER   pAd,
844         IN      UCHAR                   Index)
845 {
846         PMEASUREMENT_REPORT_ELEMENT     pReport;
847         PCHANNEL_LOAD_REPORT            pLoad;
848         PUCHAR                                          pDest;
849         UCHAR                                           CCABusyFraction;
850
851         DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction ----->\n"));
852
853         // Disable Rx with promiscuous reception, make it back to normal
854         RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification.
855
856         // 0. Setup pointer for processing beacon & probe response
857         pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen];
858         pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest;
859
860         // 1. Fill Measurement report element field.
861         pReport->Eid    = IE_MEASUREMENT_REPORT;
862         // Fixed Length at 9, not include Eid and length fields
863         pReport->Length = 9;
864         pReport->Token  = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token;
865         pReport->Mode   = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode;
866         pReport->Type   = MSRN_TYPE_CHANNEL_LOAD_REQ;
867
868         // 2. Fill channel report measurement data
869         pDest += sizeof(MEASUREMENT_REPORT_ELEMENT);
870         pLoad  = (PCHANNEL_LOAD_REPORT) pDest;
871         pLoad->Channel  = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel;
872         pLoad->Spare    = 0;
873         pLoad->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration;
874
875         // 3. Calculate the CCA Busy Fraction
876         //    (Bytes + ACK size) * 8 / Tx speed * 255 / 1000 / measurement duration, use 24 us Tx speed
877         //     =  (Bytes + ACK) / 12 / duration
878         //     9 is the good value for pAd->StaCfg.CLFactor
879         // CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 9 / pLoad->Duration);
880         CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / pAd->StaCfg.CLFactor / pLoad->Duration);
881         if (CCABusyFraction < 10)
882                         CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 3 / pLoad->Duration) + 1;
883
884         pLoad->CCABusy = CCABusyFraction;
885         DBGPRINT(RT_DEBUG_TRACE, ("CLBusyByte %ld, Duration %d, Result, %d\n", pAd->StaCfg.CLBusyBytes, pLoad->Duration, CCABusyFraction));
886
887         DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen));
888         pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(CHANNEL_LOAD_REPORT));
889         DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen));
890
891         // 4. Clear channel load measurement flag
892         RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT);
893
894         // 5. reset to idle state
895         pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE;
896
897         DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction <-----\n"));
898 }
899
900 /*
901         ========================================================================
902
903         Routine Description:
904
905         Arguments:
906
907         Return Value:
908                 None
909
910         Note:
911
912         ========================================================================
913 */
914 VOID    NoiseHistReportAction(
915         IN      PRTMP_ADAPTER   pAd,
916         IN      UCHAR                   Index)
917 {
918         PMEASUREMENT_REPORT_ELEMENT     pReport;
919         PNOISE_HIST_REPORT                      pNoise;
920         PUCHAR                                          pDest;
921         UCHAR                                           i,NoiseCnt;
922         USHORT                                          TotalRPICnt, TotalRPISum;
923
924         DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction ----->\n"));
925
926         // 0. Disable Rx with promiscuous reception, make it back to normal
927         RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification.
928         // 1. Setup pointer for processing beacon & probe response
929         pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen];
930         pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest;
931
932         // 2. Fill Measurement report element field.
933         pReport->Eid    = IE_MEASUREMENT_REPORT;
934         // Fixed Length at 16, not include Eid and length fields
935         pReport->Length = 16;
936         pReport->Token  = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token;
937         pReport->Mode   = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode;
938         pReport->Type   = MSRN_TYPE_NOISE_HIST_REQ;
939
940         // 3. Fill noise histogram report measurement data
941         pDest += sizeof(MEASUREMENT_REPORT_ELEMENT);
942         pNoise  = (PNOISE_HIST_REPORT) pDest;
943         pNoise->Channel  = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel;
944         pNoise->Spare    = 0;
945         pNoise->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration;
946         // 4. Fill Noise histogram, the total RPI counts should be 0.4 * TU
947         //    We estimate 4000 normal packets received durning 10 seconds test.
948         //    Adjust it if required.
949         // 3 is a good value for pAd->StaCfg.NHFactor
950         // TotalRPICnt = pNoise->Duration * 3 / 10;
951         TotalRPICnt = pNoise->Duration * pAd->StaCfg.NHFactor / 10;
952         TotalRPISum = 0;
953
954         for (i = 0; i < 8; i++)
955         {
956                 TotalRPISum += pAd->StaCfg.RPIDensity[i];
957                 DBGPRINT(RT_DEBUG_TRACE, ("RPI %d Conuts %d\n", i, pAd->StaCfg.RPIDensity[i]));
958         }
959
960         // Double check if the counter is larger than our expectation.
961         // We will replace it with the total number plus a fraction.
962         if (TotalRPISum > TotalRPICnt)
963                 TotalRPICnt = TotalRPISum + pNoise->Duration / 20;
964
965         DBGPRINT(RT_DEBUG_TRACE, ("Total RPI Conuts %d\n", TotalRPICnt));
966
967         // 5. Initialize noise count for the total summation of 0xff
968         NoiseCnt = 0;
969         for (i = 1; i < 8; i++)
970         {
971                 pNoise->Density[i] = (UCHAR) (pAd->StaCfg.RPIDensity[i] * 255 / TotalRPICnt);
972                 if ((pNoise->Density[i] == 0) && (pAd->StaCfg.RPIDensity[i] != 0))
973                         pNoise->Density[i]++;
974                 NoiseCnt += pNoise->Density[i];
975                 DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[%d]  = 0x%02x\n", i, pNoise->Density[i]));
976         }
977
978         // 6. RPI[0] represents the rest of counts
979         pNoise->Density[0] = 0xff - NoiseCnt;
980         DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[0]  = 0x%02x\n", pNoise->Density[0]));
981
982         pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(NOISE_HIST_REPORT));
983
984         // 7. Clear channel load measurement flag
985         RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT);
986
987         // 8. reset to idle state
988         pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE;
989
990         DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction <-----\n"));
991 }
992
993 /*
994         ========================================================================
995
996         Routine Description:
997                 Prepare Beacon report action,
998
999         Arguments:
1000                 pAd     Pointer to our adapter
1001
1002         Return Value:
1003                 None
1004
1005         Note:
1006
1007         ========================================================================
1008 */
1009 VOID    BeaconReportAction(
1010         IN      PRTMP_ADAPTER   pAd,
1011         IN      UCHAR                   Index)
1012 {
1013         DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction ----->\n"));
1014
1015         // Looks like we don't have anything thing need to do here.
1016         // All measurement report already finished in AddBeaconReport
1017         // The length is in the FrameReportLen
1018
1019         // reset Beacon index for next beacon request
1020         pAd->StaCfg.LastBssIndex = 0xff;
1021
1022         // reset to idle state
1023         pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE;
1024
1025         DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction <-----\n"));
1026 }
1027
1028 /*
1029         ========================================================================
1030
1031         Routine Description:
1032
1033         Arguments:
1034                 Index           Current BSSID in CCXBsstab entry index
1035
1036         Return Value:
1037
1038         Note:
1039
1040         ========================================================================
1041 */
1042 VOID    AironetAddBeaconReport(
1043         IN      PRTMP_ADAPTER           pAd,
1044         IN      ULONG                           Index,
1045         IN      PMLME_QUEUE_ELEM        pElem)
1046 {
1047         PVOID                                           pMsg;
1048         PUCHAR                                          pSrc, pDest;
1049         UCHAR                                           ReqIdx;
1050         ULONG                                           MsgLen;
1051         USHORT                                          Length;
1052         PFRAME_802_11                           pFrame;
1053         PMEASUREMENT_REPORT_ELEMENT     pReport;
1054         PEID_STRUCT                             pEid;
1055         PBEACON_REPORT                          pBeaconReport;
1056         PBSS_ENTRY                                      pBss;
1057
1058         // 0. Setup pointer for processing beacon & probe response
1059         pMsg   = pElem->Msg;
1060         MsgLen = pElem->MsgLen;
1061         pFrame = (PFRAME_802_11) pMsg;
1062         pSrc   = pFrame->Octet;                         // Start from AP TSF
1063         pBss   = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index];
1064         ReqIdx = pAd->StaCfg.CurrentRMReqIdx;
1065
1066         // 1 Check the Index, if we already create this entry, only update the average RSSI
1067         if ((Index <= pAd->StaCfg.LastBssIndex) && (pAd->StaCfg.LastBssIndex != 0xff))
1068         {
1069                 pDest  = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.BssReportOffset[Index]];
1070                 // Point to bss report information
1071                 pDest += sizeof(MEASUREMENT_REPORT_ELEMENT);
1072                 pBeaconReport = (PBEACON_REPORT) pDest;
1073
1074                 // Update Rx power, in dBm
1075                 // Get the original RSSI readback from BBP
1076                 pBeaconReport->RxPower += pAd->BbpRssiToDbmDelta;
1077                 // Average the Rssi reading
1078                 pBeaconReport->RxPower  = (pBeaconReport->RxPower + pBss->Rssi) / 2;
1079                 // Get to dBm format
1080                 pBeaconReport->RxPower -= pAd->BbpRssiToDbmDelta;
1081
1082                 DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ",
1083                         pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2],
1084                         pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5]));
1085                 DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld] Rssi %d, Avg Rssi %d\n", Index, (pBss->Rssi - pAd->BbpRssiToDbmDelta), pBeaconReport->RxPower - 256));
1086                 DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.BssReportOffset[Index]));
1087
1088                 // Update other information here
1089
1090                 // Done
1091                 return;
1092         }
1093
1094         // 2. Update reported Index
1095         pAd->StaCfg.LastBssIndex = Index;
1096
1097         // 3. Setup the buffer address for copying this BSSID into reporting frame
1098         //    The offset should start after 802.11 header and report frame header.
1099         pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen];
1100
1101         // 4. Save the start offset of each Bss in report frame
1102         pAd->StaCfg.BssReportOffset[Index] = pAd->StaCfg.FrameReportLen;
1103
1104         // 5. Fill Measurement report fields
1105         pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest;
1106         pReport->Eid = IE_MEASUREMENT_REPORT;
1107         pReport->Length = 0;
1108         pReport->Token  = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token;
1109         pReport->Mode   = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode;
1110         pReport->Type   = MSRN_TYPE_BEACON_REQ;
1111         Length          = sizeof(MEASUREMENT_REPORT_ELEMENT);
1112         pDest          += sizeof(MEASUREMENT_REPORT_ELEMENT);
1113
1114         // 6. Start thebeacon report format
1115         pBeaconReport = (PBEACON_REPORT) pDest;
1116         pDest        += sizeof(BEACON_REPORT);
1117         Length       += sizeof(BEACON_REPORT);
1118
1119         // 7. Copy Channel number
1120         pBeaconReport->Channel        = pBss->Channel;
1121         pBeaconReport->Spare          = 0;
1122         pBeaconReport->Duration       = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration;
1123         pBeaconReport->PhyType        = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS);
1124         // 8. Rx power, in dBm
1125         pBeaconReport->RxPower        = pBss->Rssi - pAd->BbpRssiToDbmDelta;
1126
1127         DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ",
1128                 pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2],
1129                 pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5]));
1130         DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld], Rssi %d\n", Index, pBeaconReport->RxPower - 256));
1131         DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.FrameReportLen));
1132
1133         pBeaconReport->BeaconInterval = pBss->BeaconPeriod;
1134         COPY_MAC_ADDR(pBeaconReport->BSSID, pFrame->Hdr.Addr3);
1135         NdisMoveMemory(pBeaconReport->ParentTSF, pSrc, 4);
1136         NdisMoveMemory(pBeaconReport->TargetTSF, &pElem->TimeStamp.u.LowPart, 4);
1137         NdisMoveMemory(&pBeaconReport->TargetTSF[4], &pElem->TimeStamp.u.HighPart, 4);
1138
1139         // 9. Skip the beacon frame and offset to start of capabilityinfo since we already processed capabilityinfo
1140         pSrc += (TIMESTAMP_LEN + 2);
1141         pBeaconReport->CapabilityInfo = *(USHORT *)pSrc;
1142
1143         // 10. Point to start of element ID
1144         pSrc += 2;
1145         pEid = (PEID_STRUCT) pSrc;
1146
1147         // 11. Start process all variable Eid oayload and add the appropriate to the frame report
1148         while (((PUCHAR) pEid + pEid->Len + 1) < ((PUCHAR) pFrame + MsgLen))
1149         {
1150                 // Only limited EID are required to report for CCX 2. It includes SSID, Supported rate,
1151                 // FH paramenter set, DS parameter set, CF parameter set, IBSS parameter set,
1152                 // TIM (report first 4 bytes only, radio measurement capability
1153                 switch (pEid->Eid)
1154                 {
1155                         case IE_SSID:
1156                         case IE_SUPP_RATES:
1157                         case IE_FH_PARM:
1158                         case IE_DS_PARM:
1159                         case IE_CF_PARM:
1160                         case IE_IBSS_PARM:
1161                                 NdisMoveMemory(pDest, pEid, pEid->Len + 2);
1162                                 pDest  += (pEid->Len + 2);
1163                                 Length += (pEid->Len + 2);
1164                                 break;
1165
1166                         case IE_MEASUREMENT_CAPABILITY:
1167                                 // Since this IE is duplicated with WPA security IE, we has to do sanity check before
1168                                 // recognize it.
1169                                 // 1. It also has fixed 6 bytes IE length.
1170                                 if (pEid->Len != 6)
1171                                         break;
1172                                 // 2. Check the Cisco Aironet OUI
1173                                 if (NdisEqualMemory(CISCO_OUI, (pSrc + 2), 3))
1174                                 {
1175                                         // Matched, this is what we want
1176                                         NdisMoveMemory(pDest, pEid, pEid->Len + 2);
1177                                         pDest  += (pEid->Len + 2);
1178                                         Length += (pEid->Len + 2);
1179                                 }
1180                                 break;
1181
1182                         case IE_TIM:
1183                                 if (pEid->Len > 4)
1184                                 {
1185                                         // May truncate and report the first 4 bytes only, with the eid & len, total should be 6
1186                                         NdisMoveMemory(pDest, pEid, 6);
1187                                         pDest  += 6;
1188                                         Length += 6;
1189                                 }
1190                                 else
1191                                 {
1192                                         NdisMoveMemory(pDest, pEid, pEid->Len + 2);
1193                                         pDest  += (pEid->Len + 2);
1194                                         Length += (pEid->Len + 2);
1195                                 }
1196                                 break;
1197
1198                         default:
1199                                 break;
1200                 }
1201                 // 12. Move to next element ID
1202                 pSrc += (2 + pEid->Len);
1203                 pEid = (PEID_STRUCT) pSrc;
1204         }
1205
1206         // 13. Update the length in the header, not include EID and length
1207         pReport->Length = Length - 4;
1208
1209         // 14. Update the frame report buffer data length
1210         pAd->StaCfg.FrameReportLen += Length;
1211         DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen));
1212 }
1213
1214 /*
1215         ========================================================================
1216
1217         Routine Description:
1218
1219         Arguments:
1220                 Index           Current BSSID in CCXBsstab entry index
1221
1222         Return Value:
1223
1224         Note:
1225
1226         ========================================================================
1227 */
1228 VOID    AironetCreateBeaconReportFromBssTable(
1229         IN      PRTMP_ADAPTER           pAd)
1230 {
1231         PMEASUREMENT_REPORT_ELEMENT     pReport;
1232         PBEACON_REPORT                          pBeaconReport;
1233         UCHAR                                           Index, ReqIdx;
1234         USHORT                                          Length;
1235         PUCHAR                                          pDest;
1236         PBSS_ENTRY                                      pBss;
1237
1238         // 0. setup base pointer
1239         ReqIdx = pAd->StaCfg.CurrentRMReqIdx;
1240
1241         for (Index = 0; Index < pAd->StaCfg.CCXBssTab.BssNr; Index++)
1242         {
1243                 // 1. Setup the buffer address for copying this BSSID into reporting frame
1244                 //    The offset should start after 802.11 header and report frame header.
1245                 pDest  = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen];
1246                 pBss   = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index];
1247                 Length = 0;
1248
1249                 // 2. Fill Measurement report fields
1250                 pReport         = (PMEASUREMENT_REPORT_ELEMENT) pDest;
1251                 pReport->Eid    = IE_MEASUREMENT_REPORT;
1252                 pReport->Length = 0;
1253                 pReport->Token  = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token;
1254                 pReport->Mode   = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode;
1255                 pReport->Type   = MSRN_TYPE_BEACON_REQ;
1256                 Length          = sizeof(MEASUREMENT_REPORT_ELEMENT);
1257                 pDest          += sizeof(MEASUREMENT_REPORT_ELEMENT);
1258
1259                 // 3. Start the beacon report format
1260                 pBeaconReport = (PBEACON_REPORT) pDest;
1261                 pDest        += sizeof(BEACON_REPORT);
1262                 Length       += sizeof(BEACON_REPORT);
1263
1264                 // 4. Copy Channel number
1265                 pBeaconReport->Channel        = pBss->Channel;
1266                 pBeaconReport->Spare          = 0;
1267                 pBeaconReport->Duration       = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration;
1268                 pBeaconReport->PhyType        = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS);
1269                 pBeaconReport->RxPower        = pBss->Rssi - pAd->BbpRssiToDbmDelta;
1270                 pBeaconReport->BeaconInterval = pBss->BeaconPeriod;
1271                 pBeaconReport->CapabilityInfo = pBss->CapabilityInfo;
1272                 COPY_MAC_ADDR(pBeaconReport->BSSID, pBss->Bssid);
1273                 NdisMoveMemory(pBeaconReport->ParentTSF, pBss->PTSF, 4);
1274                 NdisMoveMemory(pBeaconReport->TargetTSF, pBss->TTSF, 8);
1275
1276                 // 5. Create SSID
1277                 *pDest++ = 0x00;
1278                 *pDest++ = pBss->SsidLen;
1279                 NdisMoveMemory(pDest, pBss->Ssid, pBss->SsidLen);
1280                 pDest  += pBss->SsidLen;
1281                 Length += (2 + pBss->SsidLen);
1282
1283                 // 6. Create SupportRates
1284                 *pDest++ = 0x01;
1285                 *pDest++ = pBss->SupRateLen;
1286                 NdisMoveMemory(pDest, pBss->SupRate, pBss->SupRateLen);
1287                 pDest  += pBss->SupRateLen;
1288                 Length += (2 + pBss->SupRateLen);
1289
1290                 // 7. DS Parameter
1291                 *pDest++ = 0x03;
1292                 *pDest++ = 1;
1293                 *pDest++ = pBss->Channel;
1294                 Length  += 3;
1295
1296                 // 8. IBSS parameter if presents
1297                 if (pBss->BssType == BSS_ADHOC)
1298                 {
1299                         *pDest++ = 0x06;
1300                         *pDest++ = 2;
1301                         *(PUSHORT) pDest = pBss->AtimWin;
1302                         pDest   += 2;
1303                         Length  += 4;
1304                 }
1305
1306                 // 9. Update length field, not include EID and length
1307                 pReport->Length = Length - 4;
1308
1309                 // 10. Update total frame size
1310                 pAd->StaCfg.FrameReportLen += Length;
1311         }
1312 }