Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 266610
b: refs/heads/master
c: 1aaa8c7
h: refs/heads/master
v: v3
  • Loading branch information
Jouni Malinen authored and Kalle Valo committed Sep 22, 2011
1 parent 2c4707f commit 4dc64b6
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 252 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3b25ed186fc3ac8d2517332bfbd5c44016c10f82
refs/heads/master: 1aaa8c7469db14c3cbb0776afda0fb007eb43f46
296 changes: 45 additions & 251 deletions trunk/drivers/net/wireless/ath/ath6kl/wmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -910,277 +910,74 @@ static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len)
return 0;
}

static int ath6kl_wlan_parse_beacon(u8 *buf, int frame_len,
struct ath6kl_common_ie *cie)
{
u8 *frm, *efrm;
u8 elemid_ssid = false;

frm = buf;
efrm = (u8 *) (frm + frame_len);

/*
* beacon/probe response frame format
* [8] time stamp
* [2] beacon interval
* [2] capability information
* [tlv] ssid
* [tlv] supported rates
* [tlv] country information
* [tlv] parameter set (FH/DS)
* [tlv] erp information
* [tlv] extended supported rates
* [tlv] WMM
* [tlv] WPA or RSN
* [tlv] Atheros Advanced Capabilities
*/
if ((efrm - frm) < 12)
return -EINVAL;

memset(cie, 0, sizeof(*cie));

cie->ie_tstamp = frm;
frm += 8;
cie->ie_beaconInt = *(u16 *) frm;
frm += 2;
cie->ie_capInfo = *(u16 *) frm;
frm += 2;
cie->ie_chan = 0;

while (frm < efrm) {
switch (*frm) {
case WLAN_EID_SSID:
if (!elemid_ssid) {
cie->ie_ssid = frm;
elemid_ssid = true;
}
break;
case WLAN_EID_SUPP_RATES:
cie->ie_rates = frm;
break;
case WLAN_EID_COUNTRY:
cie->ie_country = frm;
break;
case WLAN_EID_FH_PARAMS:
break;
case WLAN_EID_DS_PARAMS:
cie->ie_chan = frm[2];
break;
case WLAN_EID_TIM:
cie->ie_tim = frm;
break;
case WLAN_EID_IBSS_PARAMS:
break;
case WLAN_EID_EXT_SUPP_RATES:
cie->ie_xrates = frm;
break;
case WLAN_EID_ERP_INFO:
if (frm[1] != 1)
return -EINVAL;

cie->ie_erp = frm[2];
break;
case WLAN_EID_RSN:
cie->ie_rsn = frm;
break;
case WLAN_EID_HT_CAPABILITY:
cie->ie_htcap = frm;
break;
case WLAN_EID_HT_INFORMATION:
cie->ie_htop = frm;
break;
case WLAN_EID_VENDOR_SPECIFIC:
if (frm[1] > 3 && frm[2] == 0x00 && frm[3] == 0x50 &&
frm[4] == 0xf2) {
/* OUT Type (00:50:F2) */

if (frm[5] == WPA_OUI_TYPE) {
/* WPA OUT */
cie->ie_wpa = frm;
} else if (frm[5] == WMM_OUI_TYPE) {
/* WMM OUT */
cie->ie_wmm = frm;
} else if (frm[5] == WSC_OUT_TYPE) {
/* WSC OUT */
cie->ie_wsc = frm;
}

} else if (frm[1] > 3 && frm[2] == 0x00
&& frm[3] == 0x03 && frm[4] == 0x7f
&& frm[5] == ATH_OUI_TYPE) {
/* Atheros OUI (00:03:7f) */
cie->ie_ath = frm;
}
break;
default:
break;
}
frm += frm[1] + 2;
}

if ((cie->ie_rates == NULL)
|| (cie->ie_rates[1] > ATH6KL_RATE_MAXSIZE))
return -EINVAL;

if ((cie->ie_ssid == NULL)
|| (cie->ie_ssid[1] > IEEE80211_MAX_SSID_LEN))
return -EINVAL;

return 0;
}

static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len)
{
struct bss *bss = NULL;
struct wmi_bss_info_hdr *bih;
u8 cached_ssid_len = 0;
u8 cached_ssid[IEEE80211_MAX_SSID_LEN] = { 0 };
u8 beacon_ssid_len = 0;
u8 *buf, *ie_ssid;
u8 *ni_buf;
int buf_len;

int ret;
u8 *buf;
struct ieee80211_channel *channel;
struct ath6kl *ar = wmi->parent_dev;
struct ieee80211_mgmt *mgmt;
struct cfg80211_bss *bss;

if (len <= sizeof(struct wmi_bss_info_hdr))
return -EINVAL;

bih = (struct wmi_bss_info_hdr *) datap;
bss = wlan_find_node(&wmi->parent_dev->scan_table, bih->bssid);

if (a_sle16_to_cpu(bih->rssi) > 0) {
if (bss == NULL)
return 0;
else
bih->rssi = a_cpu_to_sle16(bss->ni_rssi);
}

buf = datap + sizeof(struct wmi_bss_info_hdr);
len -= sizeof(struct wmi_bss_info_hdr);

ath6kl_dbg(ATH6KL_DBG_WMI,
"bss info evt - ch %u, rssi %02x, bssid \"%pM\"\n",
bih->ch, a_sle16_to_cpu(bih->rssi), bih->bssid);

if (bss != NULL) {
/*
* Free up the node. We are about to allocate a new node.
* In case of hidden AP, beacon will not have ssid,
* but a directed probe response will have it,
* so cache the probe-resp-ssid if already present.
*/
if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE)) {
ie_ssid = bss->ni_cie.ie_ssid;
if (ie_ssid && (ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) &&
(ie_ssid[2] != 0)) {
cached_ssid_len = ie_ssid[1];
memcpy(cached_ssid, ie_ssid + 2,
cached_ssid_len);
}
}

/*
* Use the current average rssi of associated AP base on
* assumption
* 1. Most os with GUI will update RSSI by
* ath6kl_wmi_get_stats_cmd() periodically.
* 2. ath6kl_wmi_get_stats_cmd(..) will be called when calling
* ath6kl_wmi_startscan_cmd(...)
* The average value of RSSI give end-user better feeling for
* instance value of scan result. It also sync up RSSI info
* in GUI between scan result and RSSI signal icon.
*/
if (memcmp(wmi->parent_dev->bssid, bih->bssid, ETH_ALEN) == 0) {
bih->rssi = a_cpu_to_sle16(bss->ni_rssi);
bih->snr = bss->ni_snr;
}

wlan_node_reclaim(&wmi->parent_dev->scan_table, bss);
}

/*
* beacon/probe response frame format
* [8] time stamp
* [2] beacon interval
* [2] capability information
* [tlv] ssid
*/
beacon_ssid_len = buf[SSID_IE_LEN_INDEX];

/*
* If ssid is cached for this hidden AP, then change
* buffer len accordingly.
*/
if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE) &&
(cached_ssid_len != 0) &&
(beacon_ssid_len == 0 || (cached_ssid_len > beacon_ssid_len &&
buf[SSID_IE_LEN_INDEX + 1] == 0))) {

len += (cached_ssid_len - beacon_ssid_len);
}
"bss info evt - ch %u, snr %d, rssi %d, bssid \"%pM\" "
"frame_type=%d\n",
bih->ch, bih->snr, a_sle16_to_cpu(bih->rssi), bih->bssid,
bih->frame_type);

bss = wlan_node_alloc(len);
if (!bss)
return -ENOMEM;
if (bih->frame_type != BEACON_FTYPE &&
bih->frame_type != PROBERESP_FTYPE)
return 0; /* Only update BSS table for now */

bss->ni_snr = bih->snr;
bss->ni_rssi = a_sle16_to_cpu(bih->rssi);
channel = ieee80211_get_channel(ar->wdev->wiphy, le16_to_cpu(bih->ch));
if (channel == NULL)
return -EINVAL;

if (WARN_ON(!bss->ni_buf))
if (len < 8 + 2 + 2)
return -EINVAL;

/*
* In case of hidden AP, beacon will not have ssid,
* but a directed probe response will have it,
* so place the cached-ssid(probe-resp) in the bss info.
* In theory, use of cfg80211_inform_bss() would be more natural here
* since we do not have the full frame. However, at least for now,
* cfg80211 can only distinguish Beacon and Probe Response frames from
* each other when using cfg80211_inform_bss_frame(), so let's build a
* fake IEEE 802.11 header to be able to take benefit of this.
*/
if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE) &&
(cached_ssid_len != 0) &&
(beacon_ssid_len == 0 || (beacon_ssid_len &&
buf[SSID_IE_LEN_INDEX + 1] == 0))) {
ni_buf = bss->ni_buf;
buf_len = len;

/*
* Copy the first 14 bytes:
* time-stamp(8), beacon-interval(2),
* cap-info(2), ssid-id(1), ssid-len(1).
*/
memcpy(ni_buf, buf, SSID_IE_LEN_INDEX + 1);

ni_buf[SSID_IE_LEN_INDEX] = cached_ssid_len;
ni_buf += (SSID_IE_LEN_INDEX + 1);

buf += (SSID_IE_LEN_INDEX + 1);
buf_len -= (SSID_IE_LEN_INDEX + 1);

memcpy(ni_buf, cached_ssid, cached_ssid_len);
ni_buf += cached_ssid_len;

buf += beacon_ssid_len;
buf_len -= beacon_ssid_len;

if (cached_ssid_len > beacon_ssid_len)
buf_len -= (cached_ssid_len - beacon_ssid_len);

memcpy(ni_buf, buf, buf_len);
} else
memcpy(bss->ni_buf, buf, len);
mgmt = kmalloc(24 + len, GFP_ATOMIC);
if (mgmt == NULL)
return -EINVAL;

bss->ni_framelen = len;
if (bih->frame_type == BEACON_FTYPE) {
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_BEACON);
memset(mgmt->da, 0xff, ETH_ALEN);
} else {
struct net_device *dev = ar->net_dev;

ret = ath6kl_wlan_parse_beacon(bss->ni_buf, len, &bss->ni_cie);
if (ret) {
wlan_node_free(bss);
return -EINVAL;
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_PROBE_RESP);
memcpy(mgmt->da, dev->dev_addr, ETH_ALEN);
}
mgmt->duration = cpu_to_le16(0);
memcpy(mgmt->sa, bih->bssid, ETH_ALEN);
memcpy(mgmt->bssid, bih->bssid, ETH_ALEN);
mgmt->seq_ctrl = cpu_to_le16(0);

/*
* Update the frequency in ie_chan, overwriting of channel number
* which is done in ath6kl_wlan_parse_beacon
*/
bss->ni_cie.ie_chan = le16_to_cpu(bih->ch);
wlan_setup_node(&wmi->parent_dev->scan_table, bss, bih->bssid);
memcpy(&mgmt->u.beacon, buf, len);

bss = cfg80211_inform_bss_frame(ar->wdev->wiphy, channel, mgmt,
24 + len, bih->snr * 100, GFP_ATOMIC);
kfree(mgmt);
if (bss == NULL)
return -ENOMEM;
cfg80211_put_bss(bss);

return 0;
}
Expand Down Expand Up @@ -1295,9 +1092,6 @@ static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len)

ev = (struct wmi_scan_complete_event *) datap;

if (a_sle32_to_cpu(ev->status) == 0)
wlan_refresh_inactive_nodes(wmi->parent_dev);

ath6kl_scan_complete_evt(wmi->parent_dev, a_sle32_to_cpu(ev->status));
wmi->is_probe_ssid = false;

Expand Down

0 comments on commit 4dc64b6

Please sign in to comment.