Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[pandora-kernel.git] / drivers / staging / rt2860 / sta / sanity.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         Module Name:
28         sanity.c
29
30         Abstract:
31
32         Revision History:
33         Who                     When                    What
34         --------        ----------              ----------------------------------------------
35         John Chang  2004-09-01      add WMM support
36 */
37 #include "../rt_config.h"
38
39 extern u8 CISCO_OUI[];
40
41 extern u8 WPA_OUI[];
42 extern u8 RSN_OUI[];
43 extern u8 WME_INFO_ELEM[];
44 extern u8 WME_PARM_ELEM[];
45 extern u8 Ccx2QosInfo[];
46 extern u8 RALINK_OUI[];
47 extern u8 BROADCOM_OUI[];
48
49 /*
50     ==========================================================================
51     Description:
52         MLME message sanity check
53     Return:
54         TRUE if all parameters are OK, FALSE otherwise
55     ==========================================================================
56  */
57 BOOLEAN MlmeStartReqSanity(struct rt_rtmp_adapter *pAd,
58                            void * Msg,
59                            unsigned long MsgLen,
60                            char Ssid[], u8 * pSsidLen)
61 {
62         struct rt_mlme_start_req *Info;
63
64         Info = (struct rt_mlme_start_req *)(Msg);
65
66         if (Info->SsidLen > MAX_LEN_OF_SSID) {
67                 DBGPRINT(RT_DEBUG_TRACE,
68                          ("MlmeStartReqSanity fail - wrong SSID length\n"));
69                 return FALSE;
70         }
71
72         *pSsidLen = Info->SsidLen;
73         NdisMoveMemory(Ssid, Info->Ssid, *pSsidLen);
74
75         return TRUE;
76 }
77
78 /*
79     ==========================================================================
80     Description:
81         MLME message sanity check
82     Return:
83         TRUE if all parameters are OK, FALSE otherwise
84
85     IRQL = DISPATCH_LEVEL
86
87     ==========================================================================
88  */
89 BOOLEAN PeerAssocRspSanity(struct rt_rtmp_adapter *pAd, void * pMsg, unsigned long MsgLen, u8 *pAddr2, u16 * pCapabilityInfo, u16 * pStatus, u16 * pAid, u8 SupRate[], u8 * pSupRateLen, u8 ExtRate[], u8 * pExtRateLen, struct rt_ht_capability_ie * pHtCapability, struct rt_add_ht_info_ie * pAddHtInfo,     /* AP might use this additional ht info IE */
90                            u8 * pHtCapabilityLen,
91                            u8 * pAddHtInfoLen,
92                            u8 * pNewExtChannelOffset,
93                            struct rt_edca_parm *pEdcaParm, u8 * pCkipFlag)
94 {
95         char IeType, *Ptr;
96         struct rt_frame_802_11 * pFrame = (struct rt_frame_802_11 *) pMsg;
97         struct rt_eid * pEid;
98         unsigned long Length = 0;
99
100         *pNewExtChannelOffset = 0xff;
101         *pHtCapabilityLen = 0;
102         *pAddHtInfoLen = 0;
103         COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2);
104         Ptr = (char *)pFrame->Octet;
105         Length += LENGTH_802_11;
106
107         NdisMoveMemory(pCapabilityInfo, &pFrame->Octet[0], 2);
108         Length += 2;
109         NdisMoveMemory(pStatus, &pFrame->Octet[2], 2);
110         Length += 2;
111         *pCkipFlag = 0;
112         *pExtRateLen = 0;
113         pEdcaParm->bValid = FALSE;
114
115         if (*pStatus != MLME_SUCCESS)
116                 return TRUE;
117
118         NdisMoveMemory(pAid, &pFrame->Octet[4], 2);
119         Length += 2;
120
121         /* Aid already swaped byte order in RTMPFrameEndianChange() for big endian platform */
122         *pAid = (*pAid) & 0x3fff;       /* AID is low 14-bit */
123
124         /* -- get supported rates from payload and advance the pointer */
125         IeType = pFrame->Octet[6];
126         *pSupRateLen = pFrame->Octet[7];
127         if ((IeType != IE_SUPP_RATES)
128             || (*pSupRateLen > MAX_LEN_OF_SUPPORTED_RATES)) {
129                 DBGPRINT(RT_DEBUG_TRACE,
130                          ("PeerAssocRspSanity fail - wrong SupportedRates IE\n"));
131                 return FALSE;
132         } else
133                 NdisMoveMemory(SupRate, &pFrame->Octet[8], *pSupRateLen);
134
135         Length = Length + 2 + *pSupRateLen;
136
137         /* many AP implement proprietary IEs in non-standard order, we'd better */
138         /* tolerate mis-ordered IEs to get best compatibility */
139         pEid = (struct rt_eid *) & pFrame->Octet[8 + (*pSupRateLen)];
140
141         /* get variable fields from payload and advance the pointer */
142         while ((Length + 2 + pEid->Len) <= MsgLen) {
143                 switch (pEid->Eid) {
144                 case IE_EXT_SUPP_RATES:
145                         if (pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) {
146                                 NdisMoveMemory(ExtRate, pEid->Octet, pEid->Len);
147                                 *pExtRateLen = pEid->Len;
148                         }
149                         break;
150
151                 case IE_HT_CAP:
152                 case IE_HT_CAP2:
153                         if (pEid->Len >= SIZE_HT_CAP_IE)        /*Note: allow extension! */
154                         {
155                                 NdisMoveMemory(pHtCapability, pEid->Octet,
156                                                SIZE_HT_CAP_IE);
157
158                                 *(u16 *) (&pHtCapability->HtCapInfo) =
159                                     cpu2le16(*(u16 *)
160                                              (&pHtCapability->HtCapInfo));
161                                 *(u16 *) (&pHtCapability->ExtHtCapInfo) =
162                                     cpu2le16(*(u16 *)
163                                              (&pHtCapability->ExtHtCapInfo));
164
165                                 *pHtCapabilityLen = SIZE_HT_CAP_IE;
166                         } else {
167                                 DBGPRINT(RT_DEBUG_WARN,
168                                          ("PeerAssocRspSanity - wrong IE_HT_CAP. \n"));
169                         }
170
171                         break;
172                 case IE_ADD_HT:
173                 case IE_ADD_HT2:
174                         if (pEid->Len >= sizeof(struct rt_add_ht_info_ie)) {
175                                 /* This IE allows extension, but we can ignore extra bytes beyond our knowledge , so only */
176                                 /* copy first sizeof(struct rt_add_ht_info_ie) */
177                                 NdisMoveMemory(pAddHtInfo, pEid->Octet,
178                                                sizeof(struct rt_add_ht_info_ie));
179
180                                 *(u16 *) (&pAddHtInfo->AddHtInfo2) =
181                                     cpu2le16(*(u16 *)
182                                              (&pAddHtInfo->AddHtInfo2));
183                                 *(u16 *) (&pAddHtInfo->AddHtInfo3) =
184                                     cpu2le16(*(u16 *)
185                                              (&pAddHtInfo->AddHtInfo3));
186
187                                 *pAddHtInfoLen = SIZE_ADD_HT_INFO_IE;
188                         } else {
189                                 DBGPRINT(RT_DEBUG_WARN,
190                                          ("PeerAssocRspSanity - wrong IE_ADD_HT. \n"));
191                         }
192
193                         break;
194                 case IE_SECONDARY_CH_OFFSET:
195                         if (pEid->Len == 1) {
196                                 *pNewExtChannelOffset = pEid->Octet[0];
197                         } else {
198                                 DBGPRINT(RT_DEBUG_WARN,
199                                          ("PeerAssocRspSanity - wrong IE_SECONDARY_CH_OFFSET. \n"));
200                         }
201                         break;
202
203                 case IE_VENDOR_SPECIFIC:
204                         /* handle WME PARAMTER ELEMENT */
205                         if (NdisEqualMemory(pEid->Octet, WME_PARM_ELEM, 6)
206                             && (pEid->Len == 24)) {
207                                 u8 *ptr;
208                                 int i;
209
210                                 /* parsing EDCA parameters */
211                                 pEdcaParm->bValid = TRUE;
212                                 pEdcaParm->bQAck = FALSE;       /* pEid->Octet[0] & 0x10; */
213                                 pEdcaParm->bQueueRequest = FALSE;       /* pEid->Octet[0] & 0x20; */
214                                 pEdcaParm->bTxopRequest = FALSE;        /* pEid->Octet[0] & 0x40; */
215                                 /*pEdcaParm->bMoreDataAck    = FALSE; // pEid->Octet[0] & 0x80; */
216                                 pEdcaParm->EdcaUpdateCount =
217                                     pEid->Octet[6] & 0x0f;
218                                 pEdcaParm->bAPSDCapable =
219                                     (pEid->Octet[6] & 0x80) ? 1 : 0;
220                                 ptr = (u8 *)& pEid->Octet[8];
221                                 for (i = 0; i < 4; i++) {
222                                         u8 aci = (*ptr & 0x60) >> 5;    /* b5~6 is AC INDEX */
223                                         pEdcaParm->bACM[aci] = (((*ptr) & 0x10) == 0x10);       /* b5 is ACM */
224                                         pEdcaParm->Aifsn[aci] = (*ptr) & 0x0f;  /* b0~3 is AIFSN */
225                                         pEdcaParm->Cwmin[aci] = *(ptr + 1) & 0x0f;      /* b0~4 is Cwmin */
226                                         pEdcaParm->Cwmax[aci] = *(ptr + 1) >> 4;        /* b5~8 is Cwmax */
227                                         pEdcaParm->Txop[aci] = *(ptr + 2) + 256 * (*(ptr + 3)); /* in unit of 32-us */
228                                         ptr += 4;       /* point to next AC */
229                                 }
230                         }
231                         break;
232                 default:
233                         DBGPRINT(RT_DEBUG_TRACE,
234                                  ("PeerAssocRspSanity - ignore unrecognized EID = %d\n",
235                                   pEid->Eid));
236                         break;
237                 }
238
239                 Length = Length + 2 + pEid->Len;
240                 pEid = (struct rt_eid *) ((u8 *) pEid + 2 + pEid->Len);
241         }
242
243         return TRUE;
244 }
245
246 /*
247     ==========================================================================
248     Description:
249         MLME message sanity check
250     Return:
251         TRUE if all parameters are OK, FALSE otherwise
252
253         IRQL = DISPATCH_LEVEL
254
255     ==========================================================================
256  */
257 BOOLEAN PeerProbeReqSanity(struct rt_rtmp_adapter *pAd,
258                            void * Msg,
259                            unsigned long MsgLen,
260                            u8 *pAddr2,
261                            char Ssid[], u8 * pSsidLen)
262 {
263         u8 Idx;
264         u8 RateLen;
265         char IeType;
266         struct rt_frame_802_11 * pFrame = (struct rt_frame_802_11 *) Msg;
267
268         COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2);
269
270         if ((pFrame->Octet[0] != IE_SSID)
271             || (pFrame->Octet[1] > MAX_LEN_OF_SSID)) {
272                 DBGPRINT(RT_DEBUG_TRACE,
273                          ("PeerProbeReqSanity fail - wrong SSID IE(Type=%d,Len=%d)\n",
274                           pFrame->Octet[0], pFrame->Octet[1]));
275                 return FALSE;
276         }
277
278         *pSsidLen = pFrame->Octet[1];
279         NdisMoveMemory(Ssid, &pFrame->Octet[2], *pSsidLen);
280
281         Idx = *pSsidLen + 2;
282
283         /* -- get supported rates from payload and advance the pointer */
284         IeType = pFrame->Octet[Idx];
285         RateLen = pFrame->Octet[Idx + 1];
286         if (IeType != IE_SUPP_RATES) {
287                 DBGPRINT(RT_DEBUG_TRACE,
288                          ("PeerProbeReqSanity fail - wrong SupportRates IE(Type=%d,Len=%d)\n",
289                           pFrame->Octet[Idx], pFrame->Octet[Idx + 1]));
290                 return FALSE;
291         } else {
292                 if ((pAd->CommonCfg.PhyMode == PHY_11G) && (RateLen < 8))
293                         return (FALSE);
294         }
295
296         return TRUE;
297 }
298
299 /*
300     ==========================================================================
301     Description:
302
303         IRQL = DISPATCH_LEVEL
304
305     ==========================================================================
306  */
307 BOOLEAN GetTimBit(char * Ptr,
308                   u16 Aid,
309                   u8 * TimLen,
310                   u8 * BcastFlag,
311                   u8 * DtimCount,
312                   u8 * DtimPeriod, u8 * MessageToMe)
313 {
314         u8 BitCntl, N1, N2, MyByte, MyBit;
315         char *IdxPtr;
316
317         IdxPtr = Ptr;
318
319         IdxPtr++;
320         *TimLen = *IdxPtr;
321
322         /* get DTIM Count from TIM element */
323         IdxPtr++;
324         *DtimCount = *IdxPtr;
325
326         /* get DTIM Period from TIM element */
327         IdxPtr++;
328         *DtimPeriod = *IdxPtr;
329
330         /* get Bitmap Control from TIM element */
331         IdxPtr++;
332         BitCntl = *IdxPtr;
333
334         if ((*DtimCount == 0) && (BitCntl & 0x01))
335                 *BcastFlag = TRUE;
336         else
337                 *BcastFlag = FALSE;
338
339         /* Parse Partial Virtual Bitmap from TIM element */
340         N1 = BitCntl & 0xfe;    /* N1 is the first bitmap byte# */
341         N2 = *TimLen - 4 + N1;  /* N2 is the last bitmap byte# */
342
343         if ((Aid < (N1 << 3)) || (Aid >= ((N2 + 1) << 3)))
344                 *MessageToMe = FALSE;
345         else {
346                 MyByte = (Aid >> 3) - N1;       /* my byte position in the bitmap byte-stream */
347                 MyBit = Aid % 16 - ((MyByte & 0x01) ? 8 : 0);
348
349                 IdxPtr += (MyByte + 1);
350
351                 /*if (*IdxPtr) */
352                 /*    DBGPRINT(RT_DEBUG_WARN, ("TIM bitmap = 0x%02x\n", *IdxPtr)); */
353
354                 if (*IdxPtr & (0x01 << MyBit))
355                         *MessageToMe = TRUE;
356                 else
357                         *MessageToMe = FALSE;
358         }
359
360         return TRUE;
361 }