1 //-----------------------------------------------------------------------------
2 //	File:
3 //		Dot11d.c
4 //
5 //	Description:
6 //		Implement 802.11d.
7 //
8 //-----------------------------------------------------------------------------
9 
10 #include "dot11d.h"
11 
12 void
Dot11d_Init(struct ieee80211_device * ieee)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
Dot11d_Reset(struct ieee80211_device * ieee)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
Dot11d_UpdateCountryIe(struct ieee80211_device * dev,u8 * pTaddr,u16 CoutryIeLen,u8 * pCoutryIe)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 	if((CoutryIeLen - 3)%3 != 0)
81 	{
82 		printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n");
83 		Dot11d_Reset(dev);
84 		return;
85 	}
86 
87 	memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1);
88 	memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1);
89 	MaxChnlNum = 0;
90 	NumTriples = (CoutryIeLen - 3) / 3; // skip 3-byte country string.
91 	pTriple = (PCHNL_TXPOWER_TRIPLE)(pCoutryIe + 3);
92 	for(i = 0; i < NumTriples; i++)
93 	{
94 		if(MaxChnlNum >= pTriple->FirstChnl)
95 		{ // It is not in a monotonically increasing order, so stop processing.
96 			printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n");
97 			Dot11d_Reset(dev);
98 			return;
99 		}
100 		if(MAX_CHANNEL_NUMBER < (pTriple->FirstChnl + pTriple->NumChnls))
101 		{ // It is not a valid set of channel id, so stop processing.
102 			printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n");
103 			Dot11d_Reset(dev);
104 			return;
105 		}
106 
107 		for(j = 0 ; j < pTriple->NumChnls; j++)
108 		{
109 			pDot11dInfo->channel_map[pTriple->FirstChnl + j] = 1;
110 			pDot11dInfo->MaxTxPwrDbmList[pTriple->FirstChnl + j] = pTriple->MaxTxPowerInDbm;
111 			MaxChnlNum = pTriple->FirstChnl + j;
112 		}
113 
114 		pTriple = (PCHNL_TXPOWER_TRIPLE)((u8*)pTriple + 3);
115 	}
116 #if 1
117 	//printk("Dot11d_UpdateCountryIe(): Channel List:\n");
118 	printk("Channel List:");
119 	for(i=1; i<= MAX_CHANNEL_NUMBER; i++)
120 		if(pDot11dInfo->channel_map[i] > 0)
121 			printk(" %d", i);
122 	printk("\n");
123 #endif
124 
125 	UPDATE_CIE_SRC(dev, pTaddr);
126 
127 	pDot11dInfo->CountryIeLen = CoutryIeLen;
128 	memcpy(pDot11dInfo->CountryIeBuf, pCoutryIe,CoutryIeLen);
129 	pDot11dInfo->State = DOT11D_STATE_LEARNED;
130 }
131 
132 u8
DOT11D_GetMaxTxPwrInDbm(struct ieee80211_device * dev,u8 Channel)133 DOT11D_GetMaxTxPwrInDbm(
134 	struct ieee80211_device *dev,
135 	u8 Channel
136 	)
137 {
138 	PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
139 	u8 MaxTxPwrInDbm = 255;
140 
141 	if(MAX_CHANNEL_NUMBER < Channel)
142 	{
143 		printk("DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n");
144 		return MaxTxPwrInDbm;
145 	}
146 	if(pDot11dInfo->channel_map[Channel])
147 	{
148 		MaxTxPwrInDbm = pDot11dInfo->MaxTxPwrDbmList[Channel];
149 	}
150 
151 	return MaxTxPwrInDbm;
152 }
153 
154 
155 void
DOT11D_ScanComplete(struct ieee80211_device * dev)156 DOT11D_ScanComplete(
157 	struct ieee80211_device * dev
158 	)
159 {
160 	PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
161 
162 	switch(pDot11dInfo->State)
163 	{
164 	case DOT11D_STATE_LEARNED:
165 		pDot11dInfo->State = DOT11D_STATE_DONE;
166 		break;
167 
168 	case DOT11D_STATE_DONE:
169 		if( GET_CIE_WATCHDOG(dev) == 0 )
170 		{ // Reset country IE if previous one is gone.
171 			Dot11d_Reset(dev);
172 		}
173 		break;
174 	case DOT11D_STATE_NONE:
175 		break;
176 	}
177 }
178 
IsLegalChannel(struct ieee80211_device * dev,u8 channel)179 int IsLegalChannel(
180 	struct ieee80211_device * dev,
181 	u8 channel
182 )
183 {
184 	PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
185 
186 	if(MAX_CHANNEL_NUMBER < channel)
187 	{
188 		printk("IsLegalChannel(): Invalid Channel\n");
189 		return 0;
190 	}
191 	if(pDot11dInfo->channel_map[channel] > 0)
192 		return 1;
193 	return 0;
194 }
195 
ToLegalChannel(struct ieee80211_device * dev,u8 channel)196 int ToLegalChannel(
197 	struct ieee80211_device * dev,
198 	u8 channel
199 )
200 {
201 	PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev);
202 	u8 default_chn = 0;
203 	u32 i = 0;
204 
205 	for (i=1; i<= MAX_CHANNEL_NUMBER; i++)
206 	{
207 		if(pDot11dInfo->channel_map[i] > 0)
208 		{
209 			default_chn = i;
210 			break;
211 		}
212 	}
213 
214 	if(MAX_CHANNEL_NUMBER < channel)
215 	{
216 		printk("IsLegalChannel(): Invalid Channel\n");
217 		return default_chn;
218 	}
219 
220 	if(pDot11dInfo->channel_map[channel] > 0)
221 		return channel;
222 
223 	return default_chn;
224 }
225