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 ((u16) \
53 ((((u8 *)(p))[0] ) | (((u8 *)(p))[1] << 8)))
54
55 #define LE_READ_4(p) \
56 ((u32) \
57 ((((u8 *)(p))[0] ) | (((u8 *)(p))[1] << 8) | \
58 (((u8 *)(p))[2] << 16) | (((u8 *)(p))[3] << 24)))
59
60
61 static int __inline
iswpaoui(const u8 * frm)62 iswpaoui(const u8 *frm)
63 {
64 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
65 }
66
67 static int __inline
iswmmoui(const u8 * frm)68 iswmmoui(const u8 *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 u8 *frm)
77 {
78 return frm[1] > 5 && frm[6] == WMM_PARAM_OUI_SUBTYPE;
79 }
80
81 static int __inline
82 iswmminfo(const u8 *frm)
83 {
84 return frm[1] > 5 && frm[6] == WMM_INFO_OUI_SUBTYPE;
85 }
86 #endif
87
88 static int __inline
isatherosoui(const u8 * frm)89 isatherosoui(const u8 *frm)
90 {
91 return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
92 }
93
94 static int __inline
iswscoui(const u8 * frm)95 iswscoui(const u8 *frm)
96 {
97 return frm[1] > 3 && LE_READ_4(frm+2) == ((0x04<<24)|WPA_OUI);
98 }
99
100 int
wlan_parse_beacon(u8 * buf,int framelen,struct ieee80211_common_ie * cie)101 wlan_parse_beacon(u8 *buf, int framelen, struct ieee80211_common_ie *cie)
102 {
103 u8 *frm, *efrm;
104 u8 elemid_ssid = false;
105
106 frm = buf;
107 efrm = (u8 *) (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(*(u16 *)frm); frm += 2;
129 cie->ie_capInfo = A_LE2CPU16(*(u16 *)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 0;
200 }
201