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