int prism2_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) { struct prism2_wiphy_private *priv = wiphy_priv(wiphy); wlandevice_t *wlandev = dev->ml_priv; struct p80211msg_dot11req_scan msg1; struct p80211msg_dot11req_scan_results msg2; int result; int err = 0; int numbss = 0; int i = 0; u8 ie_buf[46]; int ie_len; if (!request) return -EINVAL; if (priv->scan_request && priv->scan_request != request) return -EBUSY; if (wlandev->macmode == WLAN_MACMODE_ESS_AP) { printk(KERN_ERR "Can't scan in AP mode\n"); return -EOPNOTSUPP; } priv->scan_request = request; memset(&msg1, 0x00, sizeof(struct p80211msg_dot11req_scan)); msg1.msgcode = DIDmsg_dot11req_scan; msg1.bsstype.data = P80211ENUM_bsstype_any; memset(&(msg1.bssid.data), 0xFF, sizeof(p80211item_pstr6_t)); msg1.bssid.data.len = 6; if (request->n_ssids > 0) { msg1.scantype.data = P80211ENUM_scantype_active; msg1.ssid.data.len = request->ssids->ssid_len; memcpy(msg1.ssid.data.data, request->ssids->ssid, request->ssids->ssid_len); } else { msg1.scantype.data = 0; } msg1.probedelay.data = 0; for (i = 0; (i < request->n_channels) && i < ARRAY_SIZE(prism2_channels); i++) msg1.channellist.data.data[i] = ieee80211_frequency_to_channel(request->channels[i]->center_freq); msg1.channellist.data.len = request->n_channels; msg1.maxchanneltime.data = 250; msg1.minchanneltime.data = 200; result = p80211req_dorequest(wlandev, (u8 *) &msg1); if (result) { err = prism2_result2err(msg1.resultcode.data); goto exit; } /* Now retrieve scan results */ numbss = msg1.numbss.data; for (i = 0; i < numbss; i++) { memset(&msg2, 0, sizeof(msg2)); msg2.msgcode = DIDmsg_dot11req_scan_results; msg2.bssindex.data = i; result = p80211req_dorequest(wlandev, (u8 *) &msg2); if ((result != 0) || (msg2.resultcode.data != P80211ENUM_resultcode_success)) { break; } ie_buf[0] = WLAN_EID_SSID; ie_buf[1] = msg2.ssid.data.len; ie_len = ie_buf[1] + 2; memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len); cfg80211_inform_bss(wiphy, ieee80211_get_channel(wiphy, ieee80211_dsss_chan_to_freq(msg2.dschannel.data)), (const u8 *) &(msg2.bssid.data.data), msg2.timestamp.data, msg2.capinfo.data, msg2.beaconperiod.data, ie_buf, ie_len, (msg2.signal.data - 65536) * 100, /* Conversion to signed type */ GFP_KERNEL ); } if (result) err = prism2_result2err(msg2.resultcode.data); exit: cfg80211_scan_done(request, err ? 1 : 0); priv->scan_request = NULL; return err; }
static void _rtw_reg_apply_flags(struct wiphy *wiphy) { #if 1 /* by channel plan */ _adapter *padapter = wiphy_to_adapter(wiphy); u8 channel_plan = padapter->mlmepriv.ChannelPlan; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; RT_CHANNEL_INFO *channel_set = pmlmeext->channel_set; u8 max_chan_nums = pmlmeext->max_chan_nums; struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; unsigned int i, j; u16 channel; u32 freq; /* all channels disable */ for (i = 0; i < NUM_NL80211_BANDS; i++) { sband = wiphy->bands[i]; if (sband) { for (j = 0; j < sband->n_channels; j++) { ch = &sband->channels[j]; if (ch) ch->flags = IEEE80211_CHAN_DISABLED; } } } /* channels apply by channel plans. */ for (i = 0; i < max_chan_nums; i++) { channel = channel_set[i].ChannelNum; freq = rtw_ch2freq(channel); ch = ieee80211_get_channel(wiphy, freq); if (ch) { if (channel_set[i].ScanType == SCAN_PASSIVE #if defined(CONFIG_DFS_MASTER) && rtw_odm_dfs_domain_unknown(wiphy_to_adapter(wiphy)) #endif ) { #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) ch->flags = (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_PASSIVE_SCAN); #else ch->flags = IEEE80211_CHAN_NO_IR; #endif } else ch->flags = 0; } } #else struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; unsigned int i, j; u16 channels[37] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 }; u16 channel; u32 freq; for (i = 0; i < NUM_NL80211_BANDS; i++) { sband = wiphy->bands[i]; if (sband) for (j = 0; j < sband->n_channels; j++) { ch = &sband->channels[j]; if (ch) ch->flags = IEEE80211_CHAN_DISABLED; } } for (i = 0; i < 37; i++) { channel = channels[i]; freq = rtw_ch2freq(channel); ch = ieee80211_get_channel(wiphy, freq); if (ch) { if (channel <= 11) ch->flags = 0; else ch->flags = 0; /* IEEE80211_CHAN_PASSIVE_SCAN; */ } /* printk("%s: freq %d(%d) flag 0x%02X\n", __func__, freq, channel, ch->flags); */ } #endif }
static void _rtw_reg_apply_flags(struct wiphy *wiphy) { #if 1 // by channel plan _adapter *padapter = wiphy_to_adapter(wiphy); u8 channel_plan = padapter->mlmepriv.ChannelPlan; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; RT_CHANNEL_INFO *channel_set = pmlmeext->channel_set; u8 max_chan_nums = pmlmeext->max_chan_nums; struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; unsigned int i, j; u16 channel; u32 freq; // all channels disable for (i = 0; i < IEEE80211_NUM_BANDS; i++) { sband = wiphy->bands[i]; if (sband) { for (j = 0; j < sband->n_channels; j++) { ch = &sband->channels[j]; if (ch) ch->flags = IEEE80211_CHAN_DISABLED; } } } // channels apply by channel plans. for (i = 0; i < max_chan_nums; i++) { channel = channel_set[i].ChannelNum; if (channel <= 14) freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); else freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); ch = ieee80211_get_channel(wiphy, freq); if (ch) { if (channel_set[i].ScanType == SCAN_PASSIVE) ch->flags = IEEE80211_CHAN_PASSIVE_SCAN; else ch->flags = 0; } } #else struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; unsigned int i, j; u16 channels[37] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 }; u16 channel; u32 freq; for (i = 0; i < IEEE80211_NUM_BANDS; i++) { sband = wiphy->bands[i]; if (sband) for (j = 0; j < sband->n_channels; j++) { ch = &sband->channels[j]; if (ch) ch->flags = IEEE80211_CHAN_DISABLED; } } for (i = 0; i < 37; i++) { channel = channels[i]; if (channel <= 14) freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); else freq = rtw_ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); ch = ieee80211_get_channel(wiphy, freq); if (ch) { if (channel <= 11) ch->flags = 0; else ch->flags = 0; //IEEE80211_CHAN_PASSIVE_SCAN; } //printk("%s: freq %d(%d) flag 0x%02X \n", __func__, freq, channel, ch->flags); } #endif }
int cfg80211_mgd_wext_siwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *wextfreq, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); struct ieee80211_channel *chan = NULL; int err, freq; /* call only for station! */ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); if (freq < 0) return freq; if (freq) { chan = ieee80211_get_channel(wdev->wiphy, freq); if (!chan) return -EINVAL; if (chan->flags & IEEE80211_CHAN_DISABLED) return -EINVAL; } cfg80211_lock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); wdev_lock(wdev); if (wdev->sme_state != CFG80211_SME_IDLE) { bool event = true; if (wdev->wext.connect.channel == chan) { err = 0; goto out; } /* if SSID set, we'll try right again, avoid event */ if (wdev->wext.connect.ssid_len) event = false; err = __cfg80211_disconnect(rdev, dev, WLAN_REASON_DEAUTH_LEAVING, event); if (err) goto out; } wdev->wext.connect.channel = chan; /* * SSID is not set, we just want to switch monitor channel, * this is really just backward compatibility, if the SSID * is set then we use the channel to select the BSS to use * to connect to instead. If we were connected on another * channel we disconnected above and reconnect below. */ if (chan && !wdev->wext.connect.ssid_len) { struct cfg80211_chan_def chandef = { .width = NL80211_CHAN_WIDTH_20_NOHT, .center_freq1 = freq, }; chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); if (chandef.chan) err = cfg80211_set_monitor_channel(rdev, &chandef); else err = -EINVAL; goto out; } err = cfg80211_mgd_wext_connect(rdev, wdev); out: wdev_unlock(wdev); mutex_unlock(&rdev->devlist_mtx); cfg80211_unlock_rdev(rdev); return err; }
/* * This function fills bss descriptor structure using provided * information. * beacon_ie buffer is allocated in this function. It is caller's * responsibility to free the memory. */ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, struct cfg80211_bss *bss, struct mwifiex_bssdescriptor *bss_desc) { u8 *beacon_ie; size_t beacon_ie_len; struct mwifiex_bss_priv *bss_priv = (void *)bss->priv; const struct cfg80211_bss_ies *ies; int ret; rcu_read_lock(); ies = rcu_dereference(bss->ies); beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC); beacon_ie_len = ies->len; bss_desc->timestamp = ies->tsf; rcu_read_unlock(); if (!beacon_ie) { mwifiex_dbg(priv->adapter, ERROR, " failed to alloc beacon_ie\n"); return -ENOMEM; } memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN); bss_desc->rssi = bss->signal; /* The caller of this function will free beacon_ie */ bss_desc->beacon_buf = beacon_ie; bss_desc->beacon_buf_size = beacon_ie_len; bss_desc->beacon_period = bss->beacon_interval; bss_desc->cap_info_bitmap = bss->capability; bss_desc->bss_band = bss_priv->band; bss_desc->fw_tsf = bss_priv->fw_tsf; if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { mwifiex_dbg(priv->adapter, INFO, "info: InterpretIE: AP WEP enabled\n"); bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; } else { bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; } if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_IBSS) bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; else bss_desc->bss_mode = NL80211_IFTYPE_STATION; /* Disable 11ac by default. Enable it only where there * exist VHT_CAP IE in AP beacon */ bss_desc->disable_11ac = true; if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT) bss_desc->sensed_11h = true; ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc); if (ret) return ret; /* Update HT40 capability based on current channel information */ if (bss_desc->bcn_ht_oper && bss_desc->bcn_ht_cap) { u8 ht_param = bss_desc->bcn_ht_oper->ht_param; u8 radio = mwifiex_band_to_radio_type(bss_desc->bss_band); struct ieee80211_supported_band *sband = priv->wdev.wiphy->bands[radio]; int freq = ieee80211_channel_to_frequency(bss_desc->channel, radio); struct ieee80211_channel *chan = ieee80211_get_channel(priv->adapter->wiphy, freq); switch (ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) { sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; } else { sband->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_SGI_40; } break; case IEEE80211_HT_PARAM_CHA_SEC_BELOW: if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) { sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; } else { sband->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_SGI_40; } break; } } return 0; }
int cfg80211_mgd_wext_siwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *wextfreq, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); struct ieee80211_channel *chan = NULL; int err, freq; /* call only for station! */ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); if (freq < 0) return freq; if (freq) { chan = ieee80211_get_channel(wdev->wiphy, freq); if (!chan) return -EINVAL; if (chan->flags & IEEE80211_CHAN_DISABLED) return -EINVAL; } cfg80211_lock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); wdev_lock(wdev); if (wdev->sme_state != CFG80211_SME_IDLE) { bool event = true; if (wdev->wext.connect.channel == chan) { err = 0; goto out; } /* if SSID set, we'll try right again, avoid event */ if (wdev->wext.connect.ssid_len) event = false; err = __cfg80211_disconnect(rdev, dev, WLAN_REASON_DEAUTH_LEAVING, event); if (err) goto out; } wdev->wext.connect.channel = chan; /* SSID is not set, we just want to switch channel */ if (chan && !wdev->wext.connect.ssid_len) { err = rdev_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT); goto out; } err = cfg80211_mgd_wext_connect(rdev, wdev); out: wdev_unlock(wdev); mutex_unlock(&rdev->devlist_mtx); cfg80211_unlock_rdev(rdev); return err; }
/* * This function informs the CFG802.11 subsystem of a new BSS connection. * * The following information are sent to the CFG802.11 subsystem * to register the new BSS connection. If we do not register the new BSS, * a kernel panic will result. * - MAC address * - Capabilities * - Beacon period * - RSSI value * - Channel * - Supported rates IE * - Extended capabilities IE * - DS parameter set IE * - HT Capability IE * - Vendor Specific IE (221) * - WPA IE * - RSN IE */ static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, struct mwifiex_802_11_ssid *ssid) { struct mwifiex_bssdescriptor *scan_table; int i, j; struct ieee80211_channel *chan; u8 *ie, *ie_buf; u32 ie_len; u8 *beacon; int beacon_size; u8 element_id, element_len; #define MAX_IE_BUF 2048 ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); if (!ie_buf) { dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n", __func__); return -ENOMEM; } scan_table = priv->adapter->scan_table; for (i = 0; i < priv->adapter->num_in_scan_table; i++) { if (ssid) { /* Inform specific BSS only */ if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, ssid->ssid_len)) continue; } memset(ie_buf, 0, MAX_IE_BUF); ie_buf[0] = WLAN_EID_SSID; ie_buf[1] = scan_table[i].ssid.ssid_len; memcpy(&ie_buf[sizeof(struct ieee_types_header)], scan_table[i].ssid.ssid, ie_buf[1]); ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header); ie_len = ie_buf[1] + sizeof(struct ieee_types_header); ie[0] = WLAN_EID_SUPP_RATES; for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) { if (!scan_table[i].supported_rates[j]) break; else ie[j + sizeof(struct ieee_types_header)] = scan_table[i].supported_rates[j]; } ie[1] = j; ie_len += ie[1] + sizeof(struct ieee_types_header); beacon = scan_table[i].beacon_buf; beacon_size = scan_table[i].beacon_buf_size; /* Skip time stamp, beacon interval and capability */ if (beacon) { beacon += sizeof(scan_table[i].beacon_period) + sizeof(scan_table[i].time_stamp) + +sizeof(scan_table[i].cap_info_bitmap); beacon_size -= sizeof(scan_table[i].beacon_period) + sizeof(scan_table[i].time_stamp) + sizeof(scan_table[i].cap_info_bitmap); } while (beacon_size >= sizeof(struct ieee_types_header)) { ie = ie_buf + ie_len; element_id = *beacon; element_len = *(beacon + 1); if (beacon_size < (int) element_len + sizeof(struct ieee_types_header)) { dev_err(priv->adapter->dev, "%s: in processing" " IE, bytes left < IE length\n", __func__); break; } switch (element_id) { case WLAN_EID_EXT_CAPABILITY: case WLAN_EID_DS_PARAMS: case WLAN_EID_HT_CAPABILITY: case WLAN_EID_VENDOR_SPECIFIC: case WLAN_EID_RSN: case WLAN_EID_BSS_AC_ACCESS_DELAY: ie[0] = element_id; ie[1] = element_len; memcpy(&ie[sizeof(struct ieee_types_header)], (u8 *) beacon + sizeof(struct ieee_types_header), element_len); ie_len += ie[1] + sizeof(struct ieee_types_header); break; default: break; } beacon += element_len + sizeof(struct ieee_types_header); beacon_size -= element_len + sizeof(struct ieee_types_header); } chan = ieee80211_get_channel(priv->wdev->wiphy, scan_table[i].freq); cfg80211_inform_bss(priv->wdev->wiphy, chan, scan_table[i].mac_address, 0, scan_table[i].cap_info_bitmap, scan_table[i].beacon_period, ie_buf, ie_len, scan_table[i].rssi, GFP_KERNEL); } kfree(ie_buf); return 0; }
void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, u8 *bssid, u16 listen_intvl, u16 beacon_intvl, enum network_type nw_type, u8 beacon_ie_len, u8 assoc_req_len, u8 assoc_resp_len, u8 *assoc_info) { struct ieee80211_channel *chan; /* capinfo + listen interval */ u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16); /* capinfo + status code + associd */ u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16); u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset; u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len + assoc_resp_ie_offset; assoc_req_len -= assoc_req_ie_offset; assoc_resp_len -= assoc_resp_ie_offset; /* * Store Beacon interval here; DTIM period will be available only once * a Beacon frame from the AP is seen. */ ar->assoc_bss_beacon_int = beacon_intvl; clear_bit(DTIM_PERIOD_AVAIL, &ar->flag); if (nw_type & ADHOC_NETWORK) { if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: ath6k not in ibss mode\n", __func__); return; } } if (nw_type & INFRA_NETWORK) { if (ar->wdev->iftype != NL80211_IFTYPE_STATION && ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: ath6k not in station mode\n", __func__); return; } } chan = ieee80211_get_channel(ar->wdev->wiphy, (int) channel); if (nw_type & ADHOC_NETWORK) { cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL); return; } if (ath6kl_add_bss_if_needed(ar, bssid, chan, assoc_info, beacon_ie_len) < 0) { ath6kl_err("could not add cfg80211 bss entry for " "connect/roamed notification\n"); return; } if (ar->sme_state == SME_CONNECTING) { /* inform connect result to cfg80211 */ ar->sme_state = SME_CONNECTED; cfg80211_connect_result(ar->net_dev, bssid, assoc_req_ie, assoc_req_len, assoc_resp_ie, assoc_resp_len, WLAN_STATUS_SUCCESS, GFP_KERNEL); } else if (ar->sme_state == SME_CONNECTED) { /* inform roam event to cfg80211 */ cfg80211_roamed(ar->net_dev, chan, bssid, assoc_req_ie, assoc_req_len, assoc_resp_ie, assoc_resp_len, GFP_KERNEL); } }
static int qtnf_event_handle_scan_results(struct qtnf_vif *vif, const struct qlink_event_scan_result *sr, u16 len) { struct cfg80211_bss *bss; struct ieee80211_channel *channel; struct wiphy *wiphy = priv_to_wiphy(vif->mac); enum cfg80211_bss_frame_type frame_type = CFG80211_BSS_FTYPE_UNKNOWN; size_t payload_len; u16 tlv_type; u16 tlv_value_len; size_t tlv_full_len; const struct qlink_tlv_hdr *tlv; const u8 *ies = NULL; size_t ies_len = 0; if (len < sizeof(*sr)) { pr_err("VIF%u.%u: payload is too short\n", vif->mac->macid, vif->vifid); return -EINVAL; } channel = ieee80211_get_channel(wiphy, le16_to_cpu(sr->freq)); if (!channel) { pr_err("VIF%u.%u: channel at %u MHz not found\n", vif->mac->macid, vif->vifid, le16_to_cpu(sr->freq)); return -EINVAL; } payload_len = len - sizeof(*sr); tlv = (struct qlink_tlv_hdr *)sr->payload; while (payload_len >= sizeof(struct qlink_tlv_hdr)) { tlv_type = le16_to_cpu(tlv->type); tlv_value_len = le16_to_cpu(tlv->len); tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); if (tlv_full_len > payload_len) return -EINVAL; if (tlv_type == QTN_TLV_ID_IE_SET) { const struct qlink_tlv_ie_set *ie_set; unsigned int ie_len; if (payload_len < sizeof(*ie_set)) return -EINVAL; ie_set = (const struct qlink_tlv_ie_set *)tlv; ie_len = tlv_value_len - (sizeof(*ie_set) - sizeof(ie_set->hdr)); switch (ie_set->type) { case QLINK_IE_SET_BEACON_IES: frame_type = CFG80211_BSS_FTYPE_BEACON; break; case QLINK_IE_SET_PROBE_RESP_IES: frame_type = CFG80211_BSS_FTYPE_PRESP; break; default: frame_type = CFG80211_BSS_FTYPE_UNKNOWN; } if (ie_len) { ies = ie_set->ie_data; ies_len = ie_len; } } payload_len -= tlv_full_len; tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); } if (payload_len) return -EINVAL; bss = cfg80211_inform_bss(wiphy, channel, frame_type, sr->bssid, get_unaligned_le64(&sr->tsf), le16_to_cpu(sr->capab), le16_to_cpu(sr->bintval), ies, ies_len, DBM_TO_MBM(sr->sig_dbm), GFP_KERNEL); if (!bss) return -ENOMEM; cfg80211_put_bss(wiphy, bss); return 0; }
int ieee80211_ifattach(struct ieee80211com *ic, IEEE80211_REG_PARAMETERS *ieee80211_reg_parm) { u_int8_t bcast[IEEE80211_ADDR_LEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; int error = 0; ic->ic_reg_parm = *ieee80211_reg_parm; /* set up broadcast address */ IEEE80211_ADDR_COPY(ic->ic_broadcast, bcast); /* initialize channel list */ ieee80211_update_channellist(ic, 0); /* initialize rate set */ ieee80211_init_rateset(ic); /* validate ic->ic_curmode */ if (!IEEE80211_SUPPORT_PHY_MODE(ic, ic->ic_curmode)) ic->ic_curmode = IEEE80211_MODE_AUTO; /* setup initial channel settings */ ic->ic_curchan = ieee80211_get_channel(ic, 0); /* arbitrarily pick the first channel */ /* Enable marking of dfs by default */ ic->ic_flags_ext |= IEEE80211_FEXT_MARKDFS; if (ic->ic_reg_parm.htEnableWepTkip) { ieee80211_ic_wep_tkip_htrate_set(ic); } else { ieee80211_ic_wep_tkip_htrate_clear(ic); } if (ic->ic_reg_parm.htVendorIeEnable) IEEE80211_ENABLE_HTVIE(ic); /* whether to ignore 11d beacon */ if (ic->ic_reg_parm.ignore11dBeacon) IEEE80211_ENABLE_IGNORE_11D_BEACON(ic); if (ic->ic_reg_parm.disallowAutoCCchange) { ieee80211_ic_disallowAutoCCchange_set(ic); } else { ieee80211_ic_disallowAutoCCchange_clear(ic); } (void) ieee80211_setmode(ic, ic->ic_curmode, ic->ic_opmode); ic->ic_intval = IEEE80211_BINTVAL_DEFAULT; /* beacon interval */ ic->ic_set_beacon_interval(ic); ic->ic_lintval = 1; /* listen interval */ ic->ic_lintval_assoc = IEEE80211_LINTVAL_MAX; /* listen interval to use in association */ ic->ic_bmisstimeout = IEEE80211_BMISS_LIMIT * ic->ic_intval; TAILQ_INIT(&ic->ic_vaps); ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX; /* Intialize WDS Auto Detect mode */ ic->ic_flags_ext |= IEEE80211_FEXT_WDS_AUTODETECT; /* ** Enable the 11d country code IE by default */ ic->ic_flags_ext |= IEEE80211_FEXT_COUNTRYIE; /* setup CWM configuration */ ic->ic_cwm_set_mode(ic, ic->ic_reg_parm.cwmMode); ic->ic_cwm_set_extoffset(ic, ic->ic_reg_parm.cwmExtOffset); ic->ic_cwm_set_extprotmode(ic, ic->ic_reg_parm.cwmExtProtMode); ic->ic_cwm_set_extprotspacing(ic, ic->ic_reg_parm.cwmExtProtSpacing); #if tbd /* XXX - TODO - move these into ath layer */ #else ic->ic_cwm_set_enable(ic, ic->ic_reg_parm.cwmEnable); ic->ic_cwm_set_extbusythreshold(ic, ic->ic_reg_parm.cwmExtBusyThreshold); #endif ic->ic_enable2GHzHt40Cap = ic->ic_reg_parm.enable2GHzHt40Cap; #ifdef ATH_COALESCING ic->ic_tx_coalescing = ic->ic_reg_parm.txCoalescingEnable; #endif ic->ic_ignoreDynamicHalt = ic->ic_reg_parm.ignoreDynamicHalt; /* default to auto ADDBA mode */ ic->ic_addba_mode = ADDBA_MODE_AUTO; if (ic->ic_reg_parm.ht20AdhocEnable) { /* * Support HT rates in Ad hoc connections. */ if (IEEE80211_SUPPORT_PHY_MODE(ic, IEEE80211_MODE_11NA_HT20) || IEEE80211_SUPPORT_PHY_MODE(ic, IEEE80211_MODE_11NG_HT20)) { ieee80211_ic_ht20Adhoc_set(ic); if (ic->ic_reg_parm.htAdhocAggrEnable) { ieee80211_ic_htAdhocAggr_set(ic); } } } if (ic->ic_reg_parm.ht40AdhocEnable) { /* * Support HT rates in Ad hoc connections. */ if (IEEE80211_SUPPORT_PHY_MODE(ic, IEEE80211_MODE_11NA_HT40PLUS) || IEEE80211_SUPPORT_PHY_MODE(ic, IEEE80211_MODE_11NA_HT40MINUS) || IEEE80211_SUPPORT_PHY_MODE(ic, IEEE80211_MODE_11NG_HT40PLUS) || IEEE80211_SUPPORT_PHY_MODE(ic, IEEE80211_MODE_11NG_HT40MINUS)) { ieee80211_ic_ht40Adhoc_set(ic); if (ic->ic_reg_parm.htAdhocAggrEnable) { ieee80211_ic_htAdhocAggr_set(ic); } } } OS_INIT_TIMER(ic->ic_osdev, &(ic->ic_inact_timer), ieee80211_inact_timeout, (void *) (ic)); #if UMAC_SUPPORT_WNM OS_INIT_TIMER(ic->ic_osdev, &(ic->ic_bssload_timer), ieee80211_bssload_timeout, (void *) (ic)); #endif if (ic->ic_reg_parm.disable2040Coexist) { ic->ic_flags |= IEEE80211_F_COEXT_DISABLE; } else { ic->ic_flags &= ~IEEE80211_F_COEXT_DISABLE; } /* setup other modules */ /* The TSF Timer module is required when P2P or Off-channel support are required */ ic->ic_tsf_timer = ieee80211_tsf_timer_attach(ic); #if UMAC_SUPPORT_TDLS_CHAN_SWITCH /* TDLS off-channel support requires TSF timer */ if (ic->ic_tsf_timer) { ieee80211_ic_off_channel_support_set(ic); } else { ieee80211_ic_off_channel_support_clear(ic); } #else ieee80211_ic_off_channel_support_clear(ic); #endif ieee80211_p2p_attach(ic); ieee80211_crypto_attach(ic); ieee80211_node_attach(ic); ieee80211_proto_attach(ic); ieee80211_power_attach(ic); ieee80211_mlme_attach(ic); #if ATH_SUPPORT_DFS ieee80211_dfs_attach(ic); #endif /* ATH_SUPPORT_DFS */ if (IEEE80211_ENAB_AOW(ic)) ieee80211_aow_attach(ic); error = ieee80211_scan_table_attach(ic, &(ic->ic_scan_table), ic->ic_osdev); if (error) { ieee80211_node_detach(ic); return error; } /* * By default overwrite probe response with beacon IE in scan entry. */ ieee80211_ic_override_proberesp_ie_set(ic); error = ieee80211_scan_attach(&(ic->ic_scanner), ic, ic->ic_osdev, ieee80211_is_connected, ieee80211_is_txq_empty, ieee80211_is_sw_txq_empty); if (error) { /* detach and free already allocated memory for scan */ ieee80211_scan_table_detach(&(ic->ic_scan_table)); ieee80211_node_detach(ic); return error; } ic->ic_resmgr = ieee80211_resmgr_create(ic, IEEE80211_RESMGR_MODE_SINGLE_CHANNEL); error = ieee80211_acs_attach(&(ic->ic_acs), ic, ic->ic_osdev); if (error) { /* detach and free already allocated memory for scan */ ieee80211_scan_table_detach(&(ic->ic_scan_table)); ieee80211_scan_detach(&(ic->ic_scanner)); ieee80211_node_detach(ic); return error; } ic->ic_notify_tx_bcn_mgr = ieee80211_notify_tx_bcn_attach(ic); ieee80211_rptplacement_attach(ic); IEEE80211_TDLS_ATTACH(ic); #if UMAC_SUPPORT_VI_DBG ieee80211_vi_dbg_attach(ic); #endif ieee80211_quiet_attach(ic); ieee80211_admctl_attach(ic); /* * Perform steps that require multiple objects to be initialized. * For example, cross references between objects such as ResMgr and Scanner. */ ieee80211_scan_attach_complete(ic->ic_scanner); ieee80211_resmgr_create_complete(ic->ic_resmgr); ieee80211_smartantenna_attach(ic); ieee80211_prdperfstats_attach(ic); ic->ic_get_ext_chan_info = ieee80211_get_extchan_info; /* initialization complete */ ic->ic_initialized = 1; return 0; }
void ath6kl_tgt_sony_get_scaninfo_event(struct ath6kl_vif *vif, u8 *datap, u32 len) { struct wmi_bss_info_hdr2 *bih; u8 *buf; struct ieee80211_channel *channel; struct ieee80211_mgmt *mgmt; //struct cfg80211_bss *bss; if (len <= sizeof(struct wmi_bss_info_hdr2)) return; bih = (struct wmi_bss_info_hdr2 *) datap; buf = datap + sizeof(struct wmi_bss_info_hdr2); len -= sizeof(struct wmi_bss_info_hdr2); printk( "bss info evt - ch %u, snr %d, rssi %d, bssid \"%pM\" " "frame_type=%d\n", bih->ch, bih->snr, bih->snr - 95, bih->bssid, bih->frame_type); if (bih->frame_type != BEACON_FTYPE && bih->frame_type != PROBERESP_FTYPE) return; /* Only update BSS table for now */ channel = ieee80211_get_channel(vif->wdev->wiphy, le16_to_cpu(bih->ch)); if (channel == NULL) return; if (len < 8 + 2 + 2) return; /* * In theory, use of cfg80211_inform_bss_ath6kl() would be more natural here * since we do not have the full frame. However, at least for now, * cfg80211 can only distinguish Beacon and Probe Response frames from * each other when using cfg80211_inform_bss_frame_ath6kl(), so let's build a * fake IEEE 802.11 header to be able to take benefit of this. */ mgmt = kmalloc(24 + len, GFP_ATOMIC); if (mgmt == NULL) return; if (bih->frame_type == BEACON_FTYPE) { mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); memset(mgmt->da, 0xff, ETH_ALEN); } else { struct net_device *dev = vif->net_dev; mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); memcpy(mgmt->da, dev->dev_addr, ETH_ALEN); } mgmt->duration = cpu_to_le16(0); memcpy(mgmt->sa, bih->bssid, ETH_ALEN); memcpy(mgmt->bssid, bih->bssid, ETH_ALEN); mgmt->seq_ctrl = cpu_to_le16(0); memcpy(&mgmt->u.beacon, buf, len); {//save to scan information database athcfg_wcmd_scan_result_t scan_entry; memset(&scan_entry,0x00,sizeof(athcfg_wcmd_scan_result_t)); scan_entry.isr_freq = bih->ch; scan_entry.isr_ieee = (unsigned char)ieee80211_frequency_to_channel_ath6kl(bih->ch); scan_entry.isr_rssi = (bih->snr < 0) ? 0 : bih->snr; memcpy(&scan_entry.isr_bssid[0],&bih->bssid[0],ATHCFG_WCMD_ADDR_LEN); scan_entry.isr_capinfo = le16_to_cpu(mgmt->u.beacon.capab_info); //parse ie information { struct ieee80211_ie_header *ie_element; unsigned char *temp_ptr; int remained_len; ie_element = (struct ieee80211_ie_header *)&(mgmt->u.beacon.variable); remained_len = len - 5*sizeof(u8); while(remained_len >= 0) { remained_len = remained_len - sizeof(struct ieee80211_ie_header)- ie_element->length; if (ie_element->length == 0) { ie_element += 1; /* next IE */ continue; } if (remained_len < ie_element->length) { /* Incomplete/bad info element */ //printk("EOF\n"); break; } temp_ptr = (unsigned char *)ie_element; temp_ptr = temp_ptr+sizeof(struct ieee80211_ie_header);//point to data area switch (ie_element->element_id) { case IEEE80211_ELEMID_SSID: memcpy(&scan_entry.isr_ssid,temp_ptr,ie_element->length); //printk("info_element->length=%d\n",ie_element->length); //printk("SSID=%s\n",scan_entry.isr_ssid); break; case IEEE80211_ELEMID_RATES: memcpy(&scan_entry.isr_rates[0],temp_ptr,ie_element->length); scan_entry.isr_nrates = ie_element->length; break; case IEEE80211_ELEMID_XRATES: memcpy(&scan_entry.isr_rates[scan_entry.isr_nrates],temp_ptr,ie_element->length); scan_entry.isr_nrates += ie_element->length; break; case IEEE80211_ELEMID_ERP: memcpy(&scan_entry.isr_erp,temp_ptr,ie_element->length); break; case IEEE80211_ELEMID_RSN: scan_entry.isr_rsn_ie.len = ie_element->length; memcpy(&scan_entry.isr_rsn_ie.data,temp_ptr,ie_element->length); break; case IEEE80211_ELEMID_HTCAP_ANA: if (scan_entry.isr_htcap_ie.len == 0) { scan_entry.isr_htcap_ie.len = ie_element->length; memcpy(&scan_entry.isr_htcap_ie.data[0],temp_ptr,ie_element->length); } break; case IEEE80211_ELEMID_HTINFO_ANA: /* we only care if there isn't already an HT IE (ANA) */ if (scan_entry.isr_htinfo_ie.len == 0) { scan_entry.isr_htinfo_ie.len = ie_element->length; memcpy(&scan_entry.isr_htinfo_ie.data[0],temp_ptr,ie_element->length); } break; case IEEE80211_ELEMID_HTCAP: /* we only care if there isn't already an HT IE (ANA) */ if (scan_entry.isr_htcap_ie.len == 0) { scan_entry.isr_htcap_ie.len = ie_element->length; memcpy(&scan_entry.isr_htcap_ie.data[0],temp_ptr,ie_element->length); } break; case IEEE80211_ELEMID_HTINFO: /* we only care if there isn't already an HT IE (ANA) */ if (scan_entry.isr_htinfo_ie.len == 0) { scan_entry.isr_htinfo_ie.len = ie_element->length; memcpy(&scan_entry.isr_htinfo_ie.data[0],temp_ptr,ie_element->length); } break; case IEEE80211_ELEMID_VENDOR: if (iswpaoui((u_int8_t *) ie_element)) { scan_entry.isr_wpa_ie.len = ie_element->length; memcpy(&scan_entry.isr_wpa_ie.data[0],temp_ptr,ie_element->length); } else if (iswpsoui((u_int8_t *) ie_element)) { scan_entry.isr_wps_ie.len = ie_element->length; memcpy(&scan_entry.isr_wps_ie.data[0],temp_ptr,ie_element->length); } else if (iswmeparam((u_int8_t *) ie_element)) { scan_entry.isr_wme_ie.len = ie_element->length; memcpy(&scan_entry.isr_wme_ie.data[0],temp_ptr,ie_element->length); } else if (isatherosoui((u_int8_t *) ie_element)) { scan_entry.isr_ath_ie.len = ie_element->length; memcpy(&scan_entry.isr_ath_ie.data[0],temp_ptr,ie_element->length); } else if (ishtcap((u_int8_t *) ie_element)) { if (scan_entry.isr_htcap_ie.len == 0) { scan_entry.isr_htcap_ie.len = ie_element->length; memcpy(&scan_entry.isr_htcap_ie.data[0],temp_ptr,ie_element->length); } } else if (ishtinfo((u_int8_t *) ie_element)) { if (scan_entry.isr_htinfo_ie.len == 0) { scan_entry.isr_htinfo_ie.len = ie_element->length; memcpy(&scan_entry.isr_htinfo_ie.data[0],temp_ptr,ie_element->length); } } else { //printk("Unknow know !!info_element->length=%d\n",ie_element->length); } break; default: //printk("Unknow know info_element->length=%d\n",ie_element->length); break; } ie_element = (struct ieee80211_ie_header *)(temp_ptr + ie_element->length); } } //find the exist entry or add new one { int i,entry_match_item; bool entry_match = 0; if(total_bss_info >= 100) { printk("Excess max entry 100\n"); kfree(mgmt); return; } for(i=0;i<total_bss_info;i++) { if(scaninfor_db[i].isr_freq == scan_entry.isr_freq) { if(memcmp(scaninfor_db[i].isr_bssid ,scan_entry.isr_bssid,ATHCFG_WCMD_ADDR_LEN) == 0) { //find it if(strcmp(scaninfor_db[i].isr_ssid ,scan_entry.isr_ssid) == 0) { //update it entry_match = 1; entry_match_item = i; //printk("fully match!! i=%d,update it,total_bss_info=%d\n",i,total_bss_info); memcpy(&scaninfor_db[i],&scan_entry,sizeof(athcfg_wcmd_scan_result_t)); break; } } } } if(entry_match == 0) { memcpy(&scaninfor_db[total_bss_info],&scan_entry,sizeof(athcfg_wcmd_scan_result_t)); #if 0 printk("[%d]Freq=%d\n",total_bss_info,scaninfor_db[total_bss_info].isr_freq); printk("[%d]CH=%d\n",total_bss_info,scaninfor_db[total_bss_info].isr_ieee); printk("[%d]RSSI=%d\n",total_bss_info,scaninfor_db[total_bss_info].isr_rssi); printk("[%d]BSSID=%pM\n",total_bss_info,scaninfor_db[total_bss_info].isr_bssid); printk("[%d]SSID=%s\n",total_bss_info,scaninfor_db[total_bss_info].isr_ssid); printk("[%d]isr_htinfo_ie.len=%d\n",total_bss_info,scaninfor_db[total_bss_info].isr_htinfo_ie.len); #endif total_bss_info++; //printk(" next entry=%d\n",total_bss_info); } else { #if 0 printk("[%d]Freq=%d\n",entry_match_item,scaninfor_db[entry_match_item].isr_freq); printk("[%d]CH=%d\n",entry_match_item,scaninfor_db[entry_match_item].isr_ieee); printk("[%d]RSSI=%d\n",entry_match_item,scaninfor_db[entry_match_item].isr_rssi); printk("[%d]BSSID=%pM\n",entry_match_item,scaninfor_db[entry_match_item].isr_bssid); printk("[%d]SSID=%s\n",entry_match_item,scaninfor_db[entry_match_item].isr_ssid); printk("[%d]isr_htinfo_ie.len=%d\n",entry_match_item,scaninfor_db[entry_match_item].isr_htinfo_ie.len); #endif } } } kfree(mgmt); ///total_bss_info++; return; }
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status, struct ieee802_11_elems *elems, bool beacon) { struct ieee80211_local *local = sdata->local; int freq; struct cfg80211_bss *cbss; struct ieee80211_bss *bss; struct sta_info *sta; struct ieee80211_channel *channel; u64 beacon_timestamp, rx_timestamp; u32 supp_rates = 0; enum ieee80211_band band = rx_status->band; struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; bool rates_updated = false; if (elems->ds_params && elems->ds_params_len == 1) freq = ieee80211_channel_to_frequency(elems->ds_params[0], band); else freq = rx_status->freq; channel = ieee80211_get_channel(local->hw.wiphy, freq); if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) return; if (sdata->vif.type == NL80211_IFTYPE_ADHOC && memcmp(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) { rcu_read_lock(); sta = sta_info_get(sdata, mgmt->sa); if (elems->supp_rates) { supp_rates = ieee80211_sta_get_rates(local, elems, band); if (sta) { u32 prev_rates; prev_rates = sta->sta.supp_rates[band]; /* make sure mandatory rates are always added */ sta->sta.supp_rates[band] = supp_rates | ieee80211_mandatory_rates(local, band); if (sta->sta.supp_rates[band] != prev_rates) { #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: updated supp_rates set " "for %pM based on beacon" "/probe_resp (0x%x -> 0x%x)\n", sdata->name, sta->sta.addr, prev_rates, sta->sta.supp_rates[band]); #endif rates_updated = true; } } else { rcu_read_unlock(); sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); } } if (sta && elems->wmm_info) set_sta_flag(sta, WLAN_STA_WME); if (sta && elems->ht_info_elem && 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; enum nl80211_channel_type channel_type = ieee80211_ht_info_to_channel_type( elems->ht_info_elem); ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, elems->ht_cap_elem, &sta_ht_cap_new); /* * fall back to HT20 if we don't use or use * the other extension channel */ if ((channel_type == NL80211_CHAN_HT40MINUS || channel_type == NL80211_CHAN_HT40PLUS) && channel_type != 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; } } if (sta && rates_updated) rate_control_rate_init(sta); rcu_read_unlock(); } bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, channel, beacon); if (!bss) return; cbss = container_of((void *)bss, struct cfg80211_bss, priv); /* was just updated in ieee80211_bss_info_update */ beacon_timestamp = cbss->tsf; /* check if we need to merge IBSS */ /* we use a fixed BSSID */ if (sdata->u.ibss.fixed_bssid) goto put_bss; /* not an IBSS */ if (!(cbss->capability & WLAN_CAPABILITY_IBSS)) goto put_bss; /* different channel */ if (cbss->channel != local->oper_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; /* same BSSID */ if (memcmp(cbss->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) goto put_bss; if (rx_status->flag & RX_FLAG_MACTIME_MPDU) { /* * For correct IBSS merging we need mactime; since mactime is * defined as the time the first data symbol of the frame hits * the PHY, and the timestamp of the beacon is defined as "the * time that the data symbol containing the first bit of the * timestamp is transmitted to the PHY plus the transmitting * STA's delays through its local PHY from the MAC-PHY * interface to its interface with the WM" (802.11 11.1.2) * - equals the time this bit arrives at the receiver - we have * to take into account the offset between the two. * * E.g. at 1 MBit that means mactime is 192 usec earlier * (=24 bytes * 8 usecs/byte) than the beacon timestamp. */ int rate; if (rx_status->flag & RX_FLAG_HT) rate = 65; /* TODO: HT rates */ else rate = local->hw.wiphy->bands[band]-> bitrates[rx_status->rate_idx].bitrate; rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); } else { /* * second best option: get current TSF * (will return -1 if not supported) */ rx_timestamp = drv_get_tsf(local, sdata); } #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", mgmt->sa, mgmt->bssid, (unsigned long long)rx_timestamp, (unsigned long long)beacon_timestamp, (unsigned long long)(rx_timestamp - beacon_timestamp), jiffies); #endif if (beacon_timestamp > rx_timestamp) { #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: beacon TSF higher than " "local TSF - IBSS merge with BSSID %pM\n", sdata->name, mgmt->bssid); #endif ieee80211_sta_join_ibss(sdata, bss); supp_rates = ieee80211_sta_get_rates(local, elems, band); ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); rcu_read_unlock(); } put_bss: ieee80211_rx_bss_put(local, bss); }