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