void ieee80211_chswitch_work(struct work_struct *work) { struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); struct ieee80211_bss *bss; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; if (!netif_running(sdata->dev)) return; bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid, sdata->local->hw.conf.channel->center_freq, ifmgd->ssid, ifmgd->ssid_len); if (!bss) goto exit; sdata->local->oper_channel = sdata->local->csa_channel; /* XXX: shouldn't really modify cfg80211-owned data! */ if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) bss->cbss.channel = sdata->local->oper_channel; ieee80211_rx_bss_put(sdata->local, bss); exit: ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; ieee80211_wake_queues_by_reason(&sdata->local->hw, IEEE80211_QUEUE_STOP_REASON_CSA); }
void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid, int freq, u8 *ssid, u8 ssid_len) { struct ieee80211_bss *bss; struct ieee80211_local *local = sdata->local; bss = ieee80211_rx_bss_get(local, bssid, freq, ssid, ssid_len); if (bss) { cfg80211_unlink_bss(local->hw.wiphy, (void *)bss); ieee80211_rx_bss_put(local, bss); } }
struct ieee80211_bss * ieee80211_bss_info_update(struct ieee80211_local *local, struct ieee80211_rx_status *rx_status, struct ieee80211_mgmt *mgmt, size_t len, struct ieee802_11_elems *elems, int freq, bool beacon) { struct ieee80211_bss *bss; int clen; #ifdef CONFIG_MAC80211_MESH if (elems->mesh_config) bss = ieee80211_rx_mesh_bss_get(local, elems->mesh_id, elems->mesh_id_len, elems->mesh_config, freq); else #endif bss = ieee80211_rx_bss_get(local, mgmt->bssid, freq, elems->ssid, elems->ssid_len); if (!bss) { #ifdef CONFIG_MAC80211_MESH if (elems->mesh_config) bss = ieee80211_rx_mesh_bss_add(local, elems->mesh_id, elems->mesh_id_len, elems->mesh_config, elems->mesh_config_len, freq); else #endif bss = ieee80211_rx_bss_add(local, mgmt->bssid, freq, elems->ssid, elems->ssid_len); if (!bss) return NULL; } else { #if 0 /* TODO: order by RSSI? */ spin_lock_bh(&local->bss_lock); list_move_tail(&bss->list, &local->bss_list); spin_unlock_bh(&local->bss_lock); #endif } /* save the ERP value so that it is available at association time */ if (elems->erp_info && elems->erp_info_len >= 1) { bss->erp_value = elems->erp_info[0]; bss->has_erp_value = 1; } bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); if (elems->tim) { struct ieee80211_tim_ie *tim_ie = (struct ieee80211_tim_ie *)elems->tim; bss->dtim_period = tim_ie->dtim_period; } /* set default value for buggy APs */ if (!elems->tim || bss->dtim_period == 0) bss->dtim_period = 1; bss->supp_rates_len = 0; if (elems->supp_rates) { clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; if (clen > elems->supp_rates_len) clen = elems->supp_rates_len; memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates, clen); bss->supp_rates_len += clen; } if (elems->ext_supp_rates) { clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; if (clen > elems->ext_supp_rates_len) clen = elems->ext_supp_rates_len; memcpy(&bss->supp_rates[bss->supp_rates_len], elems->ext_supp_rates, clen); bss->supp_rates_len += clen; } bss->band = rx_status->band; bss->timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); bss->last_update = jiffies; bss->signal = rx_status->signal; bss->noise = rx_status->noise; bss->qual = rx_status->qual; bss->wmm_used = elems->wmm_param || elems->wmm_info; if (!beacon) bss->last_probe_resp = jiffies; /* * For probe responses, or if we don't have any information yet, * use the IEs from the beacon. */ if (!bss->ies || !beacon) { if (bss->ies == NULL || bss->ies_len < elems->total_len) { kfree(bss->ies); bss->ies = kmalloc(elems->total_len, GFP_ATOMIC); } if (bss->ies) { memcpy(bss->ies, elems->ie_start, elems->total_len); bss->ies_len = elems->total_len; } else bss->ies_len = 0; } return bss; }