📄 ieee80211_sta.c
字号:
if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) { ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status); } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) { ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status); } } dev_kfree_skb(skb);}static int ieee80211_sta_active_ibss(struct net_device *dev){ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); int active = 0; struct sta_info *sta; read_lock_bh(&local->sta_lock); list_for_each_entry(sta, &local->sta_list, list) { if (sta->dev == dev && time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, jiffies)) { active++; break; } } read_unlock_bh(&local->sta_lock); return active;}static void ieee80211_sta_expire(struct net_device *dev){ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta, *tmp; LIST_HEAD(tmp_list); DECLARE_MAC_BUF(mac); write_lock_bh(&local->sta_lock); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) if (time_after(jiffies, sta->last_rx + IEEE80211_IBSS_INACTIVITY_LIMIT)) { printk(KERN_DEBUG "%s: expiring inactive STA %s\n", dev->name, print_mac(mac, sta->addr)); __sta_info_get(sta); sta_info_remove(sta); list_add(&sta->list, &tmp_list); } write_unlock_bh(&local->sta_lock); list_for_each_entry_safe(sta, tmp, &tmp_list, list) { sta_info_free(sta); sta_info_put(sta); }}static void ieee80211_sta_merge_ibss(struct net_device *dev, struct ieee80211_if_sta *ifsta){ mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); ieee80211_sta_expire(dev); if (ieee80211_sta_active_ibss(dev)) return; printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " "IBSS networks with same SSID (merge)\n", dev->name); ieee80211_sta_req_scan(dev, ifsta->ssid, ifsta->ssid_len);}void ieee80211_sta_timer(unsigned long data){ struct ieee80211_sub_if_data *sdata = (struct ieee80211_sub_if_data *) data; struct ieee80211_if_sta *ifsta = &sdata->u.sta; struct ieee80211_local *local = wdev_priv(&sdata->wdev); set_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); queue_work(local->hw.workqueue, &ifsta->work);}void ieee80211_sta_work(struct work_struct *work){ struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, u.sta.work); struct net_device *dev = sdata->dev; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_if_sta *ifsta; struct sk_buff *skb; if (!netif_running(dev)) return; if (local->sta_scanning) return; if (sdata->type != IEEE80211_IF_TYPE_STA && sdata->type != IEEE80211_IF_TYPE_IBSS) { printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface " "(type=%d)\n", dev->name, sdata->type); return; } ifsta = &sdata->u.sta; while ((skb = skb_dequeue(&ifsta->skb_queue))) ieee80211_sta_rx_queued_mgmt(dev, skb); if (ifsta->state != IEEE80211_AUTHENTICATE && ifsta->state != IEEE80211_ASSOCIATE && test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { if (ifsta->scan_ssid_len) ieee80211_sta_start_scan(dev, ifsta->scan_ssid, ifsta->scan_ssid_len); else ieee80211_sta_start_scan(dev, NULL, 0); return; } if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) { if (ieee80211_sta_config_auth(dev, ifsta)) return; clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request)) return; switch (ifsta->state) { case IEEE80211_DISABLED: break; case IEEE80211_AUTHENTICATE: ieee80211_authenticate(dev, ifsta); break; case IEEE80211_ASSOCIATE: ieee80211_associate(dev, ifsta); break; case IEEE80211_ASSOCIATED: ieee80211_associated(dev, ifsta); break; case IEEE80211_IBSS_SEARCH: ieee80211_sta_find_ibss(dev, ifsta); break; case IEEE80211_IBSS_JOINED: ieee80211_sta_merge_ibss(dev, ifsta); break; default: printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n", ifsta->state); break; } if (ieee80211_privacy_mismatch(dev, ifsta)) { printk(KERN_DEBUG "%s: privacy configuration mismatch and " "mixed-cell disabled - disassociate\n", dev->name); ieee80211_send_disassoc(dev, ifsta, WLAN_REASON_UNSPECIFIED); ieee80211_set_disassoc(dev, ifsta, 0); }}static void ieee80211_sta_reset_auth(struct net_device *dev, struct ieee80211_if_sta *ifsta){ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); if (local->ops->reset_tsf) { /* Reset own TSF to allow time synchronization work. */ local->ops->reset_tsf(local_to_hw(local)); } ifsta->wmm_last_param_set = -1; /* allow any WMM update */ if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) ifsta->auth_alg = WLAN_AUTH_OPEN; else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) ifsta->auth_alg = WLAN_AUTH_SHARED_KEY; else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) ifsta->auth_alg = WLAN_AUTH_LEAP; else ifsta->auth_alg = WLAN_AUTH_OPEN; printk(KERN_DEBUG "%s: Initial auth_alg=%d\n", dev->name, ifsta->auth_alg); ifsta->auth_transaction = -1; ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; ifsta->auth_tries = ifsta->assoc_tries = 0; netif_carrier_off(dev);}void ieee80211_sta_req_auth(struct net_device *dev, struct ieee80211_if_sta *ifsta){ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type != IEEE80211_IF_TYPE_STA) return; if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | IEEE80211_STA_AUTO_BSSID_SEL)) && (ifsta->flags & (IEEE80211_STA_SSID_SET | IEEE80211_STA_AUTO_SSID_SEL))) { set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); queue_work(local->hw.workqueue, &ifsta->work); }}static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, const char *ssid, int ssid_len){ int tmp, hidden_ssid; if (ssid_len == ifsta->ssid_len && !memcmp(ifsta->ssid, ssid, ssid_len)) return 1; if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) return 0; hidden_ssid = 1; tmp = ssid_len; while (tmp--) { if (ssid[tmp] != '\0') { hidden_ssid = 0; break; } } if (hidden_ssid && ifsta->ssid_len == ssid_len) return 1; if (ssid_len == 1 && ssid[0] == ' ') return 1; return 0;}static int ieee80211_sta_config_auth(struct net_device *dev, struct ieee80211_if_sta *ifsta){ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sta_bss *bss, *selected = NULL; int top_rssi = 0, freq; if (!(ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL))) { ifsta->state = IEEE80211_AUTHENTICATE; ieee80211_sta_reset_auth(dev, ifsta); return 0; } spin_lock_bh(&local->sta_bss_lock); freq = local->oper_channel->freq; list_for_each_entry(bss, &local->sta_bss_list, list) { if (!(bss->capability & WLAN_CAPABILITY_ESS)) continue; if (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^ !!sdata->default_key) continue; if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) && bss->freq != freq) continue; if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) && memcmp(bss->bssid, ifsta->bssid, ETH_ALEN)) continue; if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) && !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) continue; if (!selected || top_rssi < bss->rssi) { selected = bss; top_rssi = bss->rssi; } } if (selected) atomic_inc(&selected->users); spin_unlock_bh(&local->sta_bss_lock); if (selected) { ieee80211_set_channel(local, -1, selected->freq); if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) ieee80211_sta_set_ssid(dev, selected->ssid, selected->ssid_len); ieee80211_sta_set_bssid(dev, selected->bssid); ieee80211_rx_bss_put(dev, selected); ifsta->state = IEEE80211_AUTHENTICATE; ieee80211_sta_reset_auth(dev, ifsta); return 0; } else { if (ifsta->state != IEEE80211_AUTHENTICATE) { if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) ieee80211_sta_start_scan(dev, NULL, 0); else ieee80211_sta_start_scan(dev, ifsta->ssid, ifsta->ssid_len); ifsta->state = IEEE80211_AUTHENTICATE; set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); } else ifsta->state = IEEE80211_DISABLED; } return -1;}static int ieee80211_sta_join_ibss(struct net_device *dev, struct ieee80211_if_sta *ifsta, struct ieee80211_sta_bss *bss){ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); int res, rates, i, j; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; struct ieee80211_tx_control control; struct ieee80211_rate *rate; struct ieee80211_hw_mode *mode; struct rate_control_extra extra; u8 *pos; struct ieee80211_sub_if_data *sdata; /* Remove possible STA entries from other IBSS networks. */ sta_info_flush(local, NULL); if (local->ops->reset_tsf) { /* Reset own TSF to allow time synchronization work. */ local->ops->reset_tsf(local_to_hw(local)); } memcpy(ifsta->bssid, bss->bssid, ETH_ALEN); res = ieee80211_if_config(dev); if (res) return res; local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata->drop_unencrypted = bss->capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; res = ieee80211_set_channel(local, -1, bss->freq); if (!(local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)) { printk(KERN_DEBUG "%s: IBSS not allowed on channel %d " "(%d MHz)\n", dev->name, local->hw.conf.channel, local->hw.conf.freq); return -1; } /* Set beacon template based on scan results */ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); do { if (!skb) break; skb_reserve(skb, local->hw.extra_tx_headroom); mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + sizeof(mgmt->u.beacon)); memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, IEEE80211_STYPE_BEACON); memset(mgmt->da, 0xff, ETH_ALEN); memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); mgmt->u.beacon.beacon_int = cpu_to_le16(local->hw.conf.beacon_int); mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability); pos = skb_put(skb, 2 + ifsta->ssid_len); *pos++ = WLAN_EID_SSID; *pos++ = ifsta->ssid_len; memcpy(pos, ifsta->ssid, ifsta->ssid_len); rates = bss->supp_rates_len; if (rates > 8) rates = 8; pos = skb_put(skb, 2 + rates); *pos++ = WLAN_EID_SUPP_RATES; *pos++ = rates; memcpy(pos, bss->supp_rates, rates); pos = skb_put(skb, 2 + 1); *pos++ = WLAN_EID_DS_PARAMS; *pos++ = 1; *pos++ = bss->channel; pos = skb_put(skb, 2 + 2); *pos++ = WLAN_EID_IBSS_PARAMS; *pos++ = 2; /* FIX: set ATIM window based on scan results */ *pos++ = 0; *pos++ = 0; if (bss->supp_rates_len > 8) { rates = bss->supp_rates_len - 8; pos = skb_put(skb, 2 + rates); *pos++ = WLAN_EID_EXT_SUPP_RATES; *pos++ = rates; memcpy(pos, &bss->supp_rates[8], rates); } memset(&control, 0, sizeof(control)); memset(&extra, 0, sizeof(extra)); extra.mode = local->oper_hw_mode; rate = rate_control_get_rate(local, dev, skb, &extra); if (!rate) { printk(KERN_DEBUG "%s: Failed to determine TX rate " "for IBSS beacon\n", dev->name); break; } control.tx_rate = ((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) && (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? rate->val2 : rate->val; control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; control.power_level = local->hw.conf.power_level; control.flags |= IEEE80211_TXCTL_NO_ACK; control.retry_limit = 1; ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC); if (ifsta->probe_resp) { mgmt = (struct ieee80211_mgmt *) ifsta->probe_resp->data; mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, IEEE80211_STYPE_PROBE_RESP); } else { printk(KERN_DEBUG "%s: Could not allocate ProbeResp " "template for IBSS\n", dev->name); } if (local->ops->beacon_update && local->ops->beacon_update(local_to_hw(local), skb, &control) == 0) { printk(KERN_DEBUG "%s: Configured IBSS beacon " "template based on scan results\n", dev->name); skb = NULL; } rates = 0; mode = local->oper_hw_mode; for (i = 0; i < bss->supp_rates_len; i++) { int bitrate = (bss->supp_rates[i] & 0x7f) * 5; for (j = 0; j < mode->num_rates; j++) if (mode->rates[j].rate == bitrate) rates |= BIT(j); } ifsta->supp_rates_bits = rates; } while (0); if (skb) { printk(KERN_DEBUG "%s: Failed to configure IBSS beacon " "template\n", dev->name); dev_kfree_skb(skb); } ifsta->state = IEEE80211_IBSS_JOINED; mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); ieee80211_rx_bss_put
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -