1*0a51b27eSJohannes Berg /* 2*0a51b27eSJohannes Berg * BSS client mode implementation 3*0a51b27eSJohannes Berg * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> 4*0a51b27eSJohannes Berg * Copyright 2004, Instant802 Networks, Inc. 5*0a51b27eSJohannes Berg * Copyright 2005, Devicescape Software, Inc. 6*0a51b27eSJohannes Berg * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> 7*0a51b27eSJohannes Berg * Copyright 2007, Michael Wu <flamingice@sourmilk.net> 8*0a51b27eSJohannes Berg * 9*0a51b27eSJohannes Berg * This program is free software; you can redistribute it and/or modify 10*0a51b27eSJohannes Berg * it under the terms of the GNU General Public License version 2 as 11*0a51b27eSJohannes Berg * published by the Free Software Foundation. 12*0a51b27eSJohannes Berg */ 13*0a51b27eSJohannes Berg 14*0a51b27eSJohannes Berg #include <linux/wireless.h> 15*0a51b27eSJohannes Berg #include <linux/if_arp.h> 16*0a51b27eSJohannes Berg #include <net/mac80211.h> 17*0a51b27eSJohannes Berg #include <net/iw_handler.h> 18*0a51b27eSJohannes Berg 19*0a51b27eSJohannes Berg #include "ieee80211_i.h" 20*0a51b27eSJohannes Berg 21*0a51b27eSJohannes Berg #define IEEE80211_PROBE_DELAY (HZ / 33) 22*0a51b27eSJohannes Berg #define IEEE80211_CHANNEL_TIME (HZ / 33) 23*0a51b27eSJohannes Berg #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5) 24*0a51b27eSJohannes Berg 25*0a51b27eSJohannes Berg 26*0a51b27eSJohannes Berg static void ieee80211_send_nullfunc(struct ieee80211_local *local, 27*0a51b27eSJohannes Berg struct ieee80211_sub_if_data *sdata, 28*0a51b27eSJohannes Berg int powersave) 29*0a51b27eSJohannes Berg { 30*0a51b27eSJohannes Berg struct sk_buff *skb; 31*0a51b27eSJohannes Berg struct ieee80211_hdr *nullfunc; 32*0a51b27eSJohannes Berg __le16 fc; 33*0a51b27eSJohannes Berg 34*0a51b27eSJohannes Berg skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); 35*0a51b27eSJohannes Berg if (!skb) { 36*0a51b27eSJohannes Berg printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " 37*0a51b27eSJohannes Berg "frame\n", sdata->dev->name); 38*0a51b27eSJohannes Berg return; 39*0a51b27eSJohannes Berg } 40*0a51b27eSJohannes Berg skb_reserve(skb, local->hw.extra_tx_headroom); 41*0a51b27eSJohannes Berg 42*0a51b27eSJohannes Berg nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); 43*0a51b27eSJohannes Berg memset(nullfunc, 0, 24); 44*0a51b27eSJohannes Berg fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | 45*0a51b27eSJohannes Berg IEEE80211_FCTL_TODS); 46*0a51b27eSJohannes Berg if (powersave) 47*0a51b27eSJohannes Berg fc |= cpu_to_le16(IEEE80211_FCTL_PM); 48*0a51b27eSJohannes Berg nullfunc->frame_control = fc; 49*0a51b27eSJohannes Berg memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN); 50*0a51b27eSJohannes Berg memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); 51*0a51b27eSJohannes Berg memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN); 52*0a51b27eSJohannes Berg 53*0a51b27eSJohannes Berg ieee80211_sta_tx(sdata, skb, 0); 54*0a51b27eSJohannes Berg } 55*0a51b27eSJohannes Berg 56*0a51b27eSJohannes Berg static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) 57*0a51b27eSJohannes Berg { 58*0a51b27eSJohannes Berg if (sdata->vif.type == IEEE80211_IF_TYPE_STA || 59*0a51b27eSJohannes Berg ieee80211_vif_is_mesh(&sdata->vif)) 60*0a51b27eSJohannes Berg ieee80211_sta_timer((unsigned long)sdata); 61*0a51b27eSJohannes Berg } 62*0a51b27eSJohannes Berg 63*0a51b27eSJohannes Berg void ieee80211_scan_completed(struct ieee80211_hw *hw) 64*0a51b27eSJohannes Berg { 65*0a51b27eSJohannes Berg struct ieee80211_local *local = hw_to_local(hw); 66*0a51b27eSJohannes Berg struct ieee80211_sub_if_data *sdata; 67*0a51b27eSJohannes Berg union iwreq_data wrqu; 68*0a51b27eSJohannes Berg 69*0a51b27eSJohannes Berg local->last_scan_completed = jiffies; 70*0a51b27eSJohannes Berg memset(&wrqu, 0, sizeof(wrqu)); 71*0a51b27eSJohannes Berg wireless_send_event(local->scan_sdata->dev, SIOCGIWSCAN, &wrqu, NULL); 72*0a51b27eSJohannes Berg 73*0a51b27eSJohannes Berg if (local->sta_hw_scanning) { 74*0a51b27eSJohannes Berg local->sta_hw_scanning = 0; 75*0a51b27eSJohannes Berg if (ieee80211_hw_config(local)) 76*0a51b27eSJohannes Berg printk(KERN_DEBUG "%s: failed to restore operational " 77*0a51b27eSJohannes Berg "channel after scan\n", wiphy_name(local->hw.wiphy)); 78*0a51b27eSJohannes Berg /* Restart STA timer for HW scan case */ 79*0a51b27eSJohannes Berg rcu_read_lock(); 80*0a51b27eSJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) 81*0a51b27eSJohannes Berg ieee80211_restart_sta_timer(sdata); 82*0a51b27eSJohannes Berg rcu_read_unlock(); 83*0a51b27eSJohannes Berg 84*0a51b27eSJohannes Berg goto done; 85*0a51b27eSJohannes Berg } 86*0a51b27eSJohannes Berg 87*0a51b27eSJohannes Berg local->sta_sw_scanning = 0; 88*0a51b27eSJohannes Berg if (ieee80211_hw_config(local)) 89*0a51b27eSJohannes Berg printk(KERN_DEBUG "%s: failed to restore operational " 90*0a51b27eSJohannes Berg "channel after scan\n", wiphy_name(local->hw.wiphy)); 91*0a51b27eSJohannes Berg 92*0a51b27eSJohannes Berg 93*0a51b27eSJohannes Berg netif_tx_lock_bh(local->mdev); 94*0a51b27eSJohannes Berg netif_addr_lock(local->mdev); 95*0a51b27eSJohannes Berg local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; 96*0a51b27eSJohannes Berg local->ops->configure_filter(local_to_hw(local), 97*0a51b27eSJohannes Berg FIF_BCN_PRBRESP_PROMISC, 98*0a51b27eSJohannes Berg &local->filter_flags, 99*0a51b27eSJohannes Berg local->mdev->mc_count, 100*0a51b27eSJohannes Berg local->mdev->mc_list); 101*0a51b27eSJohannes Berg 102*0a51b27eSJohannes Berg netif_addr_unlock(local->mdev); 103*0a51b27eSJohannes Berg netif_tx_unlock_bh(local->mdev); 104*0a51b27eSJohannes Berg 105*0a51b27eSJohannes Berg rcu_read_lock(); 106*0a51b27eSJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) { 107*0a51b27eSJohannes Berg /* Tell AP we're back */ 108*0a51b27eSJohannes Berg if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { 109*0a51b27eSJohannes Berg if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { 110*0a51b27eSJohannes Berg ieee80211_send_nullfunc(local, sdata, 0); 111*0a51b27eSJohannes Berg netif_tx_wake_all_queues(sdata->dev); 112*0a51b27eSJohannes Berg } 113*0a51b27eSJohannes Berg } else 114*0a51b27eSJohannes Berg netif_tx_wake_all_queues(sdata->dev); 115*0a51b27eSJohannes Berg 116*0a51b27eSJohannes Berg ieee80211_restart_sta_timer(sdata); 117*0a51b27eSJohannes Berg } 118*0a51b27eSJohannes Berg rcu_read_unlock(); 119*0a51b27eSJohannes Berg 120*0a51b27eSJohannes Berg done: 121*0a51b27eSJohannes Berg ieee80211_mlme_notify_scan_completed(local); 122*0a51b27eSJohannes Berg } 123*0a51b27eSJohannes Berg EXPORT_SYMBOL(ieee80211_scan_completed); 124*0a51b27eSJohannes Berg 125*0a51b27eSJohannes Berg 126*0a51b27eSJohannes Berg void ieee80211_sta_scan_work(struct work_struct *work) 127*0a51b27eSJohannes Berg { 128*0a51b27eSJohannes Berg struct ieee80211_local *local = 129*0a51b27eSJohannes Berg container_of(work, struct ieee80211_local, scan_work.work); 130*0a51b27eSJohannes Berg struct ieee80211_sub_if_data *sdata = local->scan_sdata; 131*0a51b27eSJohannes Berg struct ieee80211_supported_band *sband; 132*0a51b27eSJohannes Berg struct ieee80211_channel *chan; 133*0a51b27eSJohannes Berg int skip; 134*0a51b27eSJohannes Berg unsigned long next_delay = 0; 135*0a51b27eSJohannes Berg 136*0a51b27eSJohannes Berg if (!local->sta_sw_scanning) 137*0a51b27eSJohannes Berg return; 138*0a51b27eSJohannes Berg 139*0a51b27eSJohannes Berg switch (local->scan_state) { 140*0a51b27eSJohannes Berg case SCAN_SET_CHANNEL: 141*0a51b27eSJohannes Berg /* 142*0a51b27eSJohannes Berg * Get current scan band. scan_band may be IEEE80211_NUM_BANDS 143*0a51b27eSJohannes Berg * after we successfully scanned the last channel of the last 144*0a51b27eSJohannes Berg * band (and the last band is supported by the hw) 145*0a51b27eSJohannes Berg */ 146*0a51b27eSJohannes Berg if (local->scan_band < IEEE80211_NUM_BANDS) 147*0a51b27eSJohannes Berg sband = local->hw.wiphy->bands[local->scan_band]; 148*0a51b27eSJohannes Berg else 149*0a51b27eSJohannes Berg sband = NULL; 150*0a51b27eSJohannes Berg 151*0a51b27eSJohannes Berg /* 152*0a51b27eSJohannes Berg * If we are at an unsupported band and have more bands 153*0a51b27eSJohannes Berg * left to scan, advance to the next supported one. 154*0a51b27eSJohannes Berg */ 155*0a51b27eSJohannes Berg while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) { 156*0a51b27eSJohannes Berg local->scan_band++; 157*0a51b27eSJohannes Berg sband = local->hw.wiphy->bands[local->scan_band]; 158*0a51b27eSJohannes Berg local->scan_channel_idx = 0; 159*0a51b27eSJohannes Berg } 160*0a51b27eSJohannes Berg 161*0a51b27eSJohannes Berg /* if no more bands/channels left, complete scan */ 162*0a51b27eSJohannes Berg if (!sband || local->scan_channel_idx >= sband->n_channels) { 163*0a51b27eSJohannes Berg ieee80211_scan_completed(local_to_hw(local)); 164*0a51b27eSJohannes Berg return; 165*0a51b27eSJohannes Berg } 166*0a51b27eSJohannes Berg skip = 0; 167*0a51b27eSJohannes Berg chan = &sband->channels[local->scan_channel_idx]; 168*0a51b27eSJohannes Berg 169*0a51b27eSJohannes Berg if (chan->flags & IEEE80211_CHAN_DISABLED || 170*0a51b27eSJohannes Berg (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && 171*0a51b27eSJohannes Berg chan->flags & IEEE80211_CHAN_NO_IBSS)) 172*0a51b27eSJohannes Berg skip = 1; 173*0a51b27eSJohannes Berg 174*0a51b27eSJohannes Berg if (!skip) { 175*0a51b27eSJohannes Berg local->scan_channel = chan; 176*0a51b27eSJohannes Berg if (ieee80211_hw_config(local)) { 177*0a51b27eSJohannes Berg printk(KERN_DEBUG "%s: failed to set freq to " 178*0a51b27eSJohannes Berg "%d MHz for scan\n", wiphy_name(local->hw.wiphy), 179*0a51b27eSJohannes Berg chan->center_freq); 180*0a51b27eSJohannes Berg skip = 1; 181*0a51b27eSJohannes Berg } 182*0a51b27eSJohannes Berg } 183*0a51b27eSJohannes Berg 184*0a51b27eSJohannes Berg /* advance state machine to next channel/band */ 185*0a51b27eSJohannes Berg local->scan_channel_idx++; 186*0a51b27eSJohannes Berg if (local->scan_channel_idx >= sband->n_channels) { 187*0a51b27eSJohannes Berg /* 188*0a51b27eSJohannes Berg * scan_band may end up == IEEE80211_NUM_BANDS, but 189*0a51b27eSJohannes Berg * we'll catch that case above and complete the scan 190*0a51b27eSJohannes Berg * if that is the case. 191*0a51b27eSJohannes Berg */ 192*0a51b27eSJohannes Berg local->scan_band++; 193*0a51b27eSJohannes Berg local->scan_channel_idx = 0; 194*0a51b27eSJohannes Berg } 195*0a51b27eSJohannes Berg 196*0a51b27eSJohannes Berg if (skip) 197*0a51b27eSJohannes Berg break; 198*0a51b27eSJohannes Berg 199*0a51b27eSJohannes Berg next_delay = IEEE80211_PROBE_DELAY + 200*0a51b27eSJohannes Berg usecs_to_jiffies(local->hw.channel_change_time); 201*0a51b27eSJohannes Berg local->scan_state = SCAN_SEND_PROBE; 202*0a51b27eSJohannes Berg break; 203*0a51b27eSJohannes Berg case SCAN_SEND_PROBE: 204*0a51b27eSJohannes Berg next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; 205*0a51b27eSJohannes Berg local->scan_state = SCAN_SET_CHANNEL; 206*0a51b27eSJohannes Berg 207*0a51b27eSJohannes Berg if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN) 208*0a51b27eSJohannes Berg break; 209*0a51b27eSJohannes Berg ieee80211_send_probe_req(sdata, NULL, local->scan_ssid, 210*0a51b27eSJohannes Berg local->scan_ssid_len); 211*0a51b27eSJohannes Berg next_delay = IEEE80211_CHANNEL_TIME; 212*0a51b27eSJohannes Berg break; 213*0a51b27eSJohannes Berg } 214*0a51b27eSJohannes Berg 215*0a51b27eSJohannes Berg if (local->sta_sw_scanning) 216*0a51b27eSJohannes Berg queue_delayed_work(local->hw.workqueue, &local->scan_work, 217*0a51b27eSJohannes Berg next_delay); 218*0a51b27eSJohannes Berg } 219*0a51b27eSJohannes Berg 220*0a51b27eSJohannes Berg 221*0a51b27eSJohannes Berg int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *scan_sdata, 222*0a51b27eSJohannes Berg u8 *ssid, size_t ssid_len) 223*0a51b27eSJohannes Berg { 224*0a51b27eSJohannes Berg struct ieee80211_local *local = scan_sdata->local; 225*0a51b27eSJohannes Berg struct ieee80211_sub_if_data *sdata; 226*0a51b27eSJohannes Berg 227*0a51b27eSJohannes Berg if (ssid_len > IEEE80211_MAX_SSID_LEN) 228*0a51b27eSJohannes Berg return -EINVAL; 229*0a51b27eSJohannes Berg 230*0a51b27eSJohannes Berg /* MLME-SCAN.request (page 118) page 144 (11.1.3.1) 231*0a51b27eSJohannes Berg * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS 232*0a51b27eSJohannes Berg * BSSID: MACAddress 233*0a51b27eSJohannes Berg * SSID 234*0a51b27eSJohannes Berg * ScanType: ACTIVE, PASSIVE 235*0a51b27eSJohannes Berg * ProbeDelay: delay (in microseconds) to be used prior to transmitting 236*0a51b27eSJohannes Berg * a Probe frame during active scanning 237*0a51b27eSJohannes Berg * ChannelList 238*0a51b27eSJohannes Berg * MinChannelTime (>= ProbeDelay), in TU 239*0a51b27eSJohannes Berg * MaxChannelTime: (>= MinChannelTime), in TU 240*0a51b27eSJohannes Berg */ 241*0a51b27eSJohannes Berg 242*0a51b27eSJohannes Berg /* MLME-SCAN.confirm 243*0a51b27eSJohannes Berg * BSSDescriptionSet 244*0a51b27eSJohannes Berg * ResultCode: SUCCESS, INVALID_PARAMETERS 245*0a51b27eSJohannes Berg */ 246*0a51b27eSJohannes Berg 247*0a51b27eSJohannes Berg if (local->sta_sw_scanning || local->sta_hw_scanning) { 248*0a51b27eSJohannes Berg if (local->scan_sdata == scan_sdata) 249*0a51b27eSJohannes Berg return 0; 250*0a51b27eSJohannes Berg return -EBUSY; 251*0a51b27eSJohannes Berg } 252*0a51b27eSJohannes Berg 253*0a51b27eSJohannes Berg if (local->ops->hw_scan) { 254*0a51b27eSJohannes Berg int rc = local->ops->hw_scan(local_to_hw(local), 255*0a51b27eSJohannes Berg ssid, ssid_len); 256*0a51b27eSJohannes Berg if (!rc) { 257*0a51b27eSJohannes Berg local->sta_hw_scanning = 1; 258*0a51b27eSJohannes Berg local->scan_sdata = scan_sdata; 259*0a51b27eSJohannes Berg } 260*0a51b27eSJohannes Berg return rc; 261*0a51b27eSJohannes Berg } 262*0a51b27eSJohannes Berg 263*0a51b27eSJohannes Berg local->sta_sw_scanning = 1; 264*0a51b27eSJohannes Berg 265*0a51b27eSJohannes Berg rcu_read_lock(); 266*0a51b27eSJohannes Berg list_for_each_entry_rcu(sdata, &local->interfaces, list) { 267*0a51b27eSJohannes Berg if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { 268*0a51b27eSJohannes Berg if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { 269*0a51b27eSJohannes Berg netif_tx_stop_all_queues(sdata->dev); 270*0a51b27eSJohannes Berg ieee80211_send_nullfunc(local, sdata, 1); 271*0a51b27eSJohannes Berg } 272*0a51b27eSJohannes Berg } else 273*0a51b27eSJohannes Berg netif_tx_stop_all_queues(sdata->dev); 274*0a51b27eSJohannes Berg } 275*0a51b27eSJohannes Berg rcu_read_unlock(); 276*0a51b27eSJohannes Berg 277*0a51b27eSJohannes Berg if (ssid) { 278*0a51b27eSJohannes Berg local->scan_ssid_len = ssid_len; 279*0a51b27eSJohannes Berg memcpy(local->scan_ssid, ssid, ssid_len); 280*0a51b27eSJohannes Berg } else 281*0a51b27eSJohannes Berg local->scan_ssid_len = 0; 282*0a51b27eSJohannes Berg local->scan_state = SCAN_SET_CHANNEL; 283*0a51b27eSJohannes Berg local->scan_channel_idx = 0; 284*0a51b27eSJohannes Berg local->scan_band = IEEE80211_BAND_2GHZ; 285*0a51b27eSJohannes Berg local->scan_sdata = scan_sdata; 286*0a51b27eSJohannes Berg 287*0a51b27eSJohannes Berg netif_addr_lock_bh(local->mdev); 288*0a51b27eSJohannes Berg local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; 289*0a51b27eSJohannes Berg local->ops->configure_filter(local_to_hw(local), 290*0a51b27eSJohannes Berg FIF_BCN_PRBRESP_PROMISC, 291*0a51b27eSJohannes Berg &local->filter_flags, 292*0a51b27eSJohannes Berg local->mdev->mc_count, 293*0a51b27eSJohannes Berg local->mdev->mc_list); 294*0a51b27eSJohannes Berg netif_addr_unlock_bh(local->mdev); 295*0a51b27eSJohannes Berg 296*0a51b27eSJohannes Berg /* TODO: start scan as soon as all nullfunc frames are ACKed */ 297*0a51b27eSJohannes Berg queue_delayed_work(local->hw.workqueue, &local->scan_work, 298*0a51b27eSJohannes Berg IEEE80211_CHANNEL_TIME); 299*0a51b27eSJohannes Berg 300*0a51b27eSJohannes Berg return 0; 301*0a51b27eSJohannes Berg } 302*0a51b27eSJohannes Berg 303*0a51b27eSJohannes Berg 304*0a51b27eSJohannes Berg int ieee80211_sta_req_scan(struct ieee80211_sub_if_data *sdata, u8 *ssid, size_t ssid_len) 305*0a51b27eSJohannes Berg { 306*0a51b27eSJohannes Berg struct ieee80211_if_sta *ifsta = &sdata->u.sta; 307*0a51b27eSJohannes Berg struct ieee80211_local *local = sdata->local; 308*0a51b27eSJohannes Berg 309*0a51b27eSJohannes Berg if (sdata->vif.type != IEEE80211_IF_TYPE_STA) 310*0a51b27eSJohannes Berg return ieee80211_sta_start_scan(sdata, ssid, ssid_len); 311*0a51b27eSJohannes Berg 312*0a51b27eSJohannes Berg if (local->sta_sw_scanning || local->sta_hw_scanning) { 313*0a51b27eSJohannes Berg if (local->scan_sdata == sdata) 314*0a51b27eSJohannes Berg return 0; 315*0a51b27eSJohannes Berg return -EBUSY; 316*0a51b27eSJohannes Berg } 317*0a51b27eSJohannes Berg 318*0a51b27eSJohannes Berg ifsta->scan_ssid_len = ssid_len; 319*0a51b27eSJohannes Berg if (ssid_len) 320*0a51b27eSJohannes Berg memcpy(ifsta->scan_ssid, ssid, ssid_len); 321*0a51b27eSJohannes Berg set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request); 322*0a51b27eSJohannes Berg queue_work(local->hw.workqueue, &ifsta->work); 323*0a51b27eSJohannes Berg return 0; 324*0a51b27eSJohannes Berg } 325*0a51b27eSJohannes Berg 326*0a51b27eSJohannes Berg 327*0a51b27eSJohannes Berg static void ieee80211_sta_add_scan_ies(struct iw_request_info *info, 328*0a51b27eSJohannes Berg struct ieee80211_sta_bss *bss, 329*0a51b27eSJohannes Berg char **current_ev, char *end_buf) 330*0a51b27eSJohannes Berg { 331*0a51b27eSJohannes Berg u8 *pos, *end, *next; 332*0a51b27eSJohannes Berg struct iw_event iwe; 333*0a51b27eSJohannes Berg 334*0a51b27eSJohannes Berg if (bss == NULL || bss->ies == NULL) 335*0a51b27eSJohannes Berg return; 336*0a51b27eSJohannes Berg 337*0a51b27eSJohannes Berg /* 338*0a51b27eSJohannes Berg * If needed, fragment the IEs buffer (at IE boundaries) into short 339*0a51b27eSJohannes Berg * enough fragments to fit into IW_GENERIC_IE_MAX octet messages. 340*0a51b27eSJohannes Berg */ 341*0a51b27eSJohannes Berg pos = bss->ies; 342*0a51b27eSJohannes Berg end = pos + bss->ies_len; 343*0a51b27eSJohannes Berg 344*0a51b27eSJohannes Berg while (end - pos > IW_GENERIC_IE_MAX) { 345*0a51b27eSJohannes Berg next = pos + 2 + pos[1]; 346*0a51b27eSJohannes Berg while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX) 347*0a51b27eSJohannes Berg next = next + 2 + next[1]; 348*0a51b27eSJohannes Berg 349*0a51b27eSJohannes Berg memset(&iwe, 0, sizeof(iwe)); 350*0a51b27eSJohannes Berg iwe.cmd = IWEVGENIE; 351*0a51b27eSJohannes Berg iwe.u.data.length = next - pos; 352*0a51b27eSJohannes Berg *current_ev = iwe_stream_add_point(info, *current_ev, 353*0a51b27eSJohannes Berg end_buf, &iwe, pos); 354*0a51b27eSJohannes Berg 355*0a51b27eSJohannes Berg pos = next; 356*0a51b27eSJohannes Berg } 357*0a51b27eSJohannes Berg 358*0a51b27eSJohannes Berg if (end > pos) { 359*0a51b27eSJohannes Berg memset(&iwe, 0, sizeof(iwe)); 360*0a51b27eSJohannes Berg iwe.cmd = IWEVGENIE; 361*0a51b27eSJohannes Berg iwe.u.data.length = end - pos; 362*0a51b27eSJohannes Berg *current_ev = iwe_stream_add_point(info, *current_ev, 363*0a51b27eSJohannes Berg end_buf, &iwe, pos); 364*0a51b27eSJohannes Berg } 365*0a51b27eSJohannes Berg } 366*0a51b27eSJohannes Berg 367*0a51b27eSJohannes Berg 368*0a51b27eSJohannes Berg static char * 369*0a51b27eSJohannes Berg ieee80211_sta_scan_result(struct ieee80211_local *local, 370*0a51b27eSJohannes Berg struct iw_request_info *info, 371*0a51b27eSJohannes Berg struct ieee80211_sta_bss *bss, 372*0a51b27eSJohannes Berg char *current_ev, char *end_buf) 373*0a51b27eSJohannes Berg { 374*0a51b27eSJohannes Berg struct iw_event iwe; 375*0a51b27eSJohannes Berg char *buf; 376*0a51b27eSJohannes Berg 377*0a51b27eSJohannes Berg if (time_after(jiffies, 378*0a51b27eSJohannes Berg bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE)) 379*0a51b27eSJohannes Berg return current_ev; 380*0a51b27eSJohannes Berg 381*0a51b27eSJohannes Berg memset(&iwe, 0, sizeof(iwe)); 382*0a51b27eSJohannes Berg iwe.cmd = SIOCGIWAP; 383*0a51b27eSJohannes Berg iwe.u.ap_addr.sa_family = ARPHRD_ETHER; 384*0a51b27eSJohannes Berg memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); 385*0a51b27eSJohannes Berg current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, 386*0a51b27eSJohannes Berg IW_EV_ADDR_LEN); 387*0a51b27eSJohannes Berg 388*0a51b27eSJohannes Berg memset(&iwe, 0, sizeof(iwe)); 389*0a51b27eSJohannes Berg iwe.cmd = SIOCGIWESSID; 390*0a51b27eSJohannes Berg if (bss_mesh_cfg(bss)) { 391*0a51b27eSJohannes Berg iwe.u.data.length = bss_mesh_id_len(bss); 392*0a51b27eSJohannes Berg iwe.u.data.flags = 1; 393*0a51b27eSJohannes Berg current_ev = iwe_stream_add_point(info, current_ev, end_buf, 394*0a51b27eSJohannes Berg &iwe, bss_mesh_id(bss)); 395*0a51b27eSJohannes Berg } else { 396*0a51b27eSJohannes Berg iwe.u.data.length = bss->ssid_len; 397*0a51b27eSJohannes Berg iwe.u.data.flags = 1; 398*0a51b27eSJohannes Berg current_ev = iwe_stream_add_point(info, current_ev, end_buf, 399*0a51b27eSJohannes Berg &iwe, bss->ssid); 400*0a51b27eSJohannes Berg } 401*0a51b27eSJohannes Berg 402*0a51b27eSJohannes Berg if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) 403*0a51b27eSJohannes Berg || bss_mesh_cfg(bss)) { 404*0a51b27eSJohannes Berg memset(&iwe, 0, sizeof(iwe)); 405*0a51b27eSJohannes Berg iwe.cmd = SIOCGIWMODE; 406*0a51b27eSJohannes Berg if (bss_mesh_cfg(bss)) 407*0a51b27eSJohannes Berg iwe.u.mode = IW_MODE_MESH; 408*0a51b27eSJohannes Berg else if (bss->capability & WLAN_CAPABILITY_ESS) 409*0a51b27eSJohannes Berg iwe.u.mode = IW_MODE_MASTER; 410*0a51b27eSJohannes Berg else 411*0a51b27eSJohannes Berg iwe.u.mode = IW_MODE_ADHOC; 412*0a51b27eSJohannes Berg current_ev = iwe_stream_add_event(info, current_ev, end_buf, 413*0a51b27eSJohannes Berg &iwe, IW_EV_UINT_LEN); 414*0a51b27eSJohannes Berg } 415*0a51b27eSJohannes Berg 416*0a51b27eSJohannes Berg memset(&iwe, 0, sizeof(iwe)); 417*0a51b27eSJohannes Berg iwe.cmd = SIOCGIWFREQ; 418*0a51b27eSJohannes Berg iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq); 419*0a51b27eSJohannes Berg iwe.u.freq.e = 0; 420*0a51b27eSJohannes Berg current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, 421*0a51b27eSJohannes Berg IW_EV_FREQ_LEN); 422*0a51b27eSJohannes Berg 423*0a51b27eSJohannes Berg memset(&iwe, 0, sizeof(iwe)); 424*0a51b27eSJohannes Berg iwe.cmd = SIOCGIWFREQ; 425*0a51b27eSJohannes Berg iwe.u.freq.m = bss->freq; 426*0a51b27eSJohannes Berg iwe.u.freq.e = 6; 427*0a51b27eSJohannes Berg current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, 428*0a51b27eSJohannes Berg IW_EV_FREQ_LEN); 429*0a51b27eSJohannes Berg memset(&iwe, 0, sizeof(iwe)); 430*0a51b27eSJohannes Berg iwe.cmd = IWEVQUAL; 431*0a51b27eSJohannes Berg iwe.u.qual.qual = bss->qual; 432*0a51b27eSJohannes Berg iwe.u.qual.level = bss->signal; 433*0a51b27eSJohannes Berg iwe.u.qual.noise = bss->noise; 434*0a51b27eSJohannes Berg iwe.u.qual.updated = local->wstats_flags; 435*0a51b27eSJohannes Berg current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, 436*0a51b27eSJohannes Berg IW_EV_QUAL_LEN); 437*0a51b27eSJohannes Berg 438*0a51b27eSJohannes Berg memset(&iwe, 0, sizeof(iwe)); 439*0a51b27eSJohannes Berg iwe.cmd = SIOCGIWENCODE; 440*0a51b27eSJohannes Berg if (bss->capability & WLAN_CAPABILITY_PRIVACY) 441*0a51b27eSJohannes Berg iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; 442*0a51b27eSJohannes Berg else 443*0a51b27eSJohannes Berg iwe.u.data.flags = IW_ENCODE_DISABLED; 444*0a51b27eSJohannes Berg iwe.u.data.length = 0; 445*0a51b27eSJohannes Berg current_ev = iwe_stream_add_point(info, current_ev, end_buf, 446*0a51b27eSJohannes Berg &iwe, ""); 447*0a51b27eSJohannes Berg 448*0a51b27eSJohannes Berg ieee80211_sta_add_scan_ies(info, bss, ¤t_ev, end_buf); 449*0a51b27eSJohannes Berg 450*0a51b27eSJohannes Berg if (bss->supp_rates_len > 0) { 451*0a51b27eSJohannes Berg /* display all supported rates in readable format */ 452*0a51b27eSJohannes Berg char *p = current_ev + iwe_stream_lcp_len(info); 453*0a51b27eSJohannes Berg int i; 454*0a51b27eSJohannes Berg 455*0a51b27eSJohannes Berg memset(&iwe, 0, sizeof(iwe)); 456*0a51b27eSJohannes Berg iwe.cmd = SIOCGIWRATE; 457*0a51b27eSJohannes Berg /* Those two flags are ignored... */ 458*0a51b27eSJohannes Berg iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; 459*0a51b27eSJohannes Berg 460*0a51b27eSJohannes Berg for (i = 0; i < bss->supp_rates_len; i++) { 461*0a51b27eSJohannes Berg iwe.u.bitrate.value = ((bss->supp_rates[i] & 462*0a51b27eSJohannes Berg 0x7f) * 500000); 463*0a51b27eSJohannes Berg p = iwe_stream_add_value(info, current_ev, p, 464*0a51b27eSJohannes Berg end_buf, &iwe, IW_EV_PARAM_LEN); 465*0a51b27eSJohannes Berg } 466*0a51b27eSJohannes Berg current_ev = p; 467*0a51b27eSJohannes Berg } 468*0a51b27eSJohannes Berg 469*0a51b27eSJohannes Berg buf = kmalloc(30, GFP_ATOMIC); 470*0a51b27eSJohannes Berg if (buf) { 471*0a51b27eSJohannes Berg memset(&iwe, 0, sizeof(iwe)); 472*0a51b27eSJohannes Berg iwe.cmd = IWEVCUSTOM; 473*0a51b27eSJohannes Berg sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp)); 474*0a51b27eSJohannes Berg iwe.u.data.length = strlen(buf); 475*0a51b27eSJohannes Berg current_ev = iwe_stream_add_point(info, current_ev, end_buf, 476*0a51b27eSJohannes Berg &iwe, buf); 477*0a51b27eSJohannes Berg memset(&iwe, 0, sizeof(iwe)); 478*0a51b27eSJohannes Berg iwe.cmd = IWEVCUSTOM; 479*0a51b27eSJohannes Berg sprintf(buf, " Last beacon: %dms ago", 480*0a51b27eSJohannes Berg jiffies_to_msecs(jiffies - bss->last_update)); 481*0a51b27eSJohannes Berg iwe.u.data.length = strlen(buf); 482*0a51b27eSJohannes Berg current_ev = iwe_stream_add_point(info, current_ev, 483*0a51b27eSJohannes Berg end_buf, &iwe, buf); 484*0a51b27eSJohannes Berg kfree(buf); 485*0a51b27eSJohannes Berg } 486*0a51b27eSJohannes Berg 487*0a51b27eSJohannes Berg if (bss_mesh_cfg(bss)) { 488*0a51b27eSJohannes Berg u8 *cfg = bss_mesh_cfg(bss); 489*0a51b27eSJohannes Berg buf = kmalloc(50, GFP_ATOMIC); 490*0a51b27eSJohannes Berg if (buf) { 491*0a51b27eSJohannes Berg memset(&iwe, 0, sizeof(iwe)); 492*0a51b27eSJohannes Berg iwe.cmd = IWEVCUSTOM; 493*0a51b27eSJohannes Berg sprintf(buf, "Mesh network (version %d)", cfg[0]); 494*0a51b27eSJohannes Berg iwe.u.data.length = strlen(buf); 495*0a51b27eSJohannes Berg current_ev = iwe_stream_add_point(info, current_ev, 496*0a51b27eSJohannes Berg end_buf, 497*0a51b27eSJohannes Berg &iwe, buf); 498*0a51b27eSJohannes Berg sprintf(buf, "Path Selection Protocol ID: " 499*0a51b27eSJohannes Berg "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], 500*0a51b27eSJohannes Berg cfg[4]); 501*0a51b27eSJohannes Berg iwe.u.data.length = strlen(buf); 502*0a51b27eSJohannes Berg current_ev = iwe_stream_add_point(info, current_ev, 503*0a51b27eSJohannes Berg end_buf, 504*0a51b27eSJohannes Berg &iwe, buf); 505*0a51b27eSJohannes Berg sprintf(buf, "Path Selection Metric ID: " 506*0a51b27eSJohannes Berg "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], 507*0a51b27eSJohannes Berg cfg[8]); 508*0a51b27eSJohannes Berg iwe.u.data.length = strlen(buf); 509*0a51b27eSJohannes Berg current_ev = iwe_stream_add_point(info, current_ev, 510*0a51b27eSJohannes Berg end_buf, 511*0a51b27eSJohannes Berg &iwe, buf); 512*0a51b27eSJohannes Berg sprintf(buf, "Congestion Control Mode ID: " 513*0a51b27eSJohannes Berg "0x%02X%02X%02X%02X", cfg[9], cfg[10], 514*0a51b27eSJohannes Berg cfg[11], cfg[12]); 515*0a51b27eSJohannes Berg iwe.u.data.length = strlen(buf); 516*0a51b27eSJohannes Berg current_ev = iwe_stream_add_point(info, current_ev, 517*0a51b27eSJohannes Berg end_buf, 518*0a51b27eSJohannes Berg &iwe, buf); 519*0a51b27eSJohannes Berg sprintf(buf, "Channel Precedence: " 520*0a51b27eSJohannes Berg "0x%02X%02X%02X%02X", cfg[13], cfg[14], 521*0a51b27eSJohannes Berg cfg[15], cfg[16]); 522*0a51b27eSJohannes Berg iwe.u.data.length = strlen(buf); 523*0a51b27eSJohannes Berg current_ev = iwe_stream_add_point(info, current_ev, 524*0a51b27eSJohannes Berg end_buf, 525*0a51b27eSJohannes Berg &iwe, buf); 526*0a51b27eSJohannes Berg kfree(buf); 527*0a51b27eSJohannes Berg } 528*0a51b27eSJohannes Berg } 529*0a51b27eSJohannes Berg 530*0a51b27eSJohannes Berg return current_ev; 531*0a51b27eSJohannes Berg } 532*0a51b27eSJohannes Berg 533*0a51b27eSJohannes Berg 534*0a51b27eSJohannes Berg int ieee80211_sta_scan_results(struct ieee80211_local *local, 535*0a51b27eSJohannes Berg struct iw_request_info *info, 536*0a51b27eSJohannes Berg char *buf, size_t len) 537*0a51b27eSJohannes Berg { 538*0a51b27eSJohannes Berg char *current_ev = buf; 539*0a51b27eSJohannes Berg char *end_buf = buf + len; 540*0a51b27eSJohannes Berg struct ieee80211_sta_bss *bss; 541*0a51b27eSJohannes Berg 542*0a51b27eSJohannes Berg spin_lock_bh(&local->sta_bss_lock); 543*0a51b27eSJohannes Berg list_for_each_entry(bss, &local->sta_bss_list, list) { 544*0a51b27eSJohannes Berg if (buf + len - current_ev <= IW_EV_ADDR_LEN) { 545*0a51b27eSJohannes Berg spin_unlock_bh(&local->sta_bss_lock); 546*0a51b27eSJohannes Berg return -E2BIG; 547*0a51b27eSJohannes Berg } 548*0a51b27eSJohannes Berg current_ev = ieee80211_sta_scan_result(local, info, bss, 549*0a51b27eSJohannes Berg current_ev, end_buf); 550*0a51b27eSJohannes Berg } 551*0a51b27eSJohannes Berg spin_unlock_bh(&local->sta_bss_lock); 552*0a51b27eSJohannes Berg return current_ev - buf; 553*0a51b27eSJohannes Berg } 554