1 #ifdef ENABLE_DOT11D
2 //-----------------------------------------------------------------------------
3 //	File:
4 //		Dot11d.c
5 //
6 //	Description:
7 //		Implement 802.11d.
8 //
9 //-----------------------------------------------------------------------------
10 
11 #include "dot11d.h"
12 
13 void
14 Dot11d_Init(struct ieee80211_device *ieee)
15 {
16 	PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee);
17 
18 	pDot11dInfo->bEnabled = 0;
19 
20 	pDot11dInfo->State = DOT11D_STATE_NONE;
21 	pDot11dInfo->CountryIeLen = 0;
22 	memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
23 	memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
24 	RESET_CIE_WATCHDOG(ieee);
25 
26 	printk("Dot11d_Init()\n");
27 }
28 
29 //
30 //	Description:
31 //		Reset to the state as we are just entering a regulatory domain.
32 //
33 void
34 Dot11d_Reset(struct ieee80211_device *ieee)
35 {
36 	u32 i;
37 	PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee);
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 	//printk("Dot11d_UpdateCountryIe(): Channel List:\n");
108 	printk("Channel List:");
109 	for(i=1; i<= MAX_CHANNEL_NUMBER; i++)
110 		if(pDot11dInfo->channel_map[i] > 0)
111 			printk(" %d", i);
112 	printk("\n");
113 
114 	UPDATE_CIE_SRC(dev, pTaddr);
115 
116 	pDot11dInfo->CountryIeLen = CoutryIeLen;
117 	memcpy(pDot11dInfo->CountryIeBuf, pCoutryIe,CoutryIeLen);
118 	pDot11dInfo->State = DOT11D_STATE_LEARNED;
119 }
120 
121 
122 u8
123 DOT11D_GetMaxTxPwrInDbm(
124 	struct ieee80211_device *dev,
125 	u8 Channel
126 	)
127 {
128 	PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
129 	u8 MaxTxPwrInDbm = 255;
130 
131 	if(MAX_CHANNEL_NUMBER < Channel)
132 	{
133 		printk("DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n");
134 		return MaxTxPwrInDbm;
135 	}
136 	if(pDot11dInfo->channel_map[Channel])
137 	{
138 		MaxTxPwrInDbm = pDot11dInfo->MaxTxPwrDbmList[Channel];
139 	}
140 
141 	return MaxTxPwrInDbm;
142 }
143 
144 
145 void
146 DOT11D_ScanComplete(
147 	struct ieee80211_device * dev
148 	)
149 {
150 	PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
151 
152 	switch(pDot11dInfo->State)
153 	{
154 	case DOT11D_STATE_LEARNED:
155 		pDot11dInfo->State = DOT11D_STATE_DONE;
156 		break;
157 
158 	case DOT11D_STATE_DONE:
159 		if( GET_CIE_WATCHDOG(dev) == 0 )
160 		{ // Reset country IE if previous one is gone.
161 			Dot11d_Reset(dev);
162 		}
163 		break;
164 	case DOT11D_STATE_NONE:
165 		break;
166 	}
167 }
168 
169 int IsLegalChannel(
170 	struct ieee80211_device * dev,
171 	u8 channel
172 )
173 {
174 	PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
175 
176 	if(MAX_CHANNEL_NUMBER < channel)
177 	{
178 		printk("IsLegalChannel(): Invalid Channel\n");
179 		return 0;
180 	}
181 	if(pDot11dInfo->channel_map[channel] > 0)
182 		return 1;
183 	return 0;
184 }
185 
186 int ToLegalChannel(
187 	struct ieee80211_device * dev,
188 	u8 channel
189 )
190 {
191 	PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
192 	u8 default_chn = 0;
193 	u32 i = 0;
194 
195 	for (i=1; i<= MAX_CHANNEL_NUMBER; i++)
196 	{
197 		if(pDot11dInfo->channel_map[i] > 0)
198 		{
199 			default_chn = i;
200 			break;
201 		}
202 	}
203 
204 	if(MAX_CHANNEL_NUMBER < channel)
205 	{
206 		printk("IsLegalChannel(): Invalid Channel\n");
207 		return default_chn;
208 	}
209 
210 	if(pDot11dInfo->channel_map[channel] > 0)
211 		return channel;
212 
213 	return default_chn;
214 }
215 EXPORT_SYMBOL(Dot11d_Init);
216 EXPORT_SYMBOL(Dot11d_Reset);
217 EXPORT_SYMBOL(Dot11d_UpdateCountryIe);
218 EXPORT_SYMBOL(DOT11D_GetMaxTxPwrInDbm);
219 EXPORT_SYMBOL(DOT11D_ScanComplete);
220 EXPORT_SYMBOL(IsLegalChannel);
221 EXPORT_SYMBOL(ToLegalChannel);
222 
223 #endif
224