15beabb6549b26d24afe544108eb57049d9fbc61
[openwrt.git] / target / linux / s3c24xx / files-2.6.31 / drivers / ar6000 / wlan / wlan_recv_beacon.c
1 /*-
2  * Copyright (c) 2001 Atsushi Onoe
3  * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * Alternatively, this software may be distributed under the terms of the
18  * GNU General Public License ("GPL") version 2 as published by the Free
19  * Software Foundation.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  * IEEE 802.11 input handling.
34  */
35
36 #include "a_config.h"
37 #include "athdefs.h"
38 #include "a_types.h"
39 #include "a_osapi.h"
40 #include <wmi.h>
41 #include <ieee80211.h>
42 #include <wlan_api.h>
43
44 #define IEEE80211_VERIFY_LENGTH(_len, _minlen) do {         \
45     if ((_len) < (_minlen)) {                   \
46         return A_EINVAL;                         \
47     }                               \
48 } while (0)
49
50 #define IEEE80211_VERIFY_ELEMENT(__elem, __maxlen) do {         \
51     if ((__elem) == NULL) {                     \
52         return A_EINVAL;                         \
53     }                               \
54     if ((__elem)[1] > (__maxlen)) {                 \
55         return A_EINVAL;                         \
56     }                               \
57 } while (0)
58
59
60 /* unaligned little endian access */
61 #define LE_READ_2(p)                            \
62     ((A_UINT16)                            \
63      ((((A_UINT8 *)(p))[0]      ) | (((A_UINT8 *)(p))[1] <<  8)))
64
65 #define LE_READ_4(p)                            \
66     ((A_UINT32)                            \
67      ((((A_UINT8 *)(p))[0]      ) | (((A_UINT8 *)(p))[1] <<  8) | \
68       (((A_UINT8 *)(p))[2] << 16) | (((A_UINT8 *)(p))[3] << 24)))
69
70
71 static int __inline
72 iswpaoui(const A_UINT8 *frm)
73 {
74     return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
75 }
76
77 static int __inline
78 iswmmoui(const A_UINT8 *frm)
79 {
80     return frm[1] > 3 && LE_READ_4(frm+2) == ((WMM_OUI_TYPE<<24)|WMM_OUI);
81 }
82
83 static int __inline
84 iswmmparam(const A_UINT8 *frm)
85 {
86     return frm[1] > 5 && frm[6] == WMM_PARAM_OUI_SUBTYPE;
87 }
88
89 static int __inline
90 iswmminfo(const A_UINT8 *frm)
91 {
92     return frm[1] > 5 && frm[6] == WMM_INFO_OUI_SUBTYPE;
93 }
94
95 static int __inline
96 isatherosoui(const A_UINT8 *frm)
97 {
98     return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
99 }
100
101 static int __inline
102 iswscoui(const A_UINT8 *frm)
103 {
104     return frm[1] > 3 && LE_READ_4(frm+2) == ((0x04<<24)|WPA_OUI);
105 }
106
107 A_STATUS
108 wlan_parse_beacon(A_UINT8 *buf, int framelen, struct ieee80211_common_ie *cie)
109 {
110     A_UINT8 *frm, *efrm;
111
112     frm = buf;
113     efrm = (A_UINT8 *) (frm + framelen);
114
115     /*
116      * beacon/probe response frame format
117      *  [8] time stamp
118      *  [2] beacon interval
119      *  [2] capability information
120      *  [tlv] ssid
121      *  [tlv] supported rates
122      *  [tlv] country information
123      *  [tlv] parameter set (FH/DS)
124      *  [tlv] erp information
125      *  [tlv] extended supported rates
126      *  [tlv] WMM
127      *  [tlv] WPA or RSN
128      *  [tlv] Atheros Advanced Capabilities
129      */
130     IEEE80211_VERIFY_LENGTH(efrm - frm, 12);
131     A_MEMZERO(cie, sizeof(*cie));
132
133     cie->ie_tstamp = frm; frm += 8;
134     cie->ie_beaconInt = A_LE2CPU16(*(A_UINT16 *)frm);  frm += 2;
135     cie->ie_capInfo = A_LE2CPU16(*(A_UINT16 *)frm);  frm += 2;
136     cie->ie_chan = 0;
137
138     while (frm < efrm) {
139         switch (*frm) {
140         case IEEE80211_ELEMID_SSID:
141             cie->ie_ssid = frm;
142             break;
143         case IEEE80211_ELEMID_RATES:
144             cie->ie_rates = frm;
145             break;
146         case IEEE80211_ELEMID_COUNTRY:
147             cie->ie_country = frm;
148             break;
149         case IEEE80211_ELEMID_FHPARMS:
150             break;
151         case IEEE80211_ELEMID_DSPARMS:
152             cie->ie_chan = frm[2];
153             break;
154         case IEEE80211_ELEMID_TIM:
155             cie->ie_tim = frm;
156             break;
157         case IEEE80211_ELEMID_IBSSPARMS:
158             break;
159         case IEEE80211_ELEMID_XRATES:
160             cie->ie_xrates = frm;
161             break;
162         case IEEE80211_ELEMID_ERP:
163             if (frm[1] != 1) {
164                 //A_PRINTF("Discarding ERP Element - Bad Len\n");
165                 return A_EINVAL;
166             }
167             cie->ie_erp = frm[2];
168             break;
169         case IEEE80211_ELEMID_RSN:
170             cie->ie_rsn = frm;
171             break;
172         case IEEE80211_ELEMID_VENDOR:
173             if (iswpaoui(frm)) {
174                 cie->ie_wpa = frm;
175             } else if (iswmmoui(frm)) {
176                 cie->ie_wmm = frm;
177             } else if (isatherosoui(frm)) {
178                 cie->ie_ath = frm;
179             } else if(iswscoui(frm)) {
180                 cie->ie_wsc = frm;
181             }
182             break;
183         default:
184             break;
185         }
186         frm += frm[1] + 2;
187     }
188     IEEE80211_VERIFY_ELEMENT(cie->ie_rates, IEEE80211_RATE_MAXSIZE);
189     IEEE80211_VERIFY_ELEMENT(cie->ie_ssid, IEEE80211_NWID_LEN);
190
191     return A_OK;
192 }