skb_reserve(skb, sdata->local->hw.extra_tx_headroom);
if (!ether_addr_equal(ifibss->bssid, bssid))
- sta_info_flush(sdata->local, sdata);
+ sta_info_flush(sdata);
/* if merging, indicate to driver that we leave the old IBSS */
if (sdata->vif.bss_conf.ibss_joined) {
rcu_assign_pointer(ifibss->presp, skb);
+ sdata->vif.bss_conf.enable_beacon = true;
sdata->vif.bss_conf.beacon_int = beacon_int;
sdata->vif.bss_conf.basic_rates = basic_rates;
bss_change = BSS_CHANGED_BEACON_INT;
bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan,
mgmt, skb->len, 0, GFP_KERNEL);
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(local->hw.wiphy, bss);
netif_carrier_on(sdata->dev);
cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
}
u32 basic_rates;
int i, j;
u16 beacon_int = cbss->beacon_interval;
+ const struct cfg80211_bss_ies *ies;
+ u64 tsf;
lockdep_assert_held(&sdata->u.ibss.mtx);
}
}
+ rcu_read_lock();
+ ies = rcu_dereference(cbss->ies);
+ tsf = ies->tsf;
+ rcu_read_unlock();
+
__ieee80211_sta_join_ibss(sdata, cbss->bssid,
beacon_int,
cbss->channel,
basic_rates,
cbss->capability,
- cbss->tsf,
- false);
+ tsf, false);
}
static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
"TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n",
sdata->vif.addr, addr, sdata->u.ibss.bssid);
ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, 0, NULL, 0,
- addr, sdata->u.ibss.bssid, NULL, 0, 0);
+ addr, sdata->u.ibss.bssid, NULL, 0, 0, 0);
}
return sta;
}
* has actually implemented this.
*/
ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, 0, NULL, 0,
- mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0);
+ mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0, 0);
}
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt,
- size_t len,
+ struct ieee80211_mgmt *mgmt, size_t len,
struct ieee80211_rx_status *rx_status,
- struct ieee802_11_elems *elems,
- bool beacon)
+ struct ieee802_11_elems *elems)
{
struct ieee80211_local *local = sdata->local;
int freq;
if (sta && elems->ht_operation && elems->ht_cap_elem &&
sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) {
/* we both use HT */
- struct ieee80211_sta_ht_cap sta_ht_cap_new;
+ struct ieee80211_ht_cap htcap_ie;
struct cfg80211_chan_def chandef;
ieee80211_ht_oper_to_chandef(channel,
elems->ht_operation,
&chandef);
- ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
- elems->ht_cap_elem,
- &sta_ht_cap_new);
+ memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
/*
* fall back to HT20 if we don't use or use
* the other extension channel
*/
- if (chandef.width != NL80211_CHAN_WIDTH_40 ||
- cfg80211_get_chandef_type(&chandef) !=
+ if (cfg80211_get_chandef_type(&chandef) !=
sdata->u.ibss.channel_type)
- sta_ht_cap_new.cap &=
- ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-
- if (memcmp(&sta->sta.ht_cap, &sta_ht_cap_new,
- sizeof(sta_ht_cap_new))) {
- memcpy(&sta->sta.ht_cap, &sta_ht_cap_new,
- sizeof(sta_ht_cap_new));
- rates_updated = true;
- }
+ htcap_ie.cap_info &=
+ cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40);
+
+ rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(
+ sdata, sband, &htcap_ie, sta);
}
if (sta && rates_updated) {
}
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
- channel, beacon);
+ channel);
if (!bss)
return;
cbss = container_of((void *)bss, struct cfg80211_bss, priv);
- /* was just updated in ieee80211_bss_info_update */
- beacon_timestamp = cbss->tsf;
+ /* same for beacon and probe response */
+ beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
/* check if we need to merge IBSS */
ieee80211_tx_skb(sdata, skb);
}
-static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt,
- size_t len,
- struct ieee80211_rx_status *rx_status)
+static
+void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt, size_t len,
+ struct ieee80211_rx_status *rx_status)
{
size_t baselen;
struct ieee802_11_elems elems;
+ BUILD_BUG_ON(offsetof(typeof(mgmt->u.probe_resp), variable) !=
+ offsetof(typeof(mgmt->u.beacon), variable));
+
+ /*
+ * either beacon or probe_resp but the variable field is at the
+ * same offset
+ */
baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
if (baselen > len)
return;
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
&elems);
- ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
-}
-
-static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt,
- size_t len,
- struct ieee80211_rx_status *rx_status)
-{
- size_t baselen;
- struct ieee802_11_elems elems;
-
- /* Process beacon from the current BSS */
- baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
- if (baselen > len)
- return;
-
- ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
-
- ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);
+ ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
}
void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
ieee80211_rx_mgmt_probe_req(sdata, skb);
break;
case IEEE80211_STYPE_PROBE_RESP:
- ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,
- rx_status);
- break;
case IEEE80211_STYPE_BEACON:
- ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
- rx_status);
+ ieee80211_rx_mgmt_probe_beacon(sdata, mgmt, skb->len,
+ rx_status);
break;
case IEEE80211_STYPE_AUTH:
ieee80211_rx_mgmt_auth_ibss(sdata, mgmt, skb->len);
mutex_unlock(&sdata->u.ibss.mtx);
- mutex_lock(&sdata->local->mtx);
- ieee80211_recalc_idle(sdata->local);
- mutex_unlock(&sdata->local->mtx);
-
/*
* 802.11n-2009 9.13.3.1: In an IBSS, the HT Protection field is
* reserved, but an HT STA shall protect HT transmissions as though
if (cbss) {
cfg80211_unlink_bss(local->hw.wiphy, cbss);
- cfg80211_put_bss(cbss);
+ cfg80211_put_bss(local->hw.wiphy, cbss);
}
}
memset(ifibss->bssid, 0, ETH_ALEN);
ifibss->ssid_len = 0;
- sta_info_flush(sdata->local, sdata);
+ sta_info_flush(sdata);
spin_lock_bh(&ifibss->incomplete_lock);
while (!list_empty(&ifibss->incomplete_stations)) {
RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
sdata->vif.bss_conf.ibss_joined = false;
sdata->vif.bss_conf.ibss_creator = false;
+ sdata->vif.bss_conf.enable_beacon = false;
+ clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
BSS_CHANGED_IBSS);
synchronize_rcu();
mutex_unlock(&sdata->u.ibss.mtx);
- mutex_lock(&local->mtx);
- ieee80211_recalc_idle(sdata->local);
- mutex_unlock(&local->mtx);
-
return 0;
}