]> rtime.felk.cvut.cz Git - mcf548x/linux.git/blob - drivers/staging/ath6kl/wlan/src/wlan_recv_beacon.c
Initial 2.6.37
[mcf548x/linux.git] / drivers / staging / ath6kl / wlan / src / wlan_recv_beacon.c
1 //------------------------------------------------------------------------------
2 // <copyright file="wlan_recv_beacon.c" company="Atheros">
3 //    Copyright (c) 2004-2010 Atheros Corporation.  All rights reserved.
4 // 
5 //
6 // Permission to use, copy, modify, and/or distribute this software for any
7 // purpose with or without fee is hereby granted, provided that the above
8 // copyright notice and this permission notice appear in all copies.
9 //
10 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 //
18 //
19 //------------------------------------------------------------------------------
20 //==============================================================================
21 // IEEE 802.11 input handling.
22 //
23 // Author(s): ="Atheros"
24 //==============================================================================
25
26 #include "a_config.h"
27 #include "athdefs.h"
28 #include "a_types.h"
29 #include "a_osapi.h"
30 #include <wmi.h>
31 #include <ieee80211.h>
32 #include <wlan_api.h>
33
34 #define IEEE80211_VERIFY_LENGTH(_len, _minlen) do {         \
35     if ((_len) < (_minlen)) {                   \
36         return A_EINVAL;                         \
37     }                               \
38 } while (0)
39
40 #define IEEE80211_VERIFY_ELEMENT(__elem, __maxlen) do {         \
41     if ((__elem) == NULL) {                     \
42         return A_EINVAL;                         \
43     }                               \
44     if ((__elem)[1] > (__maxlen)) {                 \
45         return A_EINVAL;                         \
46     }                               \
47 } while (0)
48
49
50 /* unaligned little endian access */
51 #define LE_READ_2(p)                            \
52     ((A_UINT16)                            \
53      ((((A_UINT8 *)(p))[0]      ) | (((A_UINT8 *)(p))[1] <<  8)))
54
55 #define LE_READ_4(p)                            \
56     ((A_UINT32)                            \
57      ((((A_UINT8 *)(p))[0]      ) | (((A_UINT8 *)(p))[1] <<  8) | \
58       (((A_UINT8 *)(p))[2] << 16) | (((A_UINT8 *)(p))[3] << 24)))
59
60
61 static int __inline
62 iswpaoui(const A_UINT8 *frm)
63 {
64     return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
65 }
66
67 static int __inline
68 iswmmoui(const A_UINT8 *frm)
69 {
70     return frm[1] > 3 && LE_READ_4(frm+2) == ((WMM_OUI_TYPE<<24)|WMM_OUI);
71 }
72
73 /* unused functions for now */
74 #if 0
75 static int __inline
76 iswmmparam(const A_UINT8 *frm)
77 {
78     return frm[1] > 5 && frm[6] == WMM_PARAM_OUI_SUBTYPE;
79 }
80
81 static int __inline
82 iswmminfo(const A_UINT8 *frm)
83 {
84     return frm[1] > 5 && frm[6] == WMM_INFO_OUI_SUBTYPE;
85 }
86 #endif
87
88 static int __inline
89 isatherosoui(const A_UINT8 *frm)
90 {
91     return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
92 }
93
94 static int __inline
95 iswscoui(const A_UINT8 *frm)
96 {
97     return frm[1] > 3 && LE_READ_4(frm+2) == ((0x04<<24)|WPA_OUI);
98 }
99
100 A_STATUS
101 wlan_parse_beacon(A_UINT8 *buf, int framelen, struct ieee80211_common_ie *cie)
102 {
103     A_UINT8 *frm, *efrm;
104     A_UINT8 elemid_ssid = FALSE;
105
106     frm = buf;
107     efrm = (A_UINT8 *) (frm + framelen);
108
109     /*
110      * beacon/probe response frame format
111      *  [8] time stamp
112      *  [2] beacon interval
113      *  [2] capability information
114      *  [tlv] ssid
115      *  [tlv] supported rates
116      *  [tlv] country information
117      *  [tlv] parameter set (FH/DS)
118      *  [tlv] erp information
119      *  [tlv] extended supported rates
120      *  [tlv] WMM
121      *  [tlv] WPA or RSN
122      *  [tlv] Atheros Advanced Capabilities
123      */
124     IEEE80211_VERIFY_LENGTH(efrm - frm, 12);
125     A_MEMZERO(cie, sizeof(*cie));
126
127     cie->ie_tstamp = frm; frm += 8;
128     cie->ie_beaconInt = A_LE2CPU16(*(A_UINT16 *)frm);  frm += 2;
129     cie->ie_capInfo = A_LE2CPU16(*(A_UINT16 *)frm);  frm += 2;
130     cie->ie_chan = 0;
131
132     while (frm < efrm) {
133         switch (*frm) {
134         case IEEE80211_ELEMID_SSID:
135             if (!elemid_ssid) {
136                 cie->ie_ssid = frm;
137                 elemid_ssid = TRUE;
138             }
139             break;
140         case IEEE80211_ELEMID_RATES:
141             cie->ie_rates = frm;
142             break;
143         case IEEE80211_ELEMID_COUNTRY:
144             cie->ie_country = frm;
145             break;
146         case IEEE80211_ELEMID_FHPARMS:
147             break;
148         case IEEE80211_ELEMID_DSPARMS:
149             cie->ie_chan = frm[2];
150             break;
151         case IEEE80211_ELEMID_TIM:
152             cie->ie_tim = frm;
153             break;
154         case IEEE80211_ELEMID_IBSSPARMS:
155             break;
156         case IEEE80211_ELEMID_XRATES:
157             cie->ie_xrates = frm;
158             break;
159         case IEEE80211_ELEMID_ERP:
160             if (frm[1] != 1) {
161                 //A_PRINTF("Discarding ERP Element - Bad Len\n");
162                 return A_EINVAL;
163             }
164             cie->ie_erp = frm[2];
165             break;
166         case IEEE80211_ELEMID_RSN:
167             cie->ie_rsn = frm;
168             break;
169         case IEEE80211_ELEMID_HTCAP_ANA:
170             cie->ie_htcap = frm;
171             break;
172         case IEEE80211_ELEMID_HTINFO_ANA:
173             cie->ie_htop = frm;
174             break;
175 #ifdef WAPI_ENABLE
176                 case IEEE80211_ELEMID_WAPI:
177             cie->ie_wapi = frm;
178             break;
179 #endif
180         case IEEE80211_ELEMID_VENDOR:
181             if (iswpaoui(frm)) {
182                 cie->ie_wpa = frm;
183             } else if (iswmmoui(frm)) {
184                 cie->ie_wmm = frm;
185             } else if (isatherosoui(frm)) {
186                 cie->ie_ath = frm;
187             } else if(iswscoui(frm)) {
188                 cie->ie_wsc = frm;
189             }
190             break;
191         default:
192             break;
193         }
194         frm += frm[1] + 2;
195     }
196     IEEE80211_VERIFY_ELEMENT(cie->ie_rates, IEEE80211_RATE_MAXSIZE);
197     IEEE80211_VERIFY_ELEMENT(cie->ie_ssid, IEEE80211_NWID_LEN);
198
199     return A_OK;
200 }