Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
[sfrench/cifs-2.6.git] / 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 #ifdef WDS_SUPPORT
1064         if (!((pRA[0] & 0xff) == 0xff)) // is pRA a broadcase address.
1065         {
1066                 INT i;
1067                 // info neighbor APs that Radar signal found throgh WDS link.
1068                 for (i = 0; i < MAX_WDS_ENTRY; i++)
1069                 {
1070                         if (ValidWdsEntry(pAd, i))
1071                         {
1072                                 PUCHAR pDA = pAd->WdsTab.WdsEntry[i].PeerWdsAddr;
1073
1074                                 // DA equal to SA. have no necessary orignal AP which found Radar signal.
1075                                 if (MAC_ADDR_EQUAL(pTA, pDA))
1076                                         continue;
1077
1078                                 // send Channel Switch Action frame to info Neighbro APs.
1079                                 EnqueueChSwAnn(pAd, pDA, ChSwMode, Channel);
1080                         }
1081                 }
1082         }
1083 #endif // WDS_SUPPORT //
1084 }
1085
1086 static VOID StartDFSProcedure(
1087         IN PRTMP_ADAPTER pAd,
1088         IN UCHAR Channel,
1089         IN UINT8 ChSwMode)
1090 {
1091         // start DFS procedure
1092         pAd->CommonCfg.Channel = Channel;
1093 #ifdef DOT11_N_SUPPORT
1094         N_ChannelCheck(pAd);
1095 #endif // DOT11_N_SUPPORT //
1096         pAd->CommonCfg.RadarDetect.RDMode = RD_SWITCHING_MODE;
1097         pAd->CommonCfg.RadarDetect.CSCount = 0;
1098 }
1099
1100 /*
1101         ==========================================================================
1102         Description:
1103                 Channel Switch Announcement action frame sanity check.
1104
1105         Parametrs:
1106                 1. MLME message containing the received frame
1107                 2. message length.
1108                 3. Channel switch announcement infomation buffer.
1109
1110
1111         Return  : None.
1112         ==========================================================================
1113  */
1114
1115 /*
1116   Channel Switch Announcement IE.
1117   +----+-----+-----------+------------+-----------+
1118   | ID | Len |Ch Sw Mode | New Ch Num | Ch Sw Cnt |
1119   +----+-----+-----------+------------+-----------+
1120     1    1        1           1            1
1121 */
1122 static BOOLEAN PeerChSwAnnSanity(
1123         IN PRTMP_ADAPTER pAd,
1124         IN VOID *pMsg,
1125         IN ULONG MsgLen,
1126         OUT PCH_SW_ANN_INFO pChSwAnnInfo)
1127 {
1128         PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
1129         PUCHAR pFramePtr = Fr->Octet;
1130         BOOLEAN result = FALSE;
1131         PEID_STRUCT eid_ptr;
1132
1133         // skip 802.11 header.
1134         MsgLen -= sizeof(HEADER_802_11);
1135
1136         // skip category and action code.
1137         pFramePtr += 2;
1138         MsgLen -= 2;
1139
1140         if (pChSwAnnInfo == NULL)
1141                 return result;
1142
1143         eid_ptr = (PEID_STRUCT)pFramePtr;
1144         while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
1145         {
1146                 switch(eid_ptr->Eid)
1147                 {
1148                         case IE_CHANNEL_SWITCH_ANNOUNCEMENT:
1149                                 NdisMoveMemory(&pChSwAnnInfo->ChSwMode, eid_ptr->Octet, 1);
1150                                 NdisMoveMemory(&pChSwAnnInfo->Channel, eid_ptr->Octet + 1, 1);
1151                                 NdisMoveMemory(&pChSwAnnInfo->ChSwCnt, eid_ptr->Octet + 2, 1);
1152
1153                                 result = TRUE;
1154                 break;
1155
1156                         default:
1157                                 break;
1158                 }
1159                 eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
1160         }
1161
1162         return result;
1163 }
1164
1165 /*
1166         ==========================================================================
1167         Description:
1168                 Measurement request action frame sanity check.
1169
1170         Parametrs:
1171                 1. MLME message containing the received frame
1172                 2. message length.
1173                 3. Measurement request infomation buffer.
1174
1175         Return  : None.
1176         ==========================================================================
1177  */
1178 static BOOLEAN PeerMeasureReqSanity(
1179         IN PRTMP_ADAPTER pAd,
1180         IN VOID *pMsg,
1181         IN ULONG MsgLen,
1182         OUT PUINT8 pDialogToken,
1183         OUT PMEASURE_REQ_INFO pMeasureReqInfo)
1184 {
1185         PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
1186         PUCHAR pFramePtr = Fr->Octet;
1187         BOOLEAN result = FALSE;
1188         PEID_STRUCT eid_ptr;
1189         PUCHAR ptr;
1190         UINT64 MeasureStartTime;
1191         UINT16 MeasureDuration;
1192
1193         // skip 802.11 header.
1194         MsgLen -= sizeof(HEADER_802_11);
1195
1196         // skip category and action code.
1197         pFramePtr += 2;
1198         MsgLen -= 2;
1199
1200         if (pMeasureReqInfo == NULL)
1201                 return result;
1202
1203         NdisMoveMemory(pDialogToken, pFramePtr, 1);
1204         pFramePtr += 1;
1205         MsgLen -= 1;
1206
1207         eid_ptr = (PEID_STRUCT)pFramePtr;
1208         while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
1209         {
1210                 switch(eid_ptr->Eid)
1211                 {
1212                         case IE_MEASUREMENT_REQUEST:
1213                                 NdisMoveMemory(&pMeasureReqInfo->Token, eid_ptr->Octet, 1);
1214                                 NdisMoveMemory(&pMeasureReqInfo->ReqMode.word, eid_ptr->Octet + 1, 1);
1215                                 NdisMoveMemory(&pMeasureReqInfo->ReqType, eid_ptr->Octet + 2, 1);
1216                                 ptr = eid_ptr->Octet + 3;
1217                                 NdisMoveMemory(&pMeasureReqInfo->MeasureReq.ChNum, ptr, 1);
1218                                 NdisMoveMemory(&MeasureStartTime, ptr + 1, 8);
1219                                 pMeasureReqInfo->MeasureReq.MeasureStartTime = SWAP64(MeasureStartTime);
1220                                 NdisMoveMemory(&MeasureDuration, ptr + 9, 2);
1221                                 pMeasureReqInfo->MeasureReq.MeasureDuration = SWAP16(MeasureDuration);
1222
1223                                 result = TRUE;
1224                                 break;
1225
1226                         default:
1227                                 break;
1228                 }
1229                 eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
1230         }
1231
1232         return result;
1233 }
1234
1235 /*
1236         ==========================================================================
1237         Description:
1238                 Measurement report action frame sanity check.
1239
1240         Parametrs:
1241                 1. MLME message containing the received frame
1242                 2. message length.
1243                 3. Measurement report infomation buffer.
1244                 4. basic report infomation buffer.
1245
1246         Return  : None.
1247         ==========================================================================
1248  */
1249
1250 /*
1251   Measurement Report IE.
1252   +----+-----+-------+-------------+--------------+----------------+
1253   | ID | Len | Token | Report Mode | Measure Type | Measure Report |
1254   +----+-----+-------+-------------+--------------+----------------+
1255     1     1      1          1             1            variable
1256
1257   Basic Report.
1258   +--------+------------+----------+-----+
1259   | Ch Num | Start Time | Duration | Map |
1260   +--------+------------+----------+-----+
1261       1          8           2        1
1262
1263   Map Field Bit Format.
1264   +-----+---------------+---------------------+-------+------------+----------+
1265   | Bss | OFDM Preamble | Unidentified signal | Radar | Unmeasured | Reserved |
1266   +-----+---------------+---------------------+-------+------------+----------+
1267      0          1                  2              3         4          5-7
1268 */
1269 static BOOLEAN PeerMeasureReportSanity(
1270         IN PRTMP_ADAPTER pAd,
1271         IN VOID *pMsg,
1272         IN ULONG MsgLen,
1273         OUT PUINT8 pDialogToken,
1274         OUT PMEASURE_REPORT_INFO pMeasureReportInfo,
1275         OUT PUINT8 pReportBuf)
1276 {
1277         PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
1278         PUCHAR pFramePtr = Fr->Octet;
1279         BOOLEAN result = FALSE;
1280         PEID_STRUCT eid_ptr;
1281         PUCHAR ptr;
1282
1283         // skip 802.11 header.
1284         MsgLen -= sizeof(HEADER_802_11);
1285
1286         // skip category and action code.
1287         pFramePtr += 2;
1288         MsgLen -= 2;
1289
1290         if (pMeasureReportInfo == NULL)
1291                 return result;
1292
1293         NdisMoveMemory(pDialogToken, pFramePtr, 1);
1294         pFramePtr += 1;
1295         MsgLen -= 1;
1296
1297         eid_ptr = (PEID_STRUCT)pFramePtr;
1298         while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
1299         {
1300                 switch(eid_ptr->Eid)
1301                 {
1302                         case IE_MEASUREMENT_REPORT:
1303                                 NdisMoveMemory(&pMeasureReportInfo->Token, eid_ptr->Octet, 1);
1304                                 NdisMoveMemory(&pMeasureReportInfo->ReportMode, eid_ptr->Octet + 1, 1);
1305                                 NdisMoveMemory(&pMeasureReportInfo->ReportType, eid_ptr->Octet + 2, 1);
1306                                 if (pMeasureReportInfo->ReportType == RM_BASIC)
1307                                 {
1308                                         PMEASURE_BASIC_REPORT pReport = (PMEASURE_BASIC_REPORT)pReportBuf;
1309                                         ptr = eid_ptr->Octet + 3;
1310                                         NdisMoveMemory(&pReport->ChNum, ptr, 1);
1311                                         NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8);
1312                                         NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2);
1313                                         NdisMoveMemory(&pReport->Map, ptr + 11, 1);
1314
1315                                 }
1316                                 else if (pMeasureReportInfo->ReportType == RM_CCA)
1317                                 {
1318                                         PMEASURE_CCA_REPORT pReport = (PMEASURE_CCA_REPORT)pReportBuf;
1319                                         ptr = eid_ptr->Octet + 3;
1320                                         NdisMoveMemory(&pReport->ChNum, ptr, 1);
1321                                         NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8);
1322                                         NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2);
1323                                         NdisMoveMemory(&pReport->CCA_Busy_Fraction, ptr + 11, 1);
1324
1325                                 }
1326                                 else if (pMeasureReportInfo->ReportType == RM_RPI_HISTOGRAM)
1327                                 {
1328                                         PMEASURE_RPI_REPORT pReport = (PMEASURE_RPI_REPORT)pReportBuf;
1329                                         ptr = eid_ptr->Octet + 3;
1330                                         NdisMoveMemory(&pReport->ChNum, ptr, 1);
1331                                         NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8);
1332                                         NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2);
1333                                         NdisMoveMemory(&pReport->RPI_Density, ptr + 11, 8);
1334                                 }
1335                                 result = TRUE;
1336                 break;
1337
1338                         default:
1339                                 break;
1340                 }
1341                 eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
1342         }
1343
1344         return result;
1345 }
1346
1347 /*
1348         ==========================================================================
1349         Description:
1350                 TPC Request action frame sanity check.
1351
1352         Parametrs:
1353                 1. MLME message containing the received frame
1354                 2. message length.
1355                 3. Dialog Token.
1356
1357         Return  : None.
1358         ==========================================================================
1359  */
1360 static BOOLEAN PeerTpcReqSanity(
1361         IN PRTMP_ADAPTER pAd,
1362         IN VOID *pMsg,
1363         IN ULONG MsgLen,
1364         OUT PUINT8 pDialogToken)
1365 {
1366         PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
1367         PUCHAR pFramePtr = Fr->Octet;
1368         BOOLEAN result = FALSE;
1369         PEID_STRUCT eid_ptr;
1370
1371         MsgLen -= sizeof(HEADER_802_11);
1372
1373         // skip category and action code.
1374         pFramePtr += 2;
1375         MsgLen -= 2;
1376
1377         if (pDialogToken == NULL)
1378                 return result;
1379
1380         NdisMoveMemory(pDialogToken, pFramePtr, 1);
1381         pFramePtr += 1;
1382         MsgLen -= 1;
1383
1384         eid_ptr = (PEID_STRUCT)pFramePtr;
1385         while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
1386         {
1387                 switch(eid_ptr->Eid)
1388                 {
1389                         case IE_TPC_REQUEST:
1390                                 result = TRUE;
1391                 break;
1392
1393                         default:
1394                                 break;
1395                 }
1396                 eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
1397         }
1398
1399         return result;
1400 }
1401
1402 /*
1403         ==========================================================================
1404         Description:
1405                 TPC Report action frame sanity check.
1406
1407         Parametrs:
1408                 1. MLME message containing the received frame
1409                 2. message length.
1410                 3. Dialog Token.
1411                 4. TPC Report IE.
1412
1413         Return  : None.
1414         ==========================================================================
1415  */
1416 static BOOLEAN PeerTpcRepSanity(
1417         IN PRTMP_ADAPTER pAd,
1418         IN VOID *pMsg,
1419         IN ULONG MsgLen,
1420         OUT PUINT8 pDialogToken,
1421         OUT PTPC_REPORT_INFO pTpcRepInfo)
1422 {
1423         PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
1424         PUCHAR pFramePtr = Fr->Octet;
1425         BOOLEAN result = FALSE;
1426         PEID_STRUCT eid_ptr;
1427
1428         MsgLen -= sizeof(HEADER_802_11);
1429
1430         // skip category and action code.
1431         pFramePtr += 2;
1432         MsgLen -= 2;
1433
1434         if (pDialogToken == NULL)
1435                 return result;
1436
1437         NdisMoveMemory(pDialogToken, pFramePtr, 1);
1438         pFramePtr += 1;
1439         MsgLen -= 1;
1440
1441         eid_ptr = (PEID_STRUCT)pFramePtr;
1442         while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
1443         {
1444                 switch(eid_ptr->Eid)
1445                 {
1446                         case IE_TPC_REPORT:
1447                                 NdisMoveMemory(&pTpcRepInfo->TxPwr, eid_ptr->Octet, 1);
1448                                 NdisMoveMemory(&pTpcRepInfo->LinkMargin, eid_ptr->Octet + 1, 1);
1449                                 result = TRUE;
1450                 break;
1451
1452                         default:
1453                                 break;
1454                 }
1455                 eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
1456         }
1457
1458         return result;
1459 }
1460
1461 /*
1462         ==========================================================================
1463         Description:
1464                 Channel Switch Announcement action frame handler.
1465
1466         Parametrs:
1467                 Elme - MLME message containing the received frame
1468
1469         Return  : None.
1470         ==========================================================================
1471  */
1472 static VOID PeerChSwAnnAction(
1473         IN PRTMP_ADAPTER pAd,
1474         IN MLME_QUEUE_ELEM *Elem)
1475 {
1476         CH_SW_ANN_INFO ChSwAnnInfo;
1477         PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg;
1478 #ifdef CONFIG_STA_SUPPORT
1479         UCHAR index = 0, Channel = 0, NewChannel = 0;
1480         ULONG Bssidx = 0;
1481 #endif // CONFIG_STA_SUPPORT //
1482
1483         NdisZeroMemory(&ChSwAnnInfo, sizeof(CH_SW_ANN_INFO));
1484         if (! PeerChSwAnnSanity(pAd, Elem->Msg, Elem->MsgLen, &ChSwAnnInfo))
1485         {
1486                 DBGPRINT(RT_DEBUG_TRACE, ("Invalid Channel Switch Action Frame.\n"));
1487                 return;
1488         }
1489
1490
1491 #ifdef CONFIG_STA_SUPPORT
1492         if (pAd->OpMode == OPMODE_STA)
1493         {
1494                 Bssidx = BssTableSearch(&pAd->ScanTab, pFr->Hdr.Addr3, pAd->CommonCfg.Channel);
1495                 if (Bssidx == BSS_NOT_FOUND)
1496                 {
1497                         DBGPRINT(RT_DEBUG_TRACE, ("PeerChSwAnnAction - Bssidx is not found\n"));
1498                         return;
1499                 }
1500
1501                 DBGPRINT(RT_DEBUG_TRACE, ("\n****Bssidx is %d, Channel = %d\n", index, pAd->ScanTab.BssEntry[Bssidx].Channel));
1502                 hex_dump("SSID",pAd->ScanTab.BssEntry[Bssidx].Bssid ,6);
1503
1504                 Channel = pAd->CommonCfg.Channel;
1505                 NewChannel = ChSwAnnInfo.Channel;
1506
1507                 if ((pAd->CommonCfg.bIEEE80211H == 1) && (NewChannel != 0) && (Channel != NewChannel))
1508                 {
1509                         // Switching to channel 1 can prevent from rescanning the current channel immediately (by auto reconnection).
1510                         // In addition, clear the MLME queue and the scan table to discard the RX packets and previous scanning results.
1511                         AsicSwitchChannel(pAd, 1, FALSE);
1512                         AsicLockChannel(pAd, 1);
1513                     LinkDown(pAd, FALSE);
1514                         MlmeQueueInit(&pAd->Mlme.Queue);
1515                         BssTableInit(&pAd->ScanTab);
1516                     RTMPusecDelay(1000000);             // use delay to prevent STA do reassoc
1517
1518                         // channel sanity check
1519                         for (index = 0 ; index < pAd->ChannelListNum; index++)
1520                         {
1521                                 if (pAd->ChannelList[index].Channel == NewChannel)
1522                                 {
1523                                         pAd->ScanTab.BssEntry[Bssidx].Channel = NewChannel;
1524                                         pAd->CommonCfg.Channel = NewChannel;
1525                                         AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
1526                                         AsicLockChannel(pAd, pAd->CommonCfg.Channel);
1527                                         DBGPRINT(RT_DEBUG_TRACE, ("&&&&&&&&&&&&&&&&PeerChSwAnnAction - STA receive channel switch announcement IE (New Channel =%d)\n", NewChannel));
1528                                         break;
1529                                 }
1530                         }
1531
1532                         if (index >= pAd->ChannelListNum)
1533                         {
1534                                 DBGPRINT_ERR(("&&&&&&&&&&&&&&&&&&&&&&&&&&PeerChSwAnnAction(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum));
1535                         }
1536                 }
1537         }
1538 #endif // CONFIG_STA_SUPPORT //
1539
1540         return;
1541 }
1542
1543
1544 /*
1545         ==========================================================================
1546         Description:
1547                 Measurement Request action frame handler.
1548
1549         Parametrs:
1550                 Elme - MLME message containing the received frame
1551
1552         Return  : None.
1553         ==========================================================================
1554  */
1555 static VOID PeerMeasureReqAction(
1556         IN PRTMP_ADAPTER pAd,
1557         IN MLME_QUEUE_ELEM *Elem)
1558 {
1559         PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg;
1560         UINT8 DialogToken;
1561         MEASURE_REQ_INFO MeasureReqInfo;
1562         MEASURE_REPORT_MODE ReportMode;
1563
1564         if(PeerMeasureReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReqInfo))
1565         {
1566                 ReportMode.word = 0;
1567                 ReportMode.field.Incapable = 1;
1568                 EnqueueMeasurementRep(pAd, pFr->Hdr.Addr2, DialogToken, MeasureReqInfo.Token, ReportMode.word, MeasureReqInfo.ReqType, 0, NULL);
1569         }
1570
1571         return;
1572 }
1573
1574 /*
1575         ==========================================================================
1576         Description:
1577                 Measurement Report action frame handler.
1578
1579         Parametrs:
1580                 Elme - MLME message containing the received frame
1581
1582         Return  : None.
1583         ==========================================================================
1584  */
1585 static VOID PeerMeasureReportAction(
1586         IN PRTMP_ADAPTER pAd,
1587         IN MLME_QUEUE_ELEM *Elem)
1588 {
1589         MEASURE_REPORT_INFO MeasureReportInfo;
1590         PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg;
1591         UINT8 DialogToken;
1592         PUINT8 pMeasureReportInfo;
1593
1594 //      if (pAd->CommonCfg.bIEEE80211H != TRUE)
1595 //              return;
1596
1597         if ((pMeasureReportInfo = kmalloc(sizeof(MEASURE_RPI_REPORT), GFP_ATOMIC)) == NULL)
1598         {
1599                 DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%d).\n", __func__, sizeof(MEASURE_RPI_REPORT)));
1600                 return;
1601         }
1602
1603         NdisZeroMemory(&MeasureReportInfo, sizeof(MEASURE_REPORT_INFO));
1604         NdisZeroMemory(pMeasureReportInfo, sizeof(MEASURE_RPI_REPORT));
1605         if (PeerMeasureReportSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReportInfo, pMeasureReportInfo))
1606         {
1607                 do {
1608                         PMEASURE_REQ_ENTRY pEntry = NULL;
1609
1610                         // Not a autonomous measure report.
1611                         // check the dialog token field. drop it if the dialog token doesn't match.
1612                         if ((DialogToken != 0)
1613                                 && ((pEntry = MeasureReqLookUp(pAd, DialogToken)) == NULL))
1614                                 break;
1615
1616                         if (pEntry != NULL)
1617                                 MeasureReqDelete(pAd, pEntry->DialogToken);
1618
1619                         if (MeasureReportInfo.ReportType == RM_BASIC)
1620                         {
1621                                 PMEASURE_BASIC_REPORT pBasicReport = (PMEASURE_BASIC_REPORT)pMeasureReportInfo;
1622                                 if ((pBasicReport->Map.field.Radar)
1623                                         && (DfsRequirementCheck(pAd, pBasicReport->ChNum) == TRUE))
1624                                 {
1625                                         NotifyChSwAnnToPeerAPs(pAd, pFr->Hdr.Addr1, pFr->Hdr.Addr2, 1, pBasicReport->ChNum);
1626                                         StartDFSProcedure(pAd, pBasicReport->ChNum, 1);
1627                                 }
1628                         }
1629                 } while (FALSE);
1630         }
1631         else
1632                 DBGPRINT(RT_DEBUG_TRACE, ("Invalid Measurement Report Frame.\n"));
1633
1634         kfree(pMeasureReportInfo);
1635
1636         return;
1637 }
1638
1639 /*
1640         ==========================================================================
1641         Description:
1642                 TPC Request action frame handler.
1643
1644         Parametrs:
1645                 Elme - MLME message containing the received frame
1646
1647         Return  : None.
1648         ==========================================================================
1649  */
1650 static VOID PeerTpcReqAction(
1651         IN PRTMP_ADAPTER pAd,
1652         IN MLME_QUEUE_ELEM *Elem)
1653 {
1654         PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg;
1655         PUCHAR pFramePtr = pFr->Octet;
1656         UINT8 DialogToken;
1657         UINT8 TxPwr = GetCurTxPwr(pAd, Elem->Wcid);
1658         UINT8 LinkMargin = 0;
1659         CHAR RealRssi;
1660
1661         // link margin: Ratio of the received signal power to the minimum desired by the station (STA). The
1662         //                              STA may incorporate rate information and channel conditions, including interference, into its computation
1663         //                              of link margin.
1664
1665         RealRssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0),
1666                                                                 ConvertToRssi(pAd, Elem->Rssi1, RSSI_1),
1667                                                                 ConvertToRssi(pAd, Elem->Rssi2, RSSI_2));
1668
1669         // skip Category and action code.
1670         pFramePtr += 2;
1671
1672         // Dialog token.
1673         NdisMoveMemory(&DialogToken, pFramePtr, 1);
1674
1675         LinkMargin = (RealRssi / MIN_RCV_PWR);
1676         if (PeerTpcReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken))
1677                 EnqueueTPCRep(pAd, pFr->Hdr.Addr2, DialogToken, TxPwr, LinkMargin);
1678
1679         return;
1680 }
1681
1682 /*
1683         ==========================================================================
1684         Description:
1685                 TPC Report action frame handler.
1686
1687         Parametrs:
1688                 Elme - MLME message containing the received frame
1689
1690         Return  : None.
1691         ==========================================================================
1692  */
1693 static VOID PeerTpcRepAction(
1694         IN PRTMP_ADAPTER pAd,
1695         IN MLME_QUEUE_ELEM *Elem)
1696 {
1697         UINT8 DialogToken;
1698         TPC_REPORT_INFO TpcRepInfo;
1699         PTPC_REQ_ENTRY pEntry = NULL;
1700
1701         NdisZeroMemory(&TpcRepInfo, sizeof(TPC_REPORT_INFO));
1702         if (PeerTpcRepSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &TpcRepInfo))
1703         {
1704                 if ((pEntry = TpcReqLookUp(pAd, DialogToken)) != NULL)
1705                 {
1706                         TpcReqDelete(pAd, pEntry->DialogToken);
1707                         DBGPRINT(RT_DEBUG_TRACE, ("%s: DialogToken=%x, TxPwr=%d, LinkMargin=%d\n",
1708                                 __func__, DialogToken, TpcRepInfo.TxPwr, TpcRepInfo.LinkMargin));
1709                 }
1710         }
1711
1712         return;
1713 }
1714
1715 /*
1716         ==========================================================================
1717         Description:
1718                 Spectrun action frames Handler such as channel switch annoucement,
1719                 measurement report, measurement request actions frames.
1720
1721         Parametrs:
1722                 Elme - MLME message containing the received frame
1723
1724         Return  : None.
1725         ==========================================================================
1726  */
1727 VOID PeerSpectrumAction(
1728         IN PRTMP_ADAPTER pAd,
1729         IN MLME_QUEUE_ELEM *Elem)
1730 {
1731
1732         UCHAR   Action = Elem->Msg[LENGTH_802_11+1];
1733
1734         if (pAd->CommonCfg.bIEEE80211H != TRUE)
1735                 return;
1736
1737         switch(Action)
1738         {
1739                 case SPEC_MRQ:
1740                         // current rt2860 unable do such measure specified in Measurement Request.
1741                         // reject all measurement request.
1742                         PeerMeasureReqAction(pAd, Elem);
1743                         break;
1744
1745                 case SPEC_MRP:
1746                         PeerMeasureReportAction(pAd, Elem);
1747                         break;
1748
1749                 case SPEC_TPCRQ:
1750                         PeerTpcReqAction(pAd, Elem);
1751                         break;
1752
1753                 case SPEC_TPCRP:
1754                         PeerTpcRepAction(pAd, Elem);
1755                         break;
1756
1757                 case SPEC_CHANNEL_SWITCH:
1758 {
1759 #ifdef DOT11N_DRAFT3
1760                                 SEC_CHA_OFFSET_IE       Secondary;
1761                                 CHA_SWITCH_ANNOUNCE_IE  ChannelSwitch;
1762
1763                                 // 802.11h only has Channel Switch Announcement IE.
1764                                 RTMPMoveMemory(&ChannelSwitch, &Elem->Msg[LENGTH_802_11+4], sizeof (CHA_SWITCH_ANNOUNCE_IE));
1765
1766                                 // 802.11n D3.03 adds secondary channel offset element in the end.
1767                                 if (Elem->MsgLen ==  (LENGTH_802_11 + 2 + sizeof (CHA_SWITCH_ANNOUNCE_IE) + sizeof (SEC_CHA_OFFSET_IE)))
1768                                 {
1769                                         RTMPMoveMemory(&Secondary, &Elem->Msg[LENGTH_802_11+9], sizeof (SEC_CHA_OFFSET_IE));
1770                                 }
1771                                 else
1772                                 {
1773                                         Secondary.SecondaryChannelOffset = 0;
1774                                 }
1775
1776                                 if ((Elem->Msg[LENGTH_802_11+2] == IE_CHANNEL_SWITCH_ANNOUNCEMENT) && (Elem->Msg[LENGTH_802_11+3] == 3))
1777                                 {
1778                                         ChannelSwitchAction(pAd, Elem->Wcid, ChannelSwitch.NewChannel, Secondary.SecondaryChannelOffset);
1779                                 }
1780 #endif // DOT11N_DRAFT3 //
1781 }
1782                         PeerChSwAnnAction(pAd, Elem);
1783                         break;
1784         }
1785
1786         return;
1787 }
1788
1789 /*
1790         ==========================================================================
1791         Description:
1792
1793         Parametrs:
1794
1795         Return  : None.
1796         ==========================================================================
1797  */
1798 INT Set_MeasureReq_Proc(
1799         IN      PRTMP_ADAPTER   pAd,
1800         IN      PUCHAR                  arg)
1801 {
1802         UINT Aid = 1;
1803         UINT ArgIdx;
1804         PUCHAR thisChar;
1805
1806         MEASURE_REQ_MODE MeasureReqMode;
1807         UINT8 MeasureReqToken = RandomByte(pAd);
1808         UINT8 MeasureReqType = RM_BASIC;
1809         UINT8 MeasureCh = 1;
1810
1811         ArgIdx = 1;
1812         while ((thisChar = strsep((char **)&arg, "-")) != NULL)
1813         {
1814                 switch(ArgIdx)
1815                 {
1816                         case 1: // Aid.
1817                                 Aid = simple_strtol(thisChar, 0, 16);
1818                                 break;
1819
1820                         case 2: // Measurement Request Type.
1821                                 MeasureReqType = simple_strtol(thisChar, 0, 16);
1822                                 if (MeasureReqType > 3)
1823                                 {
1824                                         DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow MeasureReqType(%d)\n", __func__, MeasureReqType));
1825                                         return TRUE;
1826                                 }
1827                                 break;
1828
1829                         case 3: // Measurement channel.
1830                                 MeasureCh = simple_strtol(thisChar, 0, 16);
1831                                 break;
1832                 }
1833                 ArgIdx++;
1834         }
1835
1836         DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d, MeasureReqType=%d MeasureCh=%d\n", __func__, Aid, MeasureReqType, MeasureCh));
1837         if (!VALID_WCID(Aid))
1838         {
1839                 DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __func__, Aid));
1840                 return TRUE;
1841         }
1842
1843         MeasureReqMode.word = 0;
1844         MeasureReqMode.field.Enable = 1;
1845
1846         MeasureReqInsert(pAd, MeasureReqToken);
1847
1848         EnqueueMeasurementReq(pAd, pAd->MacTab.Content[Aid].Addr,
1849                 MeasureReqToken, MeasureReqMode.word, MeasureReqType, MeasureCh, 2000);
1850
1851         return TRUE;
1852 }
1853
1854 INT Set_TpcReq_Proc(
1855         IN      PRTMP_ADAPTER   pAd,
1856         IN      PUCHAR                  arg)
1857 {
1858         UINT Aid;
1859
1860         UINT8 TpcReqToken = RandomByte(pAd);
1861
1862         Aid = simple_strtol(arg, 0, 16);
1863
1864         DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d\n", __func__, Aid));
1865         if (!VALID_WCID(Aid))
1866         {
1867                 DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __func__, Aid));
1868                 return TRUE;
1869         }
1870
1871         TpcReqInsert(pAd, TpcReqToken);
1872
1873         EnqueueTPCReq(pAd, pAd->MacTab.Content[Aid].Addr, TpcReqToken);
1874
1875         return TRUE;
1876 }
1877