Merge commit 'v2.6.32' into reiserfs/kill-bkl
[firefly-linux-kernel-4.4.55.git] / drivers / staging / rtl8192su / ieee80211 / dot11d.c
1 //-----------------------------------------------------------------------------
2 //      File:
3 //              Dot11d.c
4 //
5 //      Description:
6 //              Implement 802.11d.
7 //
8 //-----------------------------------------------------------------------------
9
10 #include "dot11d.h"
11
12 void
13 Dot11d_Init(struct ieee80211_device *ieee)
14 {
15         PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee);
16
17         pDot11dInfo->bEnabled = 0;
18
19         pDot11dInfo->State = DOT11D_STATE_NONE;
20         pDot11dInfo->CountryIeLen = 0;
21         memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
22         memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
23         RESET_CIE_WATCHDOG(ieee);
24
25         printk("Dot11d_Init()\n");
26 }
27
28 //
29 //      Description:
30 //              Reset to the state as we are just entering a regulatory domain.
31 //
32 void
33 Dot11d_Reset(struct ieee80211_device *ieee)
34 {
35         u32 i;
36         PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee);
37
38         // Clear old channel map
39         memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
40         memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
41         // Set new channel map
42         for (i=1; i<=11; i++) {
43                 (pDot11dInfo->channel_map)[i] = 1;
44         }
45         for (i=12; i<=14; i++) {
46                 (pDot11dInfo->channel_map)[i] = 2;
47         }
48
49         pDot11dInfo->State = DOT11D_STATE_NONE;
50         pDot11dInfo->CountryIeLen = 0;
51         RESET_CIE_WATCHDOG(ieee);
52
53         //printk("Dot11d_Reset()\n");
54 }
55
56 //
57 //      Description:
58 //              Update country IE from Beacon or Probe Resopnse
59 //              and configure PHY for operation in the regulatory domain.
60 //
61 //      TODO:
62 //              Configure Tx power.
63 //
64 //      Assumption:
65 //              1. IS_DOT11D_ENABLE() is TRUE.
66 //              2. Input IE is an valid one.
67 //
68 void
69 Dot11d_UpdateCountryIe(
70         struct ieee80211_device *dev,
71         u8 *            pTaddr,
72         u16     CoutryIeLen,
73         u8 * pCoutryIe
74         )
75 {
76         PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
77         u8 i, j, NumTriples, MaxChnlNum;
78         PCHNL_TXPOWER_TRIPLE pTriple;
79
80         memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
81         memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
82         MaxChnlNum = 0;
83         NumTriples = (CoutryIeLen - 3) / 3; // skip 3-byte country string.
84         pTriple = (PCHNL_TXPOWER_TRIPLE)(pCoutryIe + 3);
85         for(i = 0; i < NumTriples; i++)
86         {
87                 if(MaxChnlNum >= pTriple->FirstChnl)
88                 { // It is not in a monotonically increasing order, so stop processing.
89                         printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n");
90                         return;
91                 }
92                 if(MAX_CHANNEL_NUMBER < (pTriple->FirstChnl + pTriple->NumChnls))
93                 { // It is not a valid set of channel id, so stop processing.
94                         printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n");
95                         return;
96                 }
97
98                 for(j = 0 ; j < pTriple->NumChnls; j++)
99                 {
100                         pDot11dInfo->channel_map[pTriple->FirstChnl + j] = 1;
101                         pDot11dInfo->MaxTxPwrDbmList[pTriple->FirstChnl + j] = pTriple->MaxTxPowerInDbm;
102                         MaxChnlNum = pTriple->FirstChnl + j;
103                 }
104
105                 pTriple = (PCHNL_TXPOWER_TRIPLE)((u8*)pTriple + 3);
106         }
107 #if 1
108         //printk("Dot11d_UpdateCountryIe(): Channel List:\n");
109         printk("Channel List:");
110         for(i=1; i<= MAX_CHANNEL_NUMBER; i++)
111                 if(pDot11dInfo->channel_map[i] > 0)
112                         printk(" %d", i);
113         printk("\n");
114 #endif
115
116         UPDATE_CIE_SRC(dev, pTaddr);
117
118         pDot11dInfo->CountryIeLen = CoutryIeLen;
119         memcpy(pDot11dInfo->CountryIeBuf, pCoutryIe,CoutryIeLen);
120         pDot11dInfo->State = DOT11D_STATE_LEARNED;
121 }
122
123
124 u8
125 DOT11D_GetMaxTxPwrInDbm(
126         struct ieee80211_device *dev,
127         u8 Channel
128         )
129 {
130         PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
131         u8 MaxTxPwrInDbm = 255;
132
133         if(MAX_CHANNEL_NUMBER < Channel)
134         {
135                 printk("DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n");
136                 return MaxTxPwrInDbm;
137         }
138         if(pDot11dInfo->channel_map[Channel])
139         {
140                 MaxTxPwrInDbm = pDot11dInfo->MaxTxPwrDbmList[Channel];
141         }
142
143         return MaxTxPwrInDbm;
144 }
145
146
147 void
148 DOT11D_ScanComplete(
149         struct ieee80211_device * dev
150         )
151 {
152         PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
153
154         switch(pDot11dInfo->State)
155         {
156         case DOT11D_STATE_LEARNED:
157                 pDot11dInfo->State = DOT11D_STATE_DONE;
158                 break;
159
160         case DOT11D_STATE_DONE:
161                 if( GET_CIE_WATCHDOG(dev) == 0 )
162                 { // Reset country IE if previous one is gone.
163                         Dot11d_Reset(dev);
164                 }
165                 break;
166         case DOT11D_STATE_NONE:
167                 break;
168         }
169 }
170
171 int IsLegalChannel(
172         struct ieee80211_device * dev,
173         u8 channel
174 )
175 {
176         PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
177
178         if(MAX_CHANNEL_NUMBER < channel)
179         {
180                 printk("IsLegalChannel(): Invalid Channel\n");
181                 return 0;
182         }
183         if(pDot11dInfo->channel_map[channel] > 0)
184                 return 1;
185         return 0;
186 }
187
188 int ToLegalChannel(
189         struct ieee80211_device * dev,
190         u8 channel
191 )
192 {
193         PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
194         u8 default_chn = 0;
195         u32 i = 0;
196
197         for (i=1; i<= MAX_CHANNEL_NUMBER; i++)
198         {
199                 if(pDot11dInfo->channel_map[i] > 0)
200                 {
201                         default_chn = i;
202                         break;
203                 }
204         }
205
206         if(MAX_CHANNEL_NUMBER < channel)
207         {
208                 printk("IsLegalChannel(): Invalid Channel\n");
209                 return default_chn;
210         }
211
212         if(pDot11dInfo->channel_map[channel] > 0)
213                 return channel;
214
215         return default_chn;
216 }