pos = ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap); /* * Note: According to 802.11n-2009 9.13.3.1, HT Protection * field and RIFS Mode are reserved in IBSS mode, therefore * keep them at 0
*/
pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
chandef, 0, false);
/* Reset own TSF to allow time synchronization work. */
drv_reset_tsf(local, sdata);
if (!ether_addr_equal(ifibss->bssid, bssid))
sta_info_flush(sdata, -1);
/* if merging, indicate to driver that we leave the old IBSS */ if (sdata->vif.cfg.ibss_joined) {
sdata->vif.cfg.ibss_joined = false;
sdata->vif.cfg.ibss_creator = false;
sdata->vif.bss_conf.enable_beacon = false;
netif_carrier_off(sdata->dev);
synchronize_net();
ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_IBSS |
BSS_CHANGED_BEACON_ENABLED);
drv_leave_ibss(local, sdata);
}
presp = sdata_dereference(ifibss->presp, sdata);
RCU_INIT_POINTER(ifibss->presp, NULL); if (presp)
kfree_rcu(presp, rcu_head);
/* make a copy of the chandef, it could be modified below. */
chanreq.oper = *req_chandef;
chan = chanreq.oper.chan; if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chanreq.oper,
NL80211_IFTYPE_ADHOC)) { if (chanreq.oper.width == NL80211_CHAN_WIDTH_5 ||
chanreq.oper.width == NL80211_CHAN_WIDTH_10 ||
chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT ||
chanreq.oper.width == NL80211_CHAN_WIDTH_20) {
sdata_info(sdata, "Failed to join IBSS, beacons forbidden\n"); return;
}
chanreq.oper.width = NL80211_CHAN_WIDTH_20;
chanreq.oper.center_freq1 = chan->center_freq; /* check again for downgraded chandef */ if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chanreq.oper,
NL80211_IFTYPE_ADHOC)) {
sdata_info(sdata, "Failed to join IBSS, beacons forbidden\n"); return;
}
}
err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
&chanreq.oper, NL80211_IFTYPE_ADHOC); if (err < 0) {
sdata_info(sdata, "Failed to join IBSS, invalid chandef\n"); return;
} if (err > 0 && !ifibss->userspace_handles_dfs) {
sdata_info(sdata, "Failed to join IBSS, DFS channel without control program\n"); return;
}
radar_required = err;
if (ieee80211_link_use_channel(&sdata->deflink, &chanreq,
ifibss->fixed_channel ?
IEEE80211_CHANCTX_SHARED :
IEEE80211_CHANCTX_EXCLUSIVE)) {
sdata_info(sdata, "Failed to join IBSS, no channel context\n"); return;
}
sdata->deflink.radar_required = radar_required;
/* * In 5 GHz/802.11a, we can always use short slot time. * (IEEE 802.11-2012 18.3.8.7) * * In 2.4GHz, we must always use long slots in IBSS for compatibility * reasons. * (IEEE 802.11-2012 19.4.5) * * HT follows these specifications (IEEE 802.11-2012 20.3.18)
*/
sdata->vif.bss_conf.use_short_slot = chan->band == NL80211_BAND_5GHZ;
bss_change |= BSS_CHANGED_ERP_SLOT;
switch (sdata->u.ibss.chandef.width) { case NL80211_CHAN_WIDTH_20_NOHT: case NL80211_CHAN_WIDTH_20: case NL80211_CHAN_WIDTH_40:
chan_type = cfg80211_get_chandef_type(&sdata->u.ibss.chandef);
cfg80211_chandef_create(&chandef, cbss->channel, chan_type); break; case NL80211_CHAN_WIDTH_5: case NL80211_CHAN_WIDTH_10:
cfg80211_chandef_create(&chandef, cbss->channel,
NL80211_CHAN_NO_HT);
chandef.width = sdata->u.ibss.chandef.width; break; case NL80211_CHAN_WIDTH_80: case NL80211_CHAN_WIDTH_80P80: case NL80211_CHAN_WIDTH_160:
chandef = sdata->u.ibss.chandef;
chandef.chan = cbss->channel; break; default: /* fall back to 20 MHz for unsupported modes */
cfg80211_chandef_create(&chandef, cbss->channel,
NL80211_CHAN_NO_HT); break;
}
/* When not connected/joined, sending CSA doesn't make sense. */ if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) return -ENOLINK;
/* update cfg80211 bss information with the new channel */ if (!is_zero_ether_addr(ifibss->bssid)) {
cbss = cfg80211_get_bss(sdata->local->hw.wiphy,
ifibss->chandef.chan,
ifibss->bssid, ifibss->ssid,
ifibss->ssid_len,
IEEE80211_BSS_TYPE_IBSS,
IEEE80211_PRIVACY(ifibss->privacy)); /* XXX: should not really modify cfg80211 data */ if (cbss) {
cbss->channel = sdata->deflink.csa.chanreq.oper.chan;
cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
}
}
ibss_dbg(sdata, "Adding new IBSS station %pM\n", addr);
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); /* authorize the station only if the network is not RSN protected. If
* not wait for the userspace to authorize it */ if (!sta->sdata->u.ibss.control_port)
sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
rate_control_rate_init(&sta->deflink);
/* If it fails, maybe we raced another insertion? */ if (sta_info_insert_rcu(sta)) return sta_info_get(sdata, addr); return sta;
}
/* * XXX: Consider removing the least recently used entry and * allow new one to be added.
*/ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
net_info_ratelimited("%s: No room for a new IBSS STA entry %pM\n",
sdata->name, addr);
rcu_read_lock(); return NULL;
}
if (ifibss->state == IEEE80211_IBSS_MLME_SEARCH) {
rcu_read_lock(); return NULL;
}
if (!ether_addr_equal(bssid, sdata->u.ibss.bssid)) {
rcu_read_lock(); return NULL;
}
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON_ONCE(!chanctx_conf)) return NULL;
band = chanctx_conf->def.chan->band;
rcu_read_unlock();
sta = sta_info_alloc(sdata, addr, GFP_KERNEL); if (!sta) {
rcu_read_lock(); return NULL;
}
/* make sure mandatory rates are always added */
sband = local->hw.wiphy->bands[band];
sta->sta.deflink.supp_rates[band] = supp_rates |
ieee80211_mandatory_rates(sband);
return ieee80211_ibss_finish_sta(sta);
}
staticint ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
{ struct ieee80211_local *local = sdata->local; int active = 0; struct sta_info *sta;
/* if the current channel is a DFS channel, mark the channel as * unavailable.
*/
err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
&ifibss->chandef,
NL80211_IFTYPE_ADHOC); if (err > 0)
cfg80211_radar_event(sdata->local->hw.wiphy, &ifibss->chandef,
GFP_ATOMIC);
}
switch (ifibss->chandef.width) { case NL80211_CHAN_WIDTH_20_NOHT: case NL80211_CHAN_WIDTH_20: case NL80211_CHAN_WIDTH_40: /* keep our current HT mode (HT20/HT40+/HT40-), even if * another mode has been announced. The mode is not adopted * within the beacon while doing CSA and we should therefore * keep the mode which we announce.
*/
ch_type = cfg80211_get_chandef_type(&ifibss->chandef);
cfg80211_chandef_create(¶ms.chandef, params.chandef.chan,
ch_type); break; case NL80211_CHAN_WIDTH_5: case NL80211_CHAN_WIDTH_10: if (params.chandef.width != ifibss->chandef.width) {
sdata_info(sdata, "IBSS %pM received channel switch from incompatible channel width (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
ifibss->bssid,
params.chandef.chan->center_freq,
params.chandef.width,
params.chandef.center_freq1,
params.chandef.center_freq2); goto disconnect;
} break; default: /* should not happen, conn_flags should prevent VHT modes. */
WARN_ON(1); goto disconnect;
}
err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
¶ms.chandef,
NL80211_IFTYPE_ADHOC); if (err < 0) goto disconnect; if (err > 0 && !ifibss->userspace_handles_dfs) { /* IBSS-DFS only allowed with a control program */ goto disconnect;
}
params.radar_required = err;
if (cfg80211_chandef_identical(¶ms.chandef,
&sdata->vif.bss_conf.chanreq.oper)) {
ibss_dbg(sdata, "received csa with an identical chandef, ignoring\n"); returntrue;
}
/* all checks done, now perform the channel switch. */
ibss_dbg(sdata, "received channel switch announcement to go to channel %d MHz\n",
params.chandef.chan->center_freq);
params.block_tx = !!csa_ie.mode;
if (ieee80211_channel_switch(sdata->local->hw.wiphy, sdata->dev,
¶ms)) goto disconnect;
if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) return;
/* * IEEE 802.11 standard does not require authentication in IBSS * networks and most implementations do not seem to use it. * However, try to reply to authentication attempts if someone * has actually implemented this.
*/
ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, 0, NULL, 0,
mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0, 0);
}
/* same for beacon and probe response */
beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
/* check if we need to merge IBSS */
/* not an IBSS */ if (!(cbss->capability & WLAN_CAPABILITY_IBSS)) goto put_bss;
/* different channel */ if (sdata->u.ibss.fixed_channel &&
sdata->u.ibss.chandef.chan != cbss->channel) goto put_bss;
/* different SSID */ if (elems->ssid_len != sdata->u.ibss.ssid_len ||
memcmp(elems->ssid, sdata->u.ibss.ssid,
sdata->u.ibss.ssid_len)) goto put_bss;
/* process channel switch */ if (sdata->vif.bss_conf.csa_active ||
ieee80211_ibss_process_chanswitch(sdata, elems, true)) goto put_bss;
/* same BSSID */ if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid)) goto put_bss;
/* we use a fixed BSSID */ if (sdata->u.ibss.fixed_bssid) goto put_bss;
if (ieee80211_have_rx_timestamp(rx_status)) { /* time when timestamp field was received */
rx_timestamp =
ieee80211_calculate_rx_timestamp(local, rx_status,
len + FCS_LEN, 24);
} else { /* * second best option: get current TSF * (will return -1 if not supported)
*/
rx_timestamp = drv_get_tsf(local, sdata);
}
/* * XXX: Consider removing the least recently used entry and * allow new one to be added.
*/ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
net_info_ratelimited("%s: No room for a new IBSS STA entry %pM\n",
sdata->name, addr); return;
}
if (ifibss->state == IEEE80211_IBSS_MLME_SEARCH) return;
if (!ether_addr_equal(bssid, sdata->u.ibss.bssid)) return;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON_ONCE(!chanctx_conf)) {
rcu_read_unlock(); return;
}
band = chanctx_conf->def.chan->band;
rcu_read_unlock();
sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); if (!sta) return;
/* make sure mandatory rates are always added */
sband = local->hw.wiphy->bands[band];
sta->sta.deflink.supp_rates[band] = supp_rates |
ieee80211_mandatory_rates(sband);
if (ifibss->fixed_bssid) {
memcpy(bssid, ifibss->bssid, ETH_ALEN);
} else { /* Generate random, not broadcast, locally administered BSSID. Mix in * own MAC address to make sure that devices that do not have proper
* random number generator get different BSSID. */
get_random_bytes(bssid, ETH_ALEN); for (i = 0; i < ETH_ALEN; i++)
bssid[i] ^= sdata->vif.addr[i];
bssid[0] &= ~0x01;
bssid[0] |= 0x02;
}
sdata_info(sdata, "Creating new IBSS network, BSSID %pM\n", bssid);
capability = WLAN_CAPABILITY_IBSS;
if (ifibss->privacy)
capability |= WLAN_CAPABILITY_PRIVACY;
/* if a fixed bssid and a fixed freq have been provided create the IBSS * directly and do not waste time scanning
*/ if (ifibss->fixed_bssid && ifibss->fixed_channel) {
sdata_info(sdata, "Created IBSS using preconfigured BSSID %pM\n",
bssid);
ieee80211_sta_create_ibss(sdata); return;
}
ibss_dbg(sdata, "sta_find_ibss: did not try to join ibss\n");
/* Selected IBSS not found in current scan results - try to scan */ if (time_after(jiffies, ifibss->last_scan_completed +
IEEE80211_SCAN_INTERVAL)) { struct ieee80211_channel *channels[8]; unsignedint num;
sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
if (ifibss->fixed_channel) {
num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
&ifibss->chandef,
channels,
ARRAY_SIZE(channels));
ieee80211_request_ibss_scan(sdata, ifibss->ssid,
ifibss->ssid_len, channels,
num);
} else {
ieee80211_request_ibss_scan(sdata, ifibss->ssid,
ifibss->ssid_len, NULL, 0);
}
} else { int interval = IEEE80211_SCAN_INTERVAL;
if (time_after(jiffies, ifibss->ibss_join_req +
IEEE80211_IBSS_JOIN_TIMEOUT))
ieee80211_sta_create_ibss(sdata);
/* * 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;
elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
len - baselen, false, NULL);
/* * 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 * the HT Protection field were set to non-HT mixed mode. * * In an IBSS, the RIFS Mode field of the HT Operation element is * also reserved, but an HT STA shall operate as though this field * were set to 1.
*/
/* on the next join, re-program HT parameters */
memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa));
memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.