📄 ieee80211_sta.c
字号:
list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list) ieee80211_rx_bss_put(dev, bss);}static void ieee80211_rx_bss_info(struct net_device *dev, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status, int beacon){ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee802_11_elems elems; size_t baselen; int channel, clen; struct ieee80211_sta_bss *bss; struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); u64 timestamp; DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac2); if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN)) return; /* ignore ProbeResp to foreign address */#if 0 printk(KERN_DEBUG "%s: RX %s from %s to %s\n", dev->name, beacon ? "Beacon" : "Probe Response", print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da));#endif baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; if (baselen > len) return; timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); if (sdata->type == IEEE80211_IF_TYPE_IBSS && beacon && memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {#ifdef CONFIG_MAC80211_IBSS_DEBUG static unsigned long last_tsf_debug = 0; u64 tsf; if (local->ops->get_tsf) tsf = local->ops->get_tsf(local_to_hw(local)); else tsf = -1LLU; if (time_after(jiffies, last_tsf_debug + 5 * HZ)) { printk(KERN_DEBUG "RX beacon SA=%s BSSID=" "%s TSF=0x%llx BCN=0x%llx diff=%lld " "@%lu\n", print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->bssid), (unsigned long long)tsf, (unsigned long long)timestamp, (unsigned long long)(tsf - timestamp), jiffies); last_tsf_debug = jiffies; }#endif /* CONFIG_MAC80211_IBSS_DEBUG */ } ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); if (sdata->type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && (sta = sta_info_get(local, mgmt->sa))) { struct ieee80211_hw_mode *mode; struct ieee80211_rate *rates; size_t num_rates; u32 supp_rates, prev_rates; int i, j; mode = local->sta_scanning ? local->scan_hw_mode : local->oper_hw_mode; rates = mode->rates; num_rates = mode->num_rates; supp_rates = 0; for (i = 0; i < elems.supp_rates_len + elems.ext_supp_rates_len; i++) { u8 rate = 0; int own_rate; if (i < elems.supp_rates_len) rate = elems.supp_rates[i]; else if (elems.ext_supp_rates) rate = elems.ext_supp_rates [i - elems.supp_rates_len]; own_rate = 5 * (rate & 0x7f); for (j = 0; j < num_rates; j++) if (rates[j].rate == own_rate) supp_rates |= BIT(j); } prev_rates = sta->supp_rates; sta->supp_rates &= supp_rates; if (sta->supp_rates == 0) { /* No matching rates - this should not really happen. * Make sure that at least one rate is marked * supported to avoid issues with TX rate ctrl. */ sta->supp_rates = sdata->u.sta.supp_rates_bits; } if (sta->supp_rates != prev_rates) { printk(KERN_DEBUG "%s: updated supp_rates set for " "%s based on beacon info (0x%x & 0x%x -> " "0x%x)\n", dev->name, print_mac(mac, sta->addr), prev_rates, supp_rates, sta->supp_rates); } sta_info_put(sta); } if (!elems.ssid) return; if (elems.ds_params && elems.ds_params_len == 1) channel = elems.ds_params[0]; else channel = rx_status->channel; bss = ieee80211_rx_bss_get(dev, mgmt->bssid, channel, elems.ssid, elems.ssid_len); if (!bss) { bss = ieee80211_rx_bss_add(dev, mgmt->bssid, channel, elems.ssid, elems.ssid_len); if (!bss) return; } else {#if 0 /* TODO: order by RSSI? */ spin_lock_bh(&local->sta_bss_lock); list_move_tail(&bss->list, &local->sta_bss_list); spin_unlock_bh(&local->sta_bss_lock);#endif } if (bss->probe_resp && beacon) { /* Do not allow beacon to override data from Probe Response. */ ieee80211_rx_bss_put(dev, bss); return; } /* 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); 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; } if (elems.wpa && (!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len || memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) { kfree(bss->wpa_ie); bss->wpa_ie = kmalloc(elems.wpa_len + 2, GFP_ATOMIC); if (bss->wpa_ie) { memcpy(bss->wpa_ie, elems.wpa - 2, elems.wpa_len + 2); bss->wpa_ie_len = elems.wpa_len + 2; } else bss->wpa_ie_len = 0; } else if (!elems.wpa && bss->wpa_ie) { kfree(bss->wpa_ie); bss->wpa_ie = NULL; bss->wpa_ie_len = 0; } if (elems.rsn && (!bss->rsn_ie || bss->rsn_ie_len != elems.rsn_len || memcmp(bss->rsn_ie, elems.rsn, elems.rsn_len))) { kfree(bss->rsn_ie); bss->rsn_ie = kmalloc(elems.rsn_len + 2, GFP_ATOMIC); if (bss->rsn_ie) { memcpy(bss->rsn_ie, elems.rsn - 2, elems.rsn_len + 2); bss->rsn_ie_len = elems.rsn_len + 2; } else bss->rsn_ie_len = 0; } else if (!elems.rsn && bss->rsn_ie) { kfree(bss->rsn_ie); bss->rsn_ie = NULL; bss->rsn_ie_len = 0; } if (elems.wmm_param && (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len || memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) { kfree(bss->wmm_ie); bss->wmm_ie = kmalloc(elems.wmm_param_len + 2, GFP_ATOMIC); if (bss->wmm_ie) { memcpy(bss->wmm_ie, elems.wmm_param - 2, elems.wmm_param_len + 2); bss->wmm_ie_len = elems.wmm_param_len + 2; } else bss->wmm_ie_len = 0; } else if (!elems.wmm_param && bss->wmm_ie) { kfree(bss->wmm_ie); bss->wmm_ie = NULL; bss->wmm_ie_len = 0; } bss->hw_mode = rx_status->phymode; bss->freq = rx_status->freq; if (channel != rx_status->channel && (bss->hw_mode == MODE_IEEE80211G || bss->hw_mode == MODE_IEEE80211B) && channel >= 1 && channel <= 14) { static const int freq_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; /* IEEE 802.11g/b mode can receive packets from neighboring * channels, so map the channel into frequency. */ bss->freq = freq_list[channel - 1]; } bss->timestamp = timestamp; bss->last_update = jiffies; bss->rssi = rx_status->ssi; bss->signal = rx_status->signal; bss->noise = rx_status->noise; if (!beacon) bss->probe_resp++; ieee80211_rx_bss_put(dev, bss);}static void ieee80211_rx_mgmt_probe_resp(struct net_device *dev, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status){ ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 0);}static void ieee80211_rx_mgmt_beacon(struct net_device *dev, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status){ struct ieee80211_sub_if_data *sdata; struct ieee80211_if_sta *ifsta; size_t baselen; struct ieee802_11_elems elems; ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1); sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type != IEEE80211_IF_TYPE_STA) return; ifsta = &sdata->u.sta; if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED) || memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) return; /* 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); if (elems.erp_info && elems.erp_info_len >= 1) ieee80211_handle_erp_ie(dev, elems.erp_info[0]); if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, elems.wmm_param_len); }}static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, struct ieee80211_if_sta *ifsta, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status){ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); int tx_last_beacon; struct sk_buff *skb; struct ieee80211_mgmt *resp; u8 *pos, *end; DECLARE_MAC_BUF(mac);#ifdef CONFIG_MAC80211_IBSS_DEBUG DECLARE_MAC_BUF(mac2); DECLARE_MAC_BUF(mac3);#endif if (sdata->type != IEEE80211_IF_TYPE_IBSS || ifsta->state != IEEE80211_IBSS_JOINED || len < 24 + 2 || !ifsta->probe_resp) return; if (local->ops->tx_last_beacon) tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local)); else tx_last_beacon = 1;#ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: RX ProbeReq SA=%s DA=%s BSSID=" "%s (tx_last_beacon=%d)\n", dev->name, print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da), print_mac(mac3, mgmt->bssid), tx_last_beacon);#endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (!tx_last_beacon) return; if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0 && memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) return; end = ((u8 *) mgmt) + len; pos = mgmt->u.probe_req.variable; if (pos[0] != WLAN_EID_SSID || pos + 2 + pos[1] > end) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " "from %s\n", dev->name, print_mac(mac, mgmt->sa)); } return; } if (pos[1] != 0 && (pos[1] != ifsta->ssid_len || memcmp(pos + 2, ifsta->ssid, ifsta->ssid_len) != 0)) { /* Ignore ProbeReq for foreign SSID */ return; } /* Reply with ProbeResp */ skb = skb_copy(ifsta->probe_resp, GFP_KERNEL); if (!skb) return; resp = (struct ieee80211_mgmt *) skb->data; memcpy(resp->da, mgmt->sa, ETH_ALEN);#ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n", dev->name, print_mac(mac, resp->da));#endif /* CONFIG_MAC80211_IBSS_DEBUG */ ieee80211_sta_tx(dev, skb, 0);}void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb, struct ieee80211_rx_status *rx_status){ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata; struct ieee80211_if_sta *ifsta; struct ieee80211_mgmt *mgmt; u16 fc; if (skb->len < 24) goto fail; sdata = IEEE80211_DEV_TO_SUB_IF(dev); ifsta = &sdata->u.sta; mgmt = (struct ieee80211_mgmt *) skb->data; fc = le16_to_cpu(mgmt->frame_control); switch (fc & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_PROBE_REQ: case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: memcpy(skb->cb, rx_status, sizeof(*rx_status)); case IEEE80211_STYPE_AUTH: case IEEE80211_STYPE_ASSOC_RESP: case IEEE80211_STYPE_REASSOC_RESP: case IEEE80211_STYPE_DEAUTH: case IEEE80211_STYPE_DISASSOC: skb_queue_tail(&ifsta->skb_queue, skb); queue_work(local->hw.workqueue, &ifsta->work); return; default: printk(KERN_DEBUG "%s: received unknown management frame - " "stype=%d\n", dev->name, (fc & IEEE80211_FCTL_STYPE) >> 4); break; } fail: kfree_skb(skb);}static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev, struct sk_buff *skb){ struct ieee80211_rx_status *rx_status; struct ieee80211_sub_if_data *sdata; struct ieee80211_if_sta *ifsta; struct ieee80211_mgmt *mgmt; u16 fc; sdata = IEEE80211_DEV_TO_SUB_IF(dev); ifsta = &sdata->u.sta; rx_status = (struct ieee80211_rx_status *) skb->cb; mgmt = (struct ieee80211_mgmt *) skb->data; fc = le16_to_cpu(mgmt->frame_control); switch (fc & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_PROBE_REQ: ieee80211_rx_mgmt_probe_req(dev, ifsta, mgmt, skb->len, rx_status); break; case IEEE80211_STYPE_PROBE_RESP: ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status); break; case IEEE80211_STYPE_BEACON: ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status); break; case IEEE80211_STYPE_AUTH: ieee80211_rx_mgmt_auth(dev, ifsta, mgmt, skb->len); break; case IEEE80211_STYPE_ASSOC_RESP: ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len, 0); break; case IEEE80211_STYPE_REASSOC_RESP: ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len, 1); break; case IEEE80211_STYPE_DEAUTH: ieee80211_rx_mgmt_deauth(dev, ifsta, mgmt, skb->len); break; case IEEE80211_STYPE_DISASSOC: ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len); break; } kfree_skb(skb);}void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, struct ieee80211_rx_status *rx_status){ struct ieee80211_mgmt *mgmt; u16 fc; if (skb->len < 24) { dev_kfree_skb(skb); return; } mgmt = (struct ieee80211_mgmt *) skb->data; fc = le16_to_cpu(mgmt->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -