⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ieee80211_sta.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 + -