#include <asm/unaligned.h>
#include "ieee80211_i.h"
+#include "driver-ops.h"
#include "rate.h"
#define IEEE80211_SCAN_INTERVAL (2 * HZ)
*/
if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)
ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0,
- sdata->u.ibss.bssid, 0);
+ sdata->u.ibss.bssid, NULL, 0, 0);
}
static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
const u8 *bssid, const int beacon_int,
struct ieee80211_channel *chan,
- const size_t supp_rates_len,
- const u8 *supp_rates,
+ const u32 basic_rates,
const u16 capability, u64 tsf)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
- int rates, i, j;
+ int rates, i;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos;
struct ieee80211_supported_band *sband;
+ struct cfg80211_bss *bss;
+ u32 bss_change;
+ u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
- if (local->ops->reset_tsf) {
- /* Reset own TSF to allow time synchronization work. */
- local->ops->reset_tsf(local_to_hw(local));
- }
+ /* Reset own TSF to allow time synchronization work. */
+ drv_reset_tsf(local);
skb = ifibss->skb;
rcu_assign_pointer(ifibss->presp, NULL);
memcpy(ifibss->bssid, bssid, ETH_ALEN);
- local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10;
-
sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
- ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
-
local->oper_channel = chan;
local->oper_channel_type = NL80211_CHAN_NO_HT;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+
sband = local->hw.wiphy->bands[chan->band];
+ /* build supported rates array */
+ pos = supp_rates;
+ for (i = 0; i < sband->n_bitrates; i++) {
+ int rate = sband->bitrates[i].bitrate;
+ u8 basic = 0;
+ if (basic_rates & BIT(i))
+ basic = 0x80;
+ *pos++ = basic | (u8) (rate / 5);
+ }
+
/* Build IBSS probe response */
mgmt = (void *) skb_put(skb, 24 + sizeof(mgmt->u.beacon));
memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
memset(mgmt->da, 0xff, ETH_ALEN);
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
- mgmt->u.beacon.beacon_int = cpu_to_le16(local->hw.conf.beacon_int);
+ mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int);
mgmt->u.beacon.timestamp = cpu_to_le64(tsf);
mgmt->u.beacon.capab_info = cpu_to_le16(capability);
*pos++ = ifibss->ssid_len;
memcpy(pos, ifibss->ssid, ifibss->ssid_len);
- rates = supp_rates_len;
+ rates = sband->n_bitrates;
if (rates > 8)
rates = 8;
pos = skb_put(skb, 2 + rates);
*pos++ = 0;
*pos++ = 0;
- if (supp_rates_len > 8) {
- rates = supp_rates_len - 8;
+ if (sband->n_bitrates > 8) {
+ rates = sband->n_bitrates - 8;
pos = skb_put(skb, 2 + rates);
*pos++ = WLAN_EID_EXT_SUPP_RATES;
*pos++ = rates;
rcu_assign_pointer(ifibss->presp, skb);
- ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON |
- IEEE80211_IFCC_BEACON_ENABLED);
-
- rates = 0;
- for (i = 0; i < supp_rates_len; i++) {
- int bitrate = (supp_rates[i] & 0x7f) * 5;
- for (j = 0; j < sband->n_bitrates; j++)
- if (sband->bitrates[j].bitrate == bitrate)
- rates |= BIT(j);
- }
+ sdata->vif.bss_conf.beacon_int = beacon_int;
+ bss_change = BSS_CHANGED_BEACON_INT;
+ bss_change |= ieee80211_reset_erp_info(sdata);
+ bss_change |= BSS_CHANGED_BSSID;
+ bss_change |= BSS_CHANGED_BEACON;
+ bss_change |= BSS_CHANGED_BEACON_ENABLED;
+ ieee80211_bss_info_change_notify(sdata, bss_change);
- ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates);
+ ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates);
ifibss->state = IEEE80211_IBSS_MLME_JOINED;
mod_timer(&ifibss->timer,
round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
- cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel,
- mgmt, skb->len, 0, GFP_KERNEL);
+ bss = cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel,
+ mgmt, skb->len, 0, GFP_KERNEL);
+ cfg80211_put_bss(bss);
cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
}
static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss *bss)
{
+ struct ieee80211_supported_band *sband;
+ u32 basic_rates;
+ int i, j;
+ u16 beacon_int = bss->cbss.beacon_interval;
+
+ if (beacon_int < 10)
+ beacon_int = 10;
+
+ sband = sdata->local->hw.wiphy->bands[bss->cbss.channel->band];
+
+ basic_rates = 0;
+
+ for (i = 0; i < bss->supp_rates_len; i++) {
+ int rate = (bss->supp_rates[i] & 0x7f) * 5;
+ bool is_basic = !!(bss->supp_rates[i] & 0x80);
+
+ for (j = 0; j < sband->n_bitrates; j++) {
+ if (sband->bitrates[j].bitrate == rate) {
+ if (is_basic)
+ basic_rates |= BIT(j);
+ break;
+ }
+ }
+ }
+
__ieee80211_sta_join_ibss(sdata, bss->cbss.bssid,
- bss->cbss.beacon_interval,
+ beacon_int,
bss->cbss.channel,
- bss->supp_rates_len, bss->supp_rates,
+ basic_rates,
bss->cbss.capability,
bss->cbss.tsf);
}
bitrates[rx_status->rate_idx].bitrate;
rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
- } else if (local && local->ops && local->ops->get_tsf)
- /* second best option: get current TSF */
- rx_timestamp = local->ops->get_tsf(local_to_hw(local));
- else
- /* can't merge without knowing the TSF */
- rx_timestamp = -1LLU;
+ } else {
+ /*
+ * second best option: get current TSF
+ * (will return -1 if not supported)
+ */
+ rx_timestamp = drv_get_tsf(local);
+ }
#ifdef CONFIG_MAC80211_IBSS_DEBUG
printk(KERN_DEBUG "RX beacon SA=%pM BSSID="
ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT);
+ if (time_before(jiffies, ifibss->last_scan_completed +
+ IEEE80211_IBSS_MERGE_INTERVAL))
+ return;
+
if (ieee80211_sta_active_ibss(sdata))
return;
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
- u8 *pos;
u8 bssid[ETH_ALEN];
- u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
u16 capability;
int i;
sband = local->hw.wiphy->bands[ifibss->channel->band];
- if (local->hw.conf.beacon_int == 0)
- local->hw.conf.beacon_int = 100;
-
capability = WLAN_CAPABILITY_IBSS;
- if (sdata->default_key)
+ if (ifibss->privacy)
capability |= WLAN_CAPABILITY_PRIVACY;
else
sdata->drop_unencrypted = 0;
- pos = supp_rates;
- for (i = 0; i < sband->n_bitrates; i++) {
- int rate = sband->bitrates[i].bitrate;
- *pos++ = (u8) (rate / 5);
- }
-
- __ieee80211_sta_join_ibss(sdata, bssid, local->hw.conf.beacon_int,
- ifibss->channel, sband->n_bitrates,
- supp_rates, capability, 0);
+ __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
+ ifibss->channel, 3, /* first two are basic */
+ capability, 0);
}
static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
struct ieee80211_channel *chan = NULL;
const u8 *bssid = NULL;
int active_ibss;
+ u16 capability;
active_ibss = ieee80211_sta_active_ibss(sdata);
#ifdef CONFIG_MAC80211_IBSS_DEBUG
if (active_ibss)
return;
+ capability = WLAN_CAPABILITY_IBSS;
+ if (ifibss->privacy)
+ capability |= WLAN_CAPABILITY_PRIVACY;
if (ifibss->fixed_bssid)
bssid = ifibss->bssid;
if (ifibss->fixed_channel)
bssid = ifibss->bssid;
bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid,
ifibss->ssid, ifibss->ssid_len,
- WLAN_CAPABILITY_IBSS,
- WLAN_CAPABILITY_IBSS);
+ WLAN_CAPABILITY_IBSS |
+ WLAN_CAPABILITY_PRIVACY,
+ capability);
+ if (bss) {
#ifdef CONFIG_MAC80211_IBSS_DEBUG
- if (bss)
printk(KERN_DEBUG " sta_find_ibss: selected %pM current "
"%pM\n", bss->cbss.bssid, ifibss->bssid);
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- if (bss && memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN)) {
printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
" based on configured SSID\n",
sdata->dev->name, bss->cbss.bssid);
ieee80211_sta_join_ibss(sdata, bss);
ieee80211_rx_bss_put(local, bss);
return;
- } else if (bss)
- ieee80211_rx_bss_put(local, bss);
+ }
#ifdef CONFIG_MAC80211_IBSS_DEBUG
printk(KERN_DEBUG " did not try to join ibss\n");
len < 24 + 2 || !ifibss->presp)
return;
- if (local->ops->tx_last_beacon)
- tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local));
- else
- tx_last_beacon = 1;
+ tx_last_beacon = drv_tx_last_beacon(local);
#ifdef CONFIG_MAC80211_IBSS_DEBUG
printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM"
printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
sdata->dev->name, resp->da);
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- ieee80211_tx_skb(sdata, skb, 0);
+ IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+ ieee80211_tx_skb(sdata, skb);
}
static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt;
u16 fc;
- rx_status = (struct ieee80211_rx_status *) skb->cb;
+ rx_status = IEEE80211_SKB_RXCB(skb);
mgmt = (struct ieee80211_mgmt *) skb->data;
fc = le16_to_cpu(mgmt->frame_control);
struct ieee80211_if_ibss *ifibss;
struct sk_buff *skb;
+ if (WARN_ON(local->suspended))
+ return;
+
if (!netif_running(sdata->dev))
return;
- if (local->sw_scanning || local->hw_scanning)
+ if (local->scanning)
return;
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC))
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
+ if (local->quiescing) {
+ ifibss->timer_running = true;
+ return;
+ }
+
set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request);
- queue_work(local->hw.workqueue, &ifibss->work);
+ ieee80211_queue_work(&local->hw, &ifibss->work);
+}
+
+#ifdef CONFIG_PM
+void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+ cancel_work_sync(&ifibss->work);
+ if (del_timer_sync(&ifibss->timer))
+ ifibss->timer_running = true;
+}
+
+void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+ if (ifibss->timer_running) {
+ add_timer(&ifibss->timer);
+ ifibss->timer_running = false;
+ }
}
+#endif
void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
{
if (!sdata->u.ibss.ssid_len)
continue;
sdata->u.ibss.last_scan_completed = jiffies;
- ieee80211_sta_find_ibss(sdata);
+ mod_timer(&sdata->u.ibss.timer, 0);
}
mutex_unlock(&local->iflist_mtx);
}
ieee80211_rx_result
-ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
- struct ieee80211_rx_status *rx_status)
+ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_mgmt *mgmt;
switch (fc & IEEE80211_FCTL_STYPE) {
case IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_STYPE_BEACON:
- memcpy(skb->cb, rx_status, sizeof(*rx_status));
case IEEE80211_STYPE_PROBE_REQ:
case IEEE80211_STYPE_AUTH:
skb_queue_tail(&sdata->u.ibss.skb_queue, skb);
- queue_work(local->hw.workqueue, &sdata->u.ibss.work);
+ ieee80211_queue_work(&local->hw, &sdata->u.ibss.work);
return RX_QUEUED;
}
} else
sdata->u.ibss.fixed_bssid = false;
+ sdata->u.ibss.privacy = params->privacy;
+
+ sdata->vif.bss_conf.beacon_int = params->beacon_interval;
+
sdata->u.ibss.channel = params->channel;
sdata->u.ibss.fixed_channel = params->channel_fixed;
sdata->u.ibss.ssid_len = params->ssid_len;
+ ieee80211_recalc_idle(sdata->local);
+
set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
- queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->u.ibss.work);
return 0;
}
kfree(sdata->u.ibss.ie);
skb = sdata->u.ibss.presp;
rcu_assign_pointer(sdata->u.ibss.presp, NULL);
- ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED);
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
synchronize_rcu();
kfree_skb(skb);
skb_queue_purge(&sdata->u.ibss.skb_queue);
memset(sdata->u.ibss.bssid, 0, ETH_ALEN);
+ sdata->u.ibss.ssid_len = 0;
+
+ ieee80211_recalc_idle(sdata->local);
return 0;
}