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