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 71static int __inline 72iswpaoui(const A_UINT8 *frm) 73{ 74 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 75} 76 77static int __inline 78iswmmoui(const A_UINT8 *frm) 79{ 80 return frm[1] > 3 && LE_READ_4(frm+2) == ((WMM_OUI_TYPE<<24)|WMM_OUI); 81} 82 83static int __inline 84iswmmparam(const A_UINT8 *frm) 85{ 86 return frm[1] > 5 && frm[6] == WMM_PARAM_OUI_SUBTYPE; 87} 88 89static int __inline 90iswmminfo(const A_UINT8 *frm) 91{ 92 return frm[1] > 5 && frm[6] == WMM_INFO_OUI_SUBTYPE; 93} 94 95static int __inline 96isatherosoui(const A_UINT8 *frm) 97{ 98 return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); 99} 100 101static int __inline 102iswscoui(const A_UINT8 *frm) 103{ 104 return frm[1] > 3 && LE_READ_4(frm+2) == ((0x04<<24)|WPA_OUI); 105} 106 107A_STATUS 108wlan_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} 193