Merge branch 'linus' into tracing/hw-branch-tracing
[linux-2.6] / drivers / staging / rt2870 / common / spectrum.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         action.c
29
30     Abstract:
31     Handle association related requests either from WSTA or from local MLME
32
33     Revision History:
34     Who          When          What
35     ---------    ----------    ----------------------------------------------
36         Fonchi Wu    2008                  created for 802.11h
37  */
38
39 #include "../rt_config.h"
40 #include "action.h"
41
42 VOID MeasureReqTabInit(
43         IN PRTMP_ADAPTER pAd)
44 {
45         NdisAllocateSpinLock(&pAd->CommonCfg.MeasureReqTabLock);
46
47         pAd->CommonCfg.pMeasureReqTab = kmalloc(sizeof(MEASURE_REQ_TAB), GFP_ATOMIC);
48         if (pAd->CommonCfg.pMeasureReqTab)
49                 NdisZeroMemory(pAd->CommonCfg.pMeasureReqTab, sizeof(MEASURE_REQ_TAB));
50         else
51                 DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pMeasureReqTab.\n", __func__));
52
53         return;
54 }
55
56 VOID MeasureReqTabExit(
57         IN PRTMP_ADAPTER pAd)
58 {
59         NdisFreeSpinLock(pAd->CommonCfg.MeasureReqTabLock);
60
61         if (pAd->CommonCfg.pMeasureReqTab)
62                 kfree(pAd->CommonCfg.pMeasureReqTab);
63         pAd->CommonCfg.pMeasureReqTab = NULL;
64
65         return;
66 }
67
68 static PMEASURE_REQ_ENTRY MeasureReqLookUp(
69         IN PRTMP_ADAPTER        pAd,
70         IN UINT8                        DialogToken)
71 {
72         UINT HashIdx;
73         PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab;
74         PMEASURE_REQ_ENTRY pEntry = NULL;
75         PMEASURE_REQ_ENTRY pPrevEntry = NULL;
76
77         if (pTab == NULL)
78         {
79                 DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__));
80                 return NULL;
81         }
82
83         RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock);
84
85         HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(DialogToken);
86         pEntry = pTab->Hash[HashIdx];
87
88         while (pEntry)
89         {
90                 if (pEntry->DialogToken == DialogToken)
91                         break;
92                 else
93                 {
94                         pPrevEntry = pEntry;
95                         pEntry = pEntry->pNext;
96                 }
97         }
98
99         RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock);
100
101         return pEntry;
102 }
103
104 static PMEASURE_REQ_ENTRY MeasureReqInsert(
105         IN PRTMP_ADAPTER        pAd,
106         IN UINT8                        DialogToken)
107 {
108         INT i;
109         ULONG HashIdx;
110         PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab;
111         PMEASURE_REQ_ENTRY pEntry = NULL, pCurrEntry;
112         ULONG Now;
113
114         if(pTab == NULL)
115         {
116                 DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__));
117                 return NULL;
118         }
119
120         pEntry = MeasureReqLookUp(pAd, DialogToken);
121         if (pEntry == NULL)
122         {
123                 RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock);
124                 for (i = 0; i < MAX_MEASURE_REQ_TAB_SIZE; i++)
125                 {
126                         NdisGetSystemUpTime(&Now);
127                         pEntry = &pTab->Content[i];
128
129                         if ((pEntry->Valid == TRUE)
130                                 && RTMP_TIME_AFTER((unsigned long)Now, (unsigned long)(pEntry->lastTime + MQ_REQ_AGE_OUT)))
131                         {
132                                 PMEASURE_REQ_ENTRY pPrevEntry = NULL;
133                                 ULONG HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken);
134                                 PMEASURE_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx];
135
136                                 // update Hash list
137                                 do
138                                 {
139                                         if (pProbeEntry == pEntry)
140                                         {
141                                                 if (pPrevEntry == NULL)
142                                                 {
143                                                         pTab->Hash[HashIdx] = pEntry->pNext;
144                                                 }
145                                                 else
146                                                 {
147                                                         pPrevEntry->pNext = pEntry->pNext;
148                                                 }
149                                                 break;
150                                         }
151
152                                         pPrevEntry = pProbeEntry;
153                                         pProbeEntry = pProbeEntry->pNext;
154                                 } while (pProbeEntry);
155
156                                 NdisZeroMemory(pEntry, sizeof(MEASURE_REQ_ENTRY));
157                                 pTab->Size--;
158
159                                 break;
160                         }
161
162                         if (pEntry->Valid == FALSE)
163                                 break;
164                 }
165
166                 if (i < MAX_MEASURE_REQ_TAB_SIZE)
167                 {
168                         NdisGetSystemUpTime(&Now);
169                         pEntry->lastTime = Now;
170                         pEntry->Valid = TRUE;
171                         pEntry->DialogToken = DialogToken;
172                         pTab->Size++;
173                 }
174                 else
175                 {
176                         pEntry = NULL;
177                         DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab tab full.\n", __func__));
178                 }
179
180                 // add this Neighbor entry into HASH table
181                 if (pEntry)
182                 {
183                         HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(DialogToken);
184                         if (pTab->Hash[HashIdx] == NULL)
185                         {
186                                 pTab->Hash[HashIdx] = pEntry;
187                         }
188                         else
189                         {
190                                 pCurrEntry = pTab->Hash[HashIdx];
191                                 while (pCurrEntry->pNext != NULL)
192                                         pCurrEntry = pCurrEntry->pNext;
193                                 pCurrEntry->pNext = pEntry;
194                         }
195                 }
196
197                 RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock);
198         }
199
200         return pEntry;
201 }
202
203 static VOID MeasureReqDelete(
204         IN PRTMP_ADAPTER        pAd,
205         IN UINT8                        DialogToken)
206 {
207         PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab;
208         PMEASURE_REQ_ENTRY pEntry = NULL;
209
210         if(pTab == NULL)
211         {
212                 DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__));
213                 return;
214         }
215
216         // if empty, return
217         if (pTab->Size == 0)
218         {
219                 DBGPRINT(RT_DEBUG_ERROR, ("pMeasureReqTab empty.\n"));
220                 return;
221         }
222
223         pEntry = MeasureReqLookUp(pAd, DialogToken);
224         if (pEntry != NULL)
225         {
226                 PMEASURE_REQ_ENTRY pPrevEntry = NULL;
227                 ULONG HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken);
228                 PMEASURE_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx];
229
230                 RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock);
231                 // update Hash list
232                 do
233                 {
234                         if (pProbeEntry == pEntry)
235                         {
236                                 if (pPrevEntry == NULL)
237                                 {
238                                         pTab->Hash[HashIdx] = pEntry->pNext;
239                                 }
240                                 else
241                                 {
242                                         pPrevEntry->pNext = pEntry->pNext;
243                                 }
244                                 break;
245                         }
246
247                         pPrevEntry = pProbeEntry;
248                         pProbeEntry = pProbeEntry->pNext;
249                 } while (pProbeEntry);
250
251                 NdisZeroMemory(pEntry, sizeof(MEASURE_REQ_ENTRY));
252                 pTab->Size--;
253
254                 RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock);
255         }
256
257         return;
258 }
259
260 VOID TpcReqTabInit(
261         IN PRTMP_ADAPTER pAd)
262 {
263         NdisAllocateSpinLock(&pAd->CommonCfg.TpcReqTabLock);
264
265         pAd->CommonCfg.pTpcReqTab = kmalloc(sizeof(TPC_REQ_TAB), GFP_ATOMIC);
266         if (pAd->CommonCfg.pTpcReqTab)
267                 NdisZeroMemory(pAd->CommonCfg.pTpcReqTab, sizeof(TPC_REQ_TAB));
268         else
269                 DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pTpcReqTab.\n", __func__));
270
271         return;
272 }
273
274 VOID TpcReqTabExit(
275         IN PRTMP_ADAPTER pAd)
276 {
277         NdisFreeSpinLock(pAd->CommonCfg.TpcReqTabLock);
278
279         if (pAd->CommonCfg.pTpcReqTab)
280                 kfree(pAd->CommonCfg.pTpcReqTab);
281         pAd->CommonCfg.pTpcReqTab = NULL;
282
283         return;
284 }
285
286 static PTPC_REQ_ENTRY TpcReqLookUp(
287         IN PRTMP_ADAPTER        pAd,
288         IN UINT8                        DialogToken)
289 {
290         UINT HashIdx;
291         PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab;
292         PTPC_REQ_ENTRY pEntry = NULL;
293         PTPC_REQ_ENTRY pPrevEntry = NULL;
294
295         if (pTab == NULL)
296         {
297                 DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__));
298                 return NULL;
299         }
300
301         RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock);
302
303         HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(DialogToken);
304         pEntry = pTab->Hash[HashIdx];
305
306         while (pEntry)
307         {
308                 if (pEntry->DialogToken == DialogToken)
309                         break;
310                 else
311                 {
312                         pPrevEntry = pEntry;
313                         pEntry = pEntry->pNext;
314                 }
315         }
316
317         RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock);
318
319         return pEntry;
320 }
321
322
323 static PTPC_REQ_ENTRY TpcReqInsert(
324         IN PRTMP_ADAPTER        pAd,
325         IN UINT8                        DialogToken)
326 {
327         INT i;
328         ULONG HashIdx;
329         PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab;
330         PTPC_REQ_ENTRY pEntry = NULL, pCurrEntry;
331         ULONG Now;
332
333         if(pTab == NULL)
334         {
335                 DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__));
336                 return NULL;
337         }
338
339         pEntry = TpcReqLookUp(pAd, DialogToken);
340         if (pEntry == NULL)
341         {
342                 RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock);
343                 for (i = 0; i < MAX_TPC_REQ_TAB_SIZE; i++)
344                 {
345                         NdisGetSystemUpTime(&Now);
346                         pEntry = &pTab->Content[i];
347
348                         if ((pEntry->Valid == TRUE)
349                                 && RTMP_TIME_AFTER((unsigned long)Now, (unsigned long)(pEntry->lastTime + TPC_REQ_AGE_OUT)))
350                         {
351                                 PTPC_REQ_ENTRY pPrevEntry = NULL;
352                                 ULONG HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken);
353                                 PTPC_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx];
354
355                                 // update Hash list
356                                 do
357                                 {
358                                         if (pProbeEntry == pEntry)
359                                         {
360                                                 if (pPrevEntry == NULL)
361                                                 {
362                                                         pTab->Hash[HashIdx] = pEntry->pNext;
363                                                 }
364                                                 else
365                                                 {
366                                                         pPrevEntry->pNext = pEntry->pNext;
367                                                 }
368                                                 break;
369                                         }
370
371                                         pPrevEntry = pProbeEntry;
372                                         pProbeEntry = pProbeEntry->pNext;
373                                 } while (pProbeEntry);
374
375                                 NdisZeroMemory(pEntry, sizeof(TPC_REQ_ENTRY));
376                                 pTab->Size--;
377
378                                 break;
379                         }
380
381                         if (pEntry->Valid == FALSE)
382                                 break;
383                 }
384
385                 if (i < MAX_TPC_REQ_TAB_SIZE)
386                 {
387                         NdisGetSystemUpTime(&Now);
388                         pEntry->lastTime = Now;
389                         pEntry->Valid = TRUE;
390                         pEntry->DialogToken = DialogToken;
391                         pTab->Size++;
392                 }
393                 else
394                 {
395                         pEntry = NULL;
396                         DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab tab full.\n", __func__));
397                 }
398
399                 // add this Neighbor entry into HASH table
400                 if (pEntry)
401                 {
402                         HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(DialogToken);
403                         if (pTab->Hash[HashIdx] == NULL)
404                         {
405                                 pTab->Hash[HashIdx] = pEntry;
406                         }
407                         else
408                         {
409                                 pCurrEntry = pTab->Hash[HashIdx];
410                                 while (pCurrEntry->pNext != NULL)
411                                         pCurrEntry = pCurrEntry->pNext;
412                                 pCurrEntry->pNext = pEntry;
413                         }
414                 }
415
416                 RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock);
417         }
418
419         return pEntry;
420 }
421
422 static VOID TpcReqDelete(
423         IN PRTMP_ADAPTER        pAd,
424         IN UINT8                        DialogToken)
425 {
426         PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab;
427         PTPC_REQ_ENTRY pEntry = NULL;
428
429         if(pTab == NULL)
430         {
431                 DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__));
432                 return;
433         }
434
435         // if empty, return
436         if (pTab->Size == 0)
437         {
438                 DBGPRINT(RT_DEBUG_ERROR, ("pTpcReqTab empty.\n"));
439                 return;
440         }
441
442         pEntry = TpcReqLookUp(pAd, DialogToken);
443         if (pEntry != NULL)
444         {
445                 PTPC_REQ_ENTRY pPrevEntry = NULL;
446                 ULONG HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken);
447                 PTPC_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx];
448
449                 RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock);
450                 // update Hash list
451                 do
452                 {
453                         if (pProbeEntry == pEntry)
454                         {
455                                 if (pPrevEntry == NULL)
456                                 {
457                                         pTab->Hash[HashIdx] = pEntry->pNext;
458                                 }
459                                 else
460                                 {
461                                         pPrevEntry->pNext = pEntry->pNext;
462                                 }
463                                 break;
464                         }
465
466                         pPrevEntry = pProbeEntry;
467                         pProbeEntry = pProbeEntry->pNext;
468                 } while (pProbeEntry);
469
470                 NdisZeroMemory(pEntry, sizeof(TPC_REQ_ENTRY));
471                 pTab->Size--;
472
473                 RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock);
474         }
475
476         return;
477 }
478
479 /*
480         ==========================================================================
481         Description:
482                 Get Current TimeS tamp.
483
484         Parametrs:
485
486         Return  : Current Time Stamp.
487         ==========================================================================
488  */
489 static UINT64 GetCurrentTimeStamp(
490         IN PRTMP_ADAPTER pAd)
491 {
492         // get current time stamp.
493         return 0;
494 }
495
496 /*
497         ==========================================================================
498         Description:
499                 Get Current Transmit Power.
500
501         Parametrs:
502
503         Return  : Current Time Stamp.
504         ==========================================================================
505  */
506 static UINT8 GetCurTxPwr(
507         IN PRTMP_ADAPTER pAd,
508         IN UINT8 Wcid)
509 {
510         return 16; /* 16 dBm */
511 }
512
513 /*
514         ==========================================================================
515         Description:
516                 Insert Dialog Token into frame.
517
518         Parametrs:
519                 1. frame buffer pointer.
520                 2. frame length.
521                 3. Dialog token.
522
523         Return  : None.
524         ==========================================================================
525  */
526 static VOID InsertDialogToken(
527         IN PRTMP_ADAPTER pAd,
528         OUT PUCHAR pFrameBuf,
529         OUT PULONG pFrameLen,
530         IN UINT8 DialogToken)
531 {
532         ULONG TempLen;
533         MakeOutgoingFrame(pFrameBuf,    &TempLen,
534                                         1,                              &DialogToken,
535                                         END_OF_ARGS);
536
537         *pFrameLen = *pFrameLen + TempLen;
538
539         return;
540 }
541
542 /*
543         ==========================================================================
544         Description:
545                 Insert TPC Request IE into frame.
546
547         Parametrs:
548                 1. frame buffer pointer.
549                 2. frame length.
550
551         Return  : None.
552         ==========================================================================
553  */
554  static VOID InsertTpcReqIE(
555         IN PRTMP_ADAPTER pAd,
556         OUT PUCHAR pFrameBuf,
557         OUT PULONG pFrameLen)
558 {
559         ULONG TempLen;
560         ULONG Len = 0;
561         UINT8 ElementID = IE_TPC_REQUEST;
562
563         MakeOutgoingFrame(pFrameBuf,                                    &TempLen,
564                                                 1,                                                      &ElementID,
565                                                 1,                                                      &Len,
566                                                 END_OF_ARGS);
567
568         *pFrameLen = *pFrameLen + TempLen;
569
570         return;
571 }
572
573 /*
574         ==========================================================================
575         Description:
576                 Insert TPC Report IE into frame.
577
578         Parametrs:
579                 1. frame buffer pointer.
580                 2. frame length.
581                 3. Transmit Power.
582                 4. Link Margin.
583
584         Return  : None.
585         ==========================================================================
586  */
587  static VOID InsertTpcReportIE(
588         IN PRTMP_ADAPTER pAd,
589         OUT PUCHAR pFrameBuf,
590         OUT PULONG pFrameLen,
591         IN UINT8 TxPwr,
592         IN UINT8 LinkMargin)
593 {
594         ULONG TempLen;
595         ULONG Len = sizeof(TPC_REPORT_INFO);
596         UINT8 ElementID = IE_TPC_REPORT;
597         TPC_REPORT_INFO TpcReportIE;
598
599         TpcReportIE.TxPwr = TxPwr;
600         TpcReportIE.LinkMargin = LinkMargin;
601
602         MakeOutgoingFrame(pFrameBuf,                                    &TempLen,
603                                                 1,                                                      &ElementID,
604                                                 1,                                                      &Len,
605                                                 Len,                                            &TpcReportIE,
606                                                 END_OF_ARGS);
607
608         *pFrameLen = *pFrameLen + TempLen;
609
610
611         return;
612 }
613
614 /*
615         ==========================================================================
616         Description:
617                 Insert Channel Switch Announcement IE into frame.
618
619         Parametrs:
620                 1. frame buffer pointer.
621                 2. frame length.
622                 3. channel switch announcement mode.
623                 4. new selected channel.
624                 5. channel switch announcement count.
625
626         Return  : None.
627         ==========================================================================
628  */
629 static VOID InsertChSwAnnIE(
630         IN PRTMP_ADAPTER pAd,
631         OUT PUCHAR pFrameBuf,
632         OUT PULONG pFrameLen,
633         IN UINT8 ChSwMode,
634         IN UINT8 NewChannel,
635         IN UINT8 ChSwCnt)
636 {
637         ULONG TempLen;
638         ULONG Len = sizeof(CH_SW_ANN_INFO);
639         UINT8 ElementID = IE_CHANNEL_SWITCH_ANNOUNCEMENT;
640         CH_SW_ANN_INFO ChSwAnnIE;
641
642         ChSwAnnIE.ChSwMode = ChSwMode;
643         ChSwAnnIE.Channel = NewChannel;
644         ChSwAnnIE.ChSwCnt = ChSwCnt;
645
646         MakeOutgoingFrame(pFrameBuf,                            &TempLen,
647                                                 1,                                              &ElementID,
648                                                 1,                                              &Len,
649                                                 Len,                                    &ChSwAnnIE,
650                                                 END_OF_ARGS);
651
652         *pFrameLen = *pFrameLen + TempLen;
653
654
655         return;
656 }
657
658 /*
659         ==========================================================================
660         Description:
661                 Insert Measure Request IE into frame.
662
663         Parametrs:
664                 1. frame buffer pointer.
665                 2. frame length.
666                 3. Measure Token.
667                 4. Measure Request Mode.
668                 5. Measure Request Type.
669                 6. Measure Channel.
670                 7. Measure Start time.
671                 8. Measure Duration.
672
673
674         Return  : None.
675         ==========================================================================
676  */
677 static VOID InsertMeasureReqIE(
678         IN PRTMP_ADAPTER pAd,
679         OUT PUCHAR pFrameBuf,
680         OUT PULONG pFrameLen,
681         IN PMEASURE_REQ_INFO pMeasureReqIE)
682 {
683         ULONG TempLen;
684         UINT8 Len = sizeof(MEASURE_REQ_INFO);
685         UINT8 ElementID = IE_MEASUREMENT_REQUEST;
686
687         MakeOutgoingFrame(pFrameBuf,                                    &TempLen,
688                                                 1,                                                      &ElementID,
689                                                 1,                                                      &Len,
690                                                 Len,                                            pMeasureReqIE,
691                                                 END_OF_ARGS);
692
693         *pFrameLen = *pFrameLen + TempLen;
694
695         return;
696 }
697
698 /*
699         ==========================================================================
700         Description:
701                 Insert Measure Report IE into frame.
702
703         Parametrs:
704                 1. frame buffer pointer.
705                 2. frame length.
706                 3. Measure Token.
707                 4. Measure Request Mode.
708                 5. Measure Request Type.
709                 6. Length of Report Infomation
710                 7. Pointer of Report Infomation Buffer.
711
712         Return  : None.
713         ==========================================================================
714  */
715 static VOID InsertMeasureReportIE(
716         IN PRTMP_ADAPTER pAd,
717         OUT PUCHAR pFrameBuf,
718         OUT PULONG pFrameLen,
719         IN PMEASURE_REPORT_INFO pMeasureReportIE,
720         IN UINT8 ReportLnfoLen,
721         IN PUINT8 pReportInfo)
722 {
723         ULONG TempLen;
724         ULONG Len;
725         UINT8 ElementID = IE_MEASUREMENT_REPORT;
726
727         Len = sizeof(MEASURE_REPORT_INFO) + ReportLnfoLen;
728
729         MakeOutgoingFrame(pFrameBuf,                                    &TempLen,
730                                                 1,                                                      &ElementID,
731                                                 1,                                                      &Len,
732                                                 Len,                                            pMeasureReportIE,
733                                                 END_OF_ARGS);
734
735         *pFrameLen = *pFrameLen + TempLen;
736
737         if ((ReportLnfoLen > 0) && (pReportInfo != NULL))
738         {
739                 MakeOutgoingFrame(pFrameBuf + *pFrameLen,               &TempLen,
740                                                         ReportLnfoLen,                          pReportInfo,
741                                                         END_OF_ARGS);
742
743                 *pFrameLen = *pFrameLen + TempLen;
744         }
745         return;
746 }
747
748 /*
749         ==========================================================================
750         Description:
751                 Prepare Measurement request action frame and enqueue it into
752                 management queue waiting for transmition.
753
754         Parametrs:
755                 1. the destination mac address of the frame.
756
757         Return  : None.
758         ==========================================================================
759  */
760 VOID EnqueueMeasurementReq(
761         IN PRTMP_ADAPTER pAd,
762         IN PUCHAR pDA,
763         IN UINT8 MeasureToken,
764         IN UINT8 MeasureReqMode,
765         IN UINT8 MeasureReqType,
766         IN UINT8 MeasureCh,
767         IN UINT16 MeasureDuration)
768 {
769         PUCHAR pOutBuffer = NULL;
770         NDIS_STATUS NStatus;
771         ULONG FrameLen;
772         HEADER_802_11 ActHdr;
773         MEASURE_REQ_INFO MeasureReqIE;
774         UINT8 RmReqDailogToken = RandomByte(pAd);
775         UINT64 MeasureStartTime = GetCurrentTimeStamp(pAd);
776
777         // build action frame header.
778         MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA,
779                                                 pAd->CurrentAddress);
780
781         NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
782         if(NStatus != NDIS_STATUS_SUCCESS)
783         {
784                 DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
785                 return;
786         }
787         NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
788         FrameLen = sizeof(HEADER_802_11);
789
790         InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_MRQ);
791
792         // fill Dialog Token
793         InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, MeasureToken);
794
795         // prepare Measurement IE.
796         NdisZeroMemory(&MeasureReqIE, sizeof(MEASURE_REQ_INFO));
797         MeasureReqIE.Token = RmReqDailogToken;
798         MeasureReqIE.ReqMode.word = MeasureReqMode;
799         MeasureReqIE.ReqType = MeasureReqType;
800         MeasureReqIE.MeasureReq.ChNum = MeasureCh;
801         MeasureReqIE.MeasureReq.MeasureStartTime = cpu2le64(MeasureStartTime);
802         MeasureReqIE.MeasureReq.MeasureDuration = cpu2le16(MeasureDuration);
803         InsertMeasureReqIE(pAd, (pOutBuffer + FrameLen), &FrameLen, &MeasureReqIE);
804
805         MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
806         MlmeFreeMemory(pAd, pOutBuffer);
807
808         return;
809 }
810
811 /*
812         ==========================================================================
813         Description:
814                 Prepare Measurement report action frame and enqueue it into
815                 management queue waiting for transmition.
816
817         Parametrs:
818                 1. the destination mac address of the frame.
819
820         Return  : None.
821         ==========================================================================
822  */
823 VOID EnqueueMeasurementRep(
824         IN PRTMP_ADAPTER pAd,
825         IN PUCHAR pDA,
826         IN UINT8 DialogToken,
827         IN UINT8 MeasureToken,
828         IN UINT8 MeasureReqMode,
829         IN UINT8 MeasureReqType,
830         IN UINT8 ReportInfoLen,
831         IN PUINT8 pReportInfo)
832 {
833         PUCHAR pOutBuffer = NULL;
834         NDIS_STATUS NStatus;
835         ULONG FrameLen;
836         HEADER_802_11 ActHdr;
837         MEASURE_REPORT_INFO MeasureRepIE;
838
839         // build action frame header.
840         MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA,
841                                                 pAd->CurrentAddress);
842
843         NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
844         if(NStatus != NDIS_STATUS_SUCCESS)
845         {
846                 DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
847                 return;
848         }
849         NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
850         FrameLen = sizeof(HEADER_802_11);
851
852         InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_MRP);
853
854         // fill Dialog Token
855         InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken);
856
857         // prepare Measurement IE.
858         NdisZeroMemory(&MeasureRepIE, sizeof(MEASURE_REPORT_INFO));
859         MeasureRepIE.Token = MeasureToken;
860         MeasureRepIE.ReportMode.word = MeasureReqMode;
861         MeasureRepIE.ReportType = MeasureReqType;
862         InsertMeasureReportIE(pAd, (pOutBuffer + FrameLen), &FrameLen, &MeasureRepIE, ReportInfoLen, pReportInfo);
863
864         MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
865         MlmeFreeMemory(pAd, pOutBuffer);
866
867         return;
868 }
869
870 /*
871         ==========================================================================
872         Description:
873                 Prepare TPC Request action frame and enqueue it into
874                 management queue waiting for transmition.
875
876         Parametrs:
877                 1. the destination mac address of the frame.
878
879         Return  : None.
880         ==========================================================================
881  */
882 VOID EnqueueTPCReq(
883         IN PRTMP_ADAPTER pAd,
884         IN PUCHAR pDA,
885         IN UCHAR DialogToken)
886 {
887         PUCHAR pOutBuffer = NULL;
888         NDIS_STATUS NStatus;
889         ULONG FrameLen;
890
891         HEADER_802_11 ActHdr;
892
893         // build action frame header.
894         MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA,
895                                                 pAd->CurrentAddress);
896
897         NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
898         if(NStatus != NDIS_STATUS_SUCCESS)
899         {
900                 DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
901                 return;
902         }
903         NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
904         FrameLen = sizeof(HEADER_802_11);
905
906         InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_TPCRQ);
907
908         // fill Dialog Token
909         InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken);
910
911         // Insert TPC Request IE.
912         InsertTpcReqIE(pAd, (pOutBuffer + FrameLen), &FrameLen);
913
914         MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
915         MlmeFreeMemory(pAd, pOutBuffer);
916
917         return;
918 }
919
920 /*
921         ==========================================================================
922         Description:
923                 Prepare TPC Report action frame and enqueue it into
924                 management queue waiting for transmition.
925
926         Parametrs:
927                 1. the destination mac address of the frame.
928
929         Return  : None.
930         ==========================================================================
931  */
932 VOID EnqueueTPCRep(
933         IN PRTMP_ADAPTER pAd,
934         IN PUCHAR pDA,
935         IN UINT8 DialogToken,
936         IN UINT8 TxPwr,
937         IN UINT8 LinkMargin)
938 {
939         PUCHAR pOutBuffer = NULL;
940         NDIS_STATUS NStatus;
941         ULONG FrameLen;
942
943         HEADER_802_11 ActHdr;
944
945         // build action frame header.
946         MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA,
947                                                 pAd->CurrentAddress);
948
949         NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
950         if(NStatus != NDIS_STATUS_SUCCESS)
951         {
952                 DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
953                 return;
954         }
955         NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
956         FrameLen = sizeof(HEADER_802_11);
957
958         InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_TPCRP);
959
960         // fill Dialog Token
961         InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken);
962
963         // Insert TPC Request IE.
964         InsertTpcReportIE(pAd, (pOutBuffer + FrameLen), &FrameLen, TxPwr, LinkMargin);
965
966         MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
967         MlmeFreeMemory(pAd, pOutBuffer);
968
969         return;
970 }
971
972 /*
973         ==========================================================================
974         Description:
975                 Prepare Channel Switch Announcement action frame and enqueue it into
976                 management queue waiting for transmition.
977
978         Parametrs:
979                 1. the destination mac address of the frame.
980                 2. Channel switch announcement mode.
981                 2. a New selected channel.
982
983         Return  : None.
984         ==========================================================================
985  */
986 VOID EnqueueChSwAnn(
987         IN PRTMP_ADAPTER pAd,
988         IN PUCHAR pDA,
989         IN UINT8 ChSwMode,
990         IN UINT8 NewCh)
991 {
992         PUCHAR pOutBuffer = NULL;
993         NDIS_STATUS NStatus;
994         ULONG FrameLen;
995
996         HEADER_802_11 ActHdr;
997
998         // build action frame header.
999         MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA,
1000                                                 pAd->CurrentAddress);
1001
1002         NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
1003         if(NStatus != NDIS_STATUS_SUCCESS)
1004         {
1005                 DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
1006                 return;
1007         }
1008         NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
1009         FrameLen = sizeof(HEADER_802_11);
1010
1011         InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_CHANNEL_SWITCH);
1012
1013         InsertChSwAnnIE(pAd, (pOutBuffer + FrameLen), &FrameLen, ChSwMode, NewCh, 0);
1014
1015         MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
1016         MlmeFreeMemory(pAd, pOutBuffer);
1017
1018         return;
1019 }
1020
1021 static BOOLEAN DfsRequirementCheck(
1022         IN PRTMP_ADAPTER pAd,
1023         IN UINT8 Channel)
1024 {
1025         BOOLEAN Result = FALSE;
1026         INT i;
1027
1028         do
1029         {
1030                 // check DFS procedure is running.
1031                 // make sure DFS procedure won't start twice.
1032                 if (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)
1033                 {
1034                         Result = FALSE;
1035                         break;
1036                 }
1037
1038                 // check the new channel carried from Channel Switch Announcemnet is valid.
1039                 for (i=0; i<pAd->ChannelListNum; i++)
1040                 {
1041                         if ((Channel == pAd->ChannelList[i].Channel)
1042                                 &&(pAd->ChannelList[i].RemainingTimeForUse == 0))
1043                         {
1044                                 // found radar signal in the channel. the channel can't use at least for 30 minutes.
1045                                 pAd->ChannelList[i].RemainingTimeForUse = 1800;//30 min = 1800 sec
1046                                 Result = TRUE;
1047                                 break;
1048                         }
1049                 }
1050         } while(FALSE);
1051
1052         return Result;
1053 }
1054
1055 VOID NotifyChSwAnnToPeerAPs(
1056         IN PRTMP_ADAPTER pAd,
1057         IN PUCHAR pRA,
1058         IN PUCHAR pTA,
1059         IN UINT8 ChSwMode,
1060         IN UINT8 Channel)
1061 {
1062 #ifdef WDS_SUPPORT
1063         if (!((pRA[0] & 0xff) == 0xff)) // is pRA a broadcase address.
1064         {
1065                 INT i;
1066                 // info neighbor APs that Radar signal found throgh WDS link.
1067                 for (i = 0; i < MAX_WDS_ENTRY; i++)
1068                 {
1069                         if (ValidWdsEntry(pAd, i))
1070                         {
1071                                 PUCHAR pDA = pAd->WdsTab.WdsEntry[i].PeerWdsAddr;
1072
1073                                 // DA equal to SA. have no necessary orignal AP which found Radar signal.
1074                                 if (MAC_ADDR_EQUAL(pTA, pDA))
1075                                         continue;
1076
1077                                 // send Channel Switch Action frame to info Neighbro APs.
1078                                 EnqueueChSwAnn(pAd, pDA, ChSwMode, Channel);
1079                         }
1080                 }
1081         }
1082 #endif // WDS_SUPPORT //
1083 }
1084
1085 static VOID StartDFSProcedure(
1086         IN PRTMP_ADAPTER pAd,
1087         IN UCHAR Channel,
1088         IN UINT8 ChSwMode)
1089 {
1090         // start DFS procedure
1091         pAd->CommonCfg.Channel = Channel;
1092 #ifdef DOT11_N_SUPPORT
1093         N_ChannelCheck(pAd);
1094 #endif // DOT11_N_SUPPORT //
1095         pAd->CommonCfg.RadarDetect.RDMode = RD_SWITCHING_MODE;
1096         pAd->CommonCfg.RadarDetect.CSCount = 0;
1097 }
1098
1099 /*
1100         ==========================================================================
1101         Description:
1102                 Channel Switch Announcement action frame sanity check.
1103
1104         Parametrs:
1105                 1. MLME message containing the received frame
1106                 2. message length.
1107                 3. Channel switch announcement infomation buffer.
1108
1109
1110         Return  : None.
1111         ==========================================================================
1112  */
1113
1114 /*
1115   Channel Switch Announcement IE.
1116   +----+-----+-----------+------------+-----------+
1117   | ID | Len |Ch Sw Mode | New Ch Num | Ch Sw Cnt |
1118   +----+-----+-----------+------------+-----------+
1119     1    1        1           1            1
1120 */
1121 static BOOLEAN PeerChSwAnnSanity(
1122         IN PRTMP_ADAPTER pAd,
1123         IN VOID *pMsg,
1124         IN ULONG MsgLen,
1125         OUT PCH_SW_ANN_INFO pChSwAnnInfo)
1126 {
1127         PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
1128         PUCHAR pFramePtr = Fr->Octet;
1129         BOOLEAN result = FALSE;
1130         PEID_STRUCT eid_ptr;
1131
1132         // skip 802.11 header.
1133         MsgLen -= sizeof(HEADER_802_11);
1134
1135         // skip category and action code.
1136         pFramePtr += 2;
1137         MsgLen -= 2;
1138
1139         if (pChSwAnnInfo == NULL)
1140                 return result;
1141
1142         eid_ptr = (PEID_STRUCT)pFramePtr;
1143         while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
1144         {
1145                 switch(eid_ptr->Eid)
1146                 {
1147                         case IE_CHANNEL_SWITCH_ANNOUNCEMENT:
1148                                 NdisMoveMemory(&pChSwAnnInfo->ChSwMode, eid_ptr->Octet, 1);
1149                                 NdisMoveMemory(&pChSwAnnInfo->Channel, eid_ptr->Octet + 1, 1);
1150                                 NdisMoveMemory(&pChSwAnnInfo->ChSwCnt, eid_ptr->Octet + 2, 1);
1151
1152                                 result = TRUE;
1153                 break;
1154
1155                         default:
1156                                 break;
1157                 }
1158                 eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
1159         }
1160
1161         return result;
1162 }
1163
1164 /*
1165         ==========================================================================
1166         Description:
1167                 Measurement request action frame sanity check.
1168
1169         Parametrs:
1170                 1. MLME message containing the received frame
1171                 2. message length.
1172                 3. Measurement request infomation buffer.
1173
1174         Return  : None.
1175         ==========================================================================
1176  */
1177 static BOOLEAN PeerMeasureReqSanity(
1178         IN PRTMP_ADAPTER pAd,
1179         IN VOID *pMsg,
1180         IN ULONG MsgLen,
1181         OUT PUINT8 pDialogToken,
1182         OUT PMEASURE_REQ_INFO pMeasureReqInfo)
1183 {
1184         PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
1185         PUCHAR pFramePtr = Fr->Octet;
1186         BOOLEAN result = FALSE;
1187         PEID_STRUCT eid_ptr;
1188         PUCHAR ptr;
1189         UINT64 MeasureStartTime;
1190         UINT16 MeasureDuration;
1191
1192         // skip 802.11 header.
1193         MsgLen -= sizeof(HEADER_802_11);
1194
1195         // skip category and action code.
1196         pFramePtr += 2;
1197         MsgLen -= 2;
1198
1199         if (pMeasureReqInfo == NULL)
1200                 return result;
1201
1202         NdisMoveMemory(pDialogToken, pFramePtr, 1);
1203         pFramePtr += 1;
1204         MsgLen -= 1;
1205
1206         eid_ptr = (PEID_STRUCT)pFramePtr;
1207         while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
1208         {
1209                 switch(eid_ptr->Eid)
1210                 {
1211                         case IE_MEASUREMENT_REQUEST:
1212                                 NdisMoveMemory(&pMeasureReqInfo->Token, eid_ptr->Octet, 1);
1213                                 NdisMoveMemory(&pMeasureReqInfo->ReqMode.word, eid_ptr->Octet + 1, 1);
1214                                 NdisMoveMemory(&pMeasureReqInfo->ReqType, eid_ptr->Octet + 2, 1);
1215                                 ptr = eid_ptr->Octet + 3;
1216                                 NdisMoveMemory(&pMeasureReqInfo->MeasureReq.ChNum, ptr, 1);
1217                                 NdisMoveMemory(&MeasureStartTime, ptr + 1, 8);
1218                                 pMeasureReqInfo->MeasureReq.MeasureStartTime = SWAP64(MeasureStartTime);
1219                                 NdisMoveMemory(&MeasureDuration, ptr + 9, 2);
1220                                 pMeasureReqInfo->MeasureReq.MeasureDuration = SWAP16(MeasureDuration);
1221
1222                                 result = TRUE;
1223                                 break;
1224
1225                         default:
1226                                 break;
1227                 }
1228                 eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
1229         }
1230
1231         return result;
1232 }
1233
1234 /*
1235         ==========================================================================
1236         Description:
1237                 Measurement report action frame sanity check.
1238
1239         Parametrs:
1240                 1. MLME message containing the received frame
1241                 2. message length.
1242                 3. Measurement report infomation buffer.
1243                 4. basic report infomation buffer.
1244
1245         Return  : None.
1246         ==========================================================================
1247  */
1248
1249 /*
1250   Measurement Report IE.
1251   +----+-----+-------+-------------+--------------+----------------+
1252   | ID | Len | Token | Report Mode | Measure Type | Measure Report |
1253   +----+-----+-------+-------------+--------------+----------------+
1254     1     1      1          1             1            variable
1255
1256   Basic Report.
1257   +--------+------------+----------+-----+
1258   | Ch Num | Start Time | Duration | Map |
1259   +--------+------------+----------+-----+
1260       1          8           2        1
1261
1262   Map Field Bit Format.
1263   +-----+---------------+---------------------+-------+------------+----------+
1264   | Bss | OFDM Preamble | Unidentified signal | Radar | Unmeasured | Reserved |
1265   +-----+---------------+---------------------+-------+------------+----------+
1266      0          1                  2              3         4          5-7
1267 */
1268 static BOOLEAN PeerMeasureReportSanity(
1269         IN PRTMP_ADAPTER pAd,
1270         IN VOID *pMsg,
1271         IN ULONG MsgLen,
1272         OUT PUINT8 pDialogToken,
1273         OUT PMEASURE_REPORT_INFO pMeasureReportInfo,
1274         OUT PUINT8 pReportBuf)
1275 {
1276         PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
1277         PUCHAR pFramePtr = Fr->Octet;
1278         BOOLEAN result = FALSE;
1279         PEID_STRUCT eid_ptr;
1280         PUCHAR ptr;
1281
1282         // skip 802.11 header.
1283         MsgLen -= sizeof(HEADER_802_11);
1284
1285         // skip category and action code.
1286         pFramePtr += 2;
1287         MsgLen -= 2;
1288
1289         if (pMeasureReportInfo == NULL)
1290                 return result;
1291
1292         NdisMoveMemory(pDialogToken, pFramePtr, 1);
1293         pFramePtr += 1;
1294         MsgLen -= 1;
1295
1296         eid_ptr = (PEID_STRUCT)pFramePtr;
1297         while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
1298         {
1299                 switch(eid_ptr->Eid)
1300                 {
1301                         case IE_MEASUREMENT_REPORT:
1302                                 NdisMoveMemory(&pMeasureReportInfo->Token, eid_ptr->Octet, 1);
1303                                 NdisMoveMemory(&pMeasureReportInfo->ReportMode, eid_ptr->Octet + 1, 1);
1304                                 NdisMoveMemory(&pMeasureReportInfo->ReportType, eid_ptr->Octet + 2, 1);
1305                                 if (pMeasureReportInfo->ReportType == RM_BASIC)
1306                                 {
1307                                         PMEASURE_BASIC_REPORT pReport = (PMEASURE_BASIC_REPORT)pReportBuf;
1308                                         ptr = eid_ptr->Octet + 3;
1309                                         NdisMoveMemory(&pReport->ChNum, ptr, 1);
1310                                         NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8);
1311                                         NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2);
1312                                         NdisMoveMemory(&pReport->Map, ptr + 11, 1);
1313
1314                                 }
1315                                 else if (pMeasureReportInfo->ReportType == RM_CCA)
1316                                 {
1317                                         PMEASURE_CCA_REPORT pReport = (PMEASURE_CCA_REPORT)pReportBuf;
1318                                         ptr = eid_ptr->Octet + 3;
1319                                         NdisMoveMemory(&pReport->ChNum, ptr, 1);
1320                                         NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8);
1321                                         NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2);
1322                                         NdisMoveMemory(&pReport->CCA_Busy_Fraction, ptr + 11, 1);
1323
1324                                 }
1325                                 else if (pMeasureReportInfo->ReportType == RM_RPI_HISTOGRAM)
1326                                 {
1327                                         PMEASURE_RPI_REPORT pReport = (PMEASURE_RPI_REPORT)pReportBuf;
1328                                         ptr = eid_ptr->Octet + 3;
1329                                         NdisMoveMemory(&pReport->ChNum, ptr, 1);
1330                                         NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8);
1331                                         NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2);
1332                                         NdisMoveMemory(&pReport->RPI_Density, ptr + 11, 8);
1333                                 }
1334                                 result = TRUE;
1335                 break;
1336
1337                         default:
1338                                 break;
1339                 }
1340                 eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
1341         }
1342
1343         return result;
1344 }
1345
1346 /*
1347         ==========================================================================
1348         Description:
1349                 TPC Request action frame sanity check.
1350
1351         Parametrs:
1352                 1. MLME message containing the received frame
1353                 2. message length.
1354                 3. Dialog Token.
1355
1356         Return  : None.
1357         ==========================================================================
1358  */
1359 static BOOLEAN PeerTpcReqSanity(
1360         IN PRTMP_ADAPTER pAd,
1361         IN VOID *pMsg,
1362         IN ULONG MsgLen,
1363         OUT PUINT8 pDialogToken)
1364 {
1365         PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
1366         PUCHAR pFramePtr = Fr->Octet;
1367         BOOLEAN result = FALSE;
1368         PEID_STRUCT eid_ptr;
1369
1370         MsgLen -= sizeof(HEADER_802_11);
1371
1372         // skip category and action code.
1373         pFramePtr += 2;
1374         MsgLen -= 2;
1375
1376         if (pDialogToken == NULL)
1377                 return result;
1378
1379         NdisMoveMemory(pDialogToken, pFramePtr, 1);
1380         pFramePtr += 1;
1381         MsgLen -= 1;
1382
1383         eid_ptr = (PEID_STRUCT)pFramePtr;
1384         while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
1385         {
1386                 switch(eid_ptr->Eid)
1387                 {
1388                         case IE_TPC_REQUEST:
1389                                 result = TRUE;
1390                 break;
1391
1392                         default:
1393                                 break;
1394                 }
1395                 eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
1396         }
1397
1398         return result;
1399 }
1400
1401 /*
1402         ==========================================================================
1403         Description:
1404                 TPC Report action frame sanity check.
1405
1406         Parametrs:
1407                 1. MLME message containing the received frame
1408                 2. message length.
1409                 3. Dialog Token.
1410                 4. TPC Report IE.
1411
1412         Return  : None.
1413         ==========================================================================
1414  */
1415 static BOOLEAN PeerTpcRepSanity(
1416         IN PRTMP_ADAPTER pAd,
1417         IN VOID *pMsg,
1418         IN ULONG MsgLen,
1419         OUT PUINT8 pDialogToken,
1420         OUT PTPC_REPORT_INFO pTpcRepInfo)
1421 {
1422         PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
1423         PUCHAR pFramePtr = Fr->Octet;
1424         BOOLEAN result = FALSE;
1425         PEID_STRUCT eid_ptr;
1426
1427         MsgLen -= sizeof(HEADER_802_11);
1428
1429         // skip category and action code.
1430         pFramePtr += 2;
1431         MsgLen -= 2;
1432
1433         if (pDialogToken == NULL)
1434                 return result;
1435
1436         NdisMoveMemory(pDialogToken, pFramePtr, 1);
1437         pFramePtr += 1;
1438         MsgLen -= 1;
1439
1440         eid_ptr = (PEID_STRUCT)pFramePtr;
1441         while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
1442         {
1443                 switch(eid_ptr->Eid)
1444                 {
1445                         case IE_TPC_REPORT:
1446                                 NdisMoveMemory(&pTpcRepInfo->TxPwr, eid_ptr->Octet, 1);
1447                                 NdisMoveMemory(&pTpcRepInfo->LinkMargin, eid_ptr->Octet + 1, 1);
1448                                 result = TRUE;
1449                 break;
1450
1451                         default:
1452                                 break;
1453                 }
1454                 eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
1455         }
1456
1457         return result;
1458 }
1459
1460 /*
1461         ==========================================================================
1462         Description:
1463                 Channel Switch Announcement action frame handler.
1464
1465         Parametrs:
1466                 Elme - MLME message containing the received frame
1467
1468         Return  : None.
1469         ==========================================================================
1470  */
1471 static VOID PeerChSwAnnAction(
1472         IN PRTMP_ADAPTER pAd,
1473         IN MLME_QUEUE_ELEM *Elem)
1474 {
1475         CH_SW_ANN_INFO ChSwAnnInfo;
1476         PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg;
1477 #ifdef CONFIG_STA_SUPPORT
1478         UCHAR index = 0, Channel = 0, NewChannel = 0;
1479         ULONG Bssidx = 0;
1480 #endif // CONFIG_STA_SUPPORT //
1481
1482         NdisZeroMemory(&ChSwAnnInfo, sizeof(CH_SW_ANN_INFO));
1483         if (! PeerChSwAnnSanity(pAd, Elem->Msg, Elem->MsgLen, &ChSwAnnInfo))
1484         {
1485                 DBGPRINT(RT_DEBUG_TRACE, ("Invalid Channel Switch Action Frame.\n"));
1486                 return;
1487         }
1488
1489
1490 #ifdef CONFIG_STA_SUPPORT
1491         if (pAd->OpMode == OPMODE_STA)
1492         {
1493                 Bssidx = BssTableSearch(&pAd->ScanTab, pFr->Hdr.Addr3, pAd->CommonCfg.Channel);
1494                 if (Bssidx == BSS_NOT_FOUND)
1495                 {
1496                         DBGPRINT(RT_DEBUG_TRACE, ("PeerChSwAnnAction - Bssidx is not found\n"));
1497                         return;
1498                 }
1499
1500                 DBGPRINT(RT_DEBUG_TRACE, ("\n****Bssidx is %d, Channel = %d\n", index, pAd->ScanTab.BssEntry[Bssidx].Channel));
1501                 hex_dump("SSID",pAd->ScanTab.BssEntry[Bssidx].Bssid ,6);
1502
1503                 Channel = pAd->CommonCfg.Channel;
1504                 NewChannel = ChSwAnnInfo.Channel;
1505
1506                 if ((pAd->CommonCfg.bIEEE80211H == 1) && (NewChannel != 0) && (Channel != NewChannel))
1507                 {
1508                         // Switching to channel 1 can prevent from rescanning the current channel immediately (by auto reconnection).
1509                         // In addition, clear the MLME queue and the scan table to discard the RX packets and previous scanning results.
1510                         AsicSwitchChannel(pAd, 1, FALSE);
1511                         AsicLockChannel(pAd, 1);
1512                     LinkDown(pAd, FALSE);
1513                         MlmeQueueInit(&pAd->Mlme.Queue);
1514                         BssTableInit(&pAd->ScanTab);
1515                     RTMPusecDelay(1000000);             // use delay to prevent STA do reassoc
1516
1517                         // channel sanity check
1518                         for (index = 0 ; index < pAd->ChannelListNum; index++)
1519                         {
1520                                 if (pAd->ChannelList[index].Channel == NewChannel)
1521                                 {
1522                                         pAd->ScanTab.BssEntry[Bssidx].Channel = NewChannel;
1523                                         pAd->CommonCfg.Channel = NewChannel;
1524                                         AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
1525                                         AsicLockChannel(pAd, pAd->CommonCfg.Channel);
1526                                         DBGPRINT(RT_DEBUG_TRACE, ("&&&&&&&&&&&&&&&&PeerChSwAnnAction - STA receive channel switch announcement IE (New Channel =%d)\n", NewChannel));
1527                                         break;
1528                                 }
1529                         }
1530
1531                         if (index >= pAd->ChannelListNum)
1532                         {
1533                                 DBGPRINT_ERR(("&&&&&&&&&&&&&&&&&&&&&&&&&&PeerChSwAnnAction(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum));
1534                         }
1535                 }
1536         }
1537 #endif // CONFIG_STA_SUPPORT //
1538
1539         return;
1540 }
1541
1542
1543 /*
1544         ==========================================================================
1545         Description:
1546                 Measurement Request action frame handler.
1547
1548         Parametrs:
1549                 Elme - MLME message containing the received frame
1550
1551         Return  : None.
1552         ==========================================================================
1553  */
1554 static VOID PeerMeasureReqAction(
1555         IN PRTMP_ADAPTER pAd,
1556         IN MLME_QUEUE_ELEM *Elem)
1557 {
1558         PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg;
1559         UINT8 DialogToken;
1560         MEASURE_REQ_INFO MeasureReqInfo;
1561         MEASURE_REPORT_MODE ReportMode;
1562
1563         if(PeerMeasureReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReqInfo))
1564         {
1565                 ReportMode.word = 0;
1566                 ReportMode.field.Incapable = 1;
1567                 EnqueueMeasurementRep(pAd, pFr->Hdr.Addr2, DialogToken, MeasureReqInfo.Token, ReportMode.word, MeasureReqInfo.ReqType, 0, NULL);
1568         }
1569
1570         return;
1571 }
1572
1573 /*
1574         ==========================================================================
1575         Description:
1576                 Measurement Report action frame handler.
1577
1578         Parametrs:
1579                 Elme - MLME message containing the received frame
1580
1581         Return  : None.
1582         ==========================================================================
1583  */
1584 static VOID PeerMeasureReportAction(
1585         IN PRTMP_ADAPTER pAd,
1586         IN MLME_QUEUE_ELEM *Elem)
1587 {
1588         MEASURE_REPORT_INFO MeasureReportInfo;
1589         PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg;
1590         UINT8 DialogToken;
1591         PUINT8 pMeasureReportInfo;
1592
1593 //      if (pAd->CommonCfg.bIEEE80211H != TRUE)
1594 //              return;
1595
1596         if ((pMeasureReportInfo = kmalloc(sizeof(MEASURE_RPI_REPORT), GFP_ATOMIC)) == NULL)
1597         {
1598                 DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%zu).\n", __func__, sizeof(MEASURE_RPI_REPORT)));
1599                 return;
1600         }
1601
1602         NdisZeroMemory(&MeasureReportInfo, sizeof(MEASURE_REPORT_INFO));
1603         NdisZeroMemory(pMeasureReportInfo, sizeof(MEASURE_RPI_REPORT));
1604         if (PeerMeasureReportSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReportInfo, pMeasureReportInfo))
1605         {
1606                 do {
1607                         PMEASURE_REQ_ENTRY pEntry = NULL;
1608
1609                         // Not a autonomous measure report.
1610                         // check the dialog token field. drop it if the dialog token doesn't match.
1611                         if ((DialogToken != 0)
1612                                 && ((pEntry = MeasureReqLookUp(pAd, DialogToken)) == NULL))
1613                                 break;
1614
1615                         if (pEntry != NULL)
1616                                 MeasureReqDelete(pAd, pEntry->DialogToken);
1617
1618                         if (MeasureReportInfo.ReportType == RM_BASIC)
1619                         {
1620                                 PMEASURE_BASIC_REPORT pBasicReport = (PMEASURE_BASIC_REPORT)pMeasureReportInfo;
1621                                 if ((pBasicReport->Map.field.Radar)
1622                                         && (DfsRequirementCheck(pAd, pBasicReport->ChNum) == TRUE))
1623                                 {
1624                                         NotifyChSwAnnToPeerAPs(pAd, pFr->Hdr.Addr1, pFr->Hdr.Addr2, 1, pBasicReport->ChNum);
1625                                         StartDFSProcedure(pAd, pBasicReport->ChNum, 1);
1626                                 }
1627                         }
1628                 } while (FALSE);
1629         }
1630         else
1631                 DBGPRINT(RT_DEBUG_TRACE, ("Invalid Measurement Report Frame.\n"));
1632
1633         kfree(pMeasureReportInfo);
1634
1635         return;
1636 }
1637
1638 /*
1639         ==========================================================================
1640         Description:
1641                 TPC Request action frame handler.
1642
1643         Parametrs:
1644                 Elme - MLME message containing the received frame
1645
1646         Return  : None.
1647         ==========================================================================
1648  */
1649 static VOID PeerTpcReqAction(
1650         IN PRTMP_ADAPTER pAd,
1651         IN MLME_QUEUE_ELEM *Elem)
1652 {
1653         PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg;
1654         PUCHAR pFramePtr = pFr->Octet;
1655         UINT8 DialogToken;
1656         UINT8 TxPwr = GetCurTxPwr(pAd, Elem->Wcid);
1657         UINT8 LinkMargin = 0;
1658         CHAR RealRssi;
1659
1660         // link margin: Ratio of the received signal power to the minimum desired by the station (STA). The
1661         //                              STA may incorporate rate information and channel conditions, including interference, into its computation
1662         //                              of link margin.
1663
1664         RealRssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0),
1665                                                                 ConvertToRssi(pAd, Elem->Rssi1, RSSI_1),
1666                                                                 ConvertToRssi(pAd, Elem->Rssi2, RSSI_2));
1667
1668         // skip Category and action code.
1669         pFramePtr += 2;
1670
1671         // Dialog token.
1672         NdisMoveMemory(&DialogToken, pFramePtr, 1);
1673
1674         LinkMargin = (RealRssi / MIN_RCV_PWR);
1675         if (PeerTpcReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken))
1676                 EnqueueTPCRep(pAd, pFr->Hdr.Addr2, DialogToken, TxPwr, LinkMargin);
1677
1678         return;
1679 }
1680
1681 /*
1682         ==========================================================================
1683         Description:
1684                 TPC Report action frame handler.
1685
1686         Parametrs:
1687                 Elme - MLME message containing the received frame
1688
1689         Return  : None.
1690         ==========================================================================
1691  */
1692 static VOID PeerTpcRepAction(
1693         IN PRTMP_ADAPTER pAd,
1694         IN MLME_QUEUE_ELEM *Elem)
1695 {
1696         UINT8 DialogToken;
1697         TPC_REPORT_INFO TpcRepInfo;
1698         PTPC_REQ_ENTRY pEntry = NULL;
1699
1700         NdisZeroMemory(&TpcRepInfo, sizeof(TPC_REPORT_INFO));
1701         if (PeerTpcRepSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &TpcRepInfo))
1702         {
1703                 if ((pEntry = TpcReqLookUp(pAd, DialogToken)) != NULL)
1704                 {
1705                         TpcReqDelete(pAd, pEntry->DialogToken);
1706                         DBGPRINT(RT_DEBUG_TRACE, ("%s: DialogToken=%x, TxPwr=%d, LinkMargin=%d\n",
1707                                 __func__, DialogToken, TpcRepInfo.TxPwr, TpcRepInfo.LinkMargin));
1708                 }
1709         }
1710
1711         return;
1712 }
1713
1714 /*
1715         ==========================================================================
1716         Description:
1717                 Spectrun action frames Handler such as channel switch annoucement,
1718                 measurement report, measurement request actions frames.
1719
1720         Parametrs:
1721                 Elme - MLME message containing the received frame
1722
1723         Return  : None.
1724         ==========================================================================
1725  */
1726 VOID PeerSpectrumAction(
1727         IN PRTMP_ADAPTER pAd,
1728         IN MLME_QUEUE_ELEM *Elem)
1729 {
1730
1731         UCHAR   Action = Elem->Msg[LENGTH_802_11+1];
1732
1733         if (pAd->CommonCfg.bIEEE80211H != TRUE)
1734                 return;
1735
1736         switch(Action)
1737         {
1738                 case SPEC_MRQ:
1739                         // current rt2860 unable do such measure specified in Measurement Request.
1740                         // reject all measurement request.
1741                         PeerMeasureReqAction(pAd, Elem);
1742                         break;
1743
1744                 case SPEC_MRP:
1745                         PeerMeasureReportAction(pAd, Elem);
1746                         break;
1747
1748                 case SPEC_TPCRQ:
1749                         PeerTpcReqAction(pAd, Elem);
1750                         break;
1751
1752                 case SPEC_TPCRP:
1753                         PeerTpcRepAction(pAd, Elem);
1754                         break;
1755
1756                 case SPEC_CHANNEL_SWITCH:
1757 {
1758 #ifdef DOT11N_DRAFT3
1759                                 SEC_CHA_OFFSET_IE       Secondary;
1760                                 CHA_SWITCH_ANNOUNCE_IE  ChannelSwitch;
1761
1762                                 // 802.11h only has Channel Switch Announcement IE.
1763                                 RTMPMoveMemory(&ChannelSwitch, &Elem->Msg[LENGTH_802_11+4], sizeof (CHA_SWITCH_ANNOUNCE_IE));
1764
1765                                 // 802.11n D3.03 adds secondary channel offset element in the end.
1766                                 if (Elem->MsgLen ==  (LENGTH_802_11 + 2 + sizeof (CHA_SWITCH_ANNOUNCE_IE) + sizeof (SEC_CHA_OFFSET_IE)))
1767                                 {
1768                                         RTMPMoveMemory(&Secondary, &Elem->Msg[LENGTH_802_11+9], sizeof (SEC_CHA_OFFSET_IE));
1769                                 }
1770                                 else
1771                                 {
1772                                         Secondary.SecondaryChannelOffset = 0;
1773                                 }
1774
1775                                 if ((Elem->Msg[LENGTH_802_11+2] == IE_CHANNEL_SWITCH_ANNOUNCEMENT) && (Elem->Msg[LENGTH_802_11+3] == 3))
1776                                 {
1777                                         ChannelSwitchAction(pAd, Elem->Wcid, ChannelSwitch.NewChannel, Secondary.SecondaryChannelOffset);
1778                                 }
1779 #endif // DOT11N_DRAFT3 //
1780 }
1781                         PeerChSwAnnAction(pAd, Elem);
1782                         break;
1783         }
1784
1785         return;
1786 }
1787
1788 /*
1789         ==========================================================================
1790         Description:
1791
1792         Parametrs:
1793
1794         Return  : None.
1795         ==========================================================================
1796  */
1797 INT Set_MeasureReq_Proc(
1798         IN      PRTMP_ADAPTER   pAd,
1799         IN      PUCHAR                  arg)
1800 {
1801         UINT Aid = 1;
1802         UINT ArgIdx;
1803         PUCHAR thisChar;
1804
1805         MEASURE_REQ_MODE MeasureReqMode;
1806         UINT8 MeasureReqToken = RandomByte(pAd);
1807         UINT8 MeasureReqType = RM_BASIC;
1808         UINT8 MeasureCh = 1;
1809
1810         ArgIdx = 1;
1811         while ((thisChar = strsep((char **)&arg, "-")) != NULL)
1812         {
1813                 switch(ArgIdx)
1814                 {
1815                         case 1: // Aid.
1816                                 Aid = simple_strtol(thisChar, 0, 16);
1817                                 break;
1818
1819                         case 2: // Measurement Request Type.
1820                                 MeasureReqType = simple_strtol(thisChar, 0, 16);
1821                                 if (MeasureReqType > 3)
1822                                 {
1823                                         DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow MeasureReqType(%d)\n", __func__, MeasureReqType));
1824                                         return TRUE;
1825                                 }
1826                                 break;
1827
1828                         case 3: // Measurement channel.
1829                                 MeasureCh = simple_strtol(thisChar, 0, 16);
1830                                 break;
1831                 }
1832                 ArgIdx++;
1833         }
1834
1835         DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d, MeasureReqType=%d MeasureCh=%d\n", __func__, Aid, MeasureReqType, MeasureCh));
1836         if (!VALID_WCID(Aid))
1837         {
1838                 DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __func__, Aid));
1839                 return TRUE;
1840         }
1841
1842         MeasureReqMode.word = 0;
1843         MeasureReqMode.field.Enable = 1;
1844
1845         MeasureReqInsert(pAd, MeasureReqToken);
1846
1847         EnqueueMeasurementReq(pAd, pAd->MacTab.Content[Aid].Addr,
1848                 MeasureReqToken, MeasureReqMode.word, MeasureReqType, MeasureCh, 2000);
1849
1850         return TRUE;
1851 }
1852
1853 INT Set_TpcReq_Proc(
1854         IN      PRTMP_ADAPTER   pAd,
1855         IN      PUCHAR                  arg)
1856 {
1857         UINT Aid;
1858
1859         UINT8 TpcReqToken = RandomByte(pAd);
1860
1861         Aid = simple_strtol(arg, 0, 16);
1862
1863         DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d\n", __func__, Aid));
1864         if (!VALID_WCID(Aid))
1865         {
1866                 DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __func__, Aid));
1867                 return TRUE;
1868         }
1869
1870         TpcReqInsert(pAd, TpcReqToken);
1871
1872         EnqueueTPCReq(pAd, pAd->MacTab.Content[Aid].Addr, TpcReqToken);
1873
1874         return TRUE;
1875 }
1876