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

📄 ieee80211_sta.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * BSS client mode implementation * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> * Copyright 2004, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz> * Copyright 2007, Michael Wu <flamingice@sourmilk.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. *//* TODO: * order BSS list by RSSI(?) ("quality of AP") * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE, *    SSID) */#include <linux/delay.h>#include <linux/if_ether.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/if_arp.h>#include <linux/wireless.h>#include <linux/random.h>#include <linux/etherdevice.h>#include <net/iw_handler.h>#include <asm/types.h>#include <net/mac80211.h>#include "ieee80211_i.h"#include "ieee80211_rate.h"#include "ieee80211_led.h"#define IEEE80211_AUTH_TIMEOUT (HZ / 5)#define IEEE80211_AUTH_MAX_TRIES 3#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)#define IEEE80211_ASSOC_MAX_TRIES 3#define IEEE80211_MONITORING_INTERVAL (2 * HZ)#define IEEE80211_PROBE_INTERVAL (60 * HZ)#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)#define IEEE80211_SCAN_INTERVAL (2 * HZ)#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)#define IEEE80211_IBSS_JOIN_TIMEOUT (20 * HZ)#define IEEE80211_PROBE_DELAY (HZ / 33)#define IEEE80211_CHANNEL_TIME (HZ / 33)#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)#define IEEE80211_IBSS_MAX_STA_ENTRIES 128#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype)#define ERP_INFO_USE_PROTECTION BIT(1)static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,				     u8 *ssid, size_t ssid_len);static struct ieee80211_sta_bss *ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel,		     u8 *ssid, u8 ssid_len);static void ieee80211_rx_bss_put(struct net_device *dev,				 struct ieee80211_sta_bss *bss);static int ieee80211_sta_find_ibss(struct net_device *dev,				   struct ieee80211_if_sta *ifsta);static int ieee80211_sta_wep_configured(struct net_device *dev);static int ieee80211_sta_start_scan(struct net_device *dev,				    u8 *ssid, size_t ssid_len);static int ieee80211_sta_config_auth(struct net_device *dev,				     struct ieee80211_if_sta *ifsta);/* Parsed Information Elements */struct ieee802_11_elems {	/* pointers to IEs */	u8 *ssid;	u8 *supp_rates;	u8 *fh_params;	u8 *ds_params;	u8 *cf_params;	u8 *tim;	u8 *ibss_params;	u8 *challenge;	u8 *wpa;	u8 *rsn;	u8 *erp_info;	u8 *ext_supp_rates;	u8 *wmm_info;	u8 *wmm_param;	/* length of them, respectively */	u8 ssid_len;	u8 supp_rates_len;	u8 fh_params_len;	u8 ds_params_len;	u8 cf_params_len;	u8 tim_len;	u8 ibss_params_len;	u8 challenge_len;	u8 wpa_len;	u8 rsn_len;	u8 erp_info_len;	u8 ext_supp_rates_len;	u8 wmm_info_len;	u8 wmm_param_len;};static void ieee802_11_parse_elems(u8 *start, size_t len,				   struct ieee802_11_elems *elems){	size_t left = len;	u8 *pos = start;	memset(elems, 0, sizeof(*elems));	while (left >= 2) {		u8 id, elen;		id = *pos++;		elen = *pos++;		left -= 2;		if (elen > left)			return;		switch (id) {		case WLAN_EID_SSID:			elems->ssid = pos;			elems->ssid_len = elen;			break;		case WLAN_EID_SUPP_RATES:			elems->supp_rates = pos;			elems->supp_rates_len = elen;			break;		case WLAN_EID_FH_PARAMS:			elems->fh_params = pos;			elems->fh_params_len = elen;			break;		case WLAN_EID_DS_PARAMS:			elems->ds_params = pos;			elems->ds_params_len = elen;			break;		case WLAN_EID_CF_PARAMS:			elems->cf_params = pos;			elems->cf_params_len = elen;			break;		case WLAN_EID_TIM:			elems->tim = pos;			elems->tim_len = elen;			break;		case WLAN_EID_IBSS_PARAMS:			elems->ibss_params = pos;			elems->ibss_params_len = elen;			break;		case WLAN_EID_CHALLENGE:			elems->challenge = pos;			elems->challenge_len = elen;			break;		case WLAN_EID_WPA:			if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&			    pos[2] == 0xf2) {				/* Microsoft OUI (00:50:F2) */				if (pos[3] == 1) {					/* OUI Type 1 - WPA IE */					elems->wpa = pos;					elems->wpa_len = elen;				} else if (elen >= 5 && pos[3] == 2) {					if (pos[4] == 0) {						elems->wmm_info = pos;						elems->wmm_info_len = elen;					} else if (pos[4] == 1) {						elems->wmm_param = pos;						elems->wmm_param_len = elen;					}				}			}			break;		case WLAN_EID_RSN:			elems->rsn = pos;			elems->rsn_len = elen;			break;		case WLAN_EID_ERP_INFO:			elems->erp_info = pos;			elems->erp_info_len = elen;			break;		case WLAN_EID_EXT_SUPP_RATES:			elems->ext_supp_rates = pos;			elems->ext_supp_rates_len = elen;			break;		default:			break;		}		left -= elen;		pos += elen;	}}static int ecw2cw(int ecw){	int cw = 1;	while (ecw > 0) {		cw <<= 1;		ecw--;	}	return cw - 1;}static void ieee80211_sta_wmm_params(struct net_device *dev,				     struct ieee80211_if_sta *ifsta,				     u8 *wmm_param, size_t wmm_param_len){	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);	struct ieee80211_tx_queue_params params;	size_t left;	int count;	u8 *pos;	if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)		return;	count = wmm_param[6] & 0x0f;	if (count == ifsta->wmm_last_param_set)		return;	ifsta->wmm_last_param_set = count;	pos = wmm_param + 8;	left = wmm_param_len - 8;	memset(&params, 0, sizeof(params));	if (!local->ops->conf_tx)		return;	local->wmm_acm = 0;	for (; left >= 4; left -= 4, pos += 4) {		int aci = (pos[0] >> 5) & 0x03;		int acm = (pos[0] >> 4) & 0x01;		int queue;		switch (aci) {		case 1:			queue = IEEE80211_TX_QUEUE_DATA3;			if (acm) {				local->wmm_acm |= BIT(0) | BIT(3);			}			break;		case 2:			queue = IEEE80211_TX_QUEUE_DATA1;			if (acm) {				local->wmm_acm |= BIT(4) | BIT(5);			}			break;		case 3:			queue = IEEE80211_TX_QUEUE_DATA0;			if (acm) {				local->wmm_acm |= BIT(6) | BIT(7);			}			break;		case 0:		default:			queue = IEEE80211_TX_QUEUE_DATA2;			if (acm) {				local->wmm_acm |= BIT(1) | BIT(2);			}			break;		}		params.aifs = pos[0] & 0x0f;		params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);		params.cw_min = ecw2cw(pos[1] & 0x0f);		/* TXOP is in units of 32 usec; burst_time in 0.1 ms */		params.burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100;		printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "		       "cWmin=%d cWmax=%d burst=%d\n",		       dev->name, queue, aci, acm, params.aifs, params.cw_min,		       params.cw_max, params.burst_time);		/* TODO: handle ACM (block TX, fallback to next lowest allowed		 * AC for now) */		if (local->ops->conf_tx(local_to_hw(local), queue, &params)) {			printk(KERN_DEBUG "%s: failed to set TX queue "			       "parameters for queue %d\n", dev->name, queue);		}	}}static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value){	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);	struct ieee80211_if_sta *ifsta = &sdata->u.sta;	int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;	int preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0;	u8 changes = 0;	DECLARE_MAC_BUF(mac);	if (use_protection != !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION)) {		if (net_ratelimit()) {			printk(KERN_DEBUG "%s: CTS protection %s (BSSID="			       "%s)\n",			       dev->name,			       use_protection ? "enabled" : "disabled",			       print_mac(mac, ifsta->bssid));		}		if (use_protection)			sdata->flags |= IEEE80211_SDATA_USE_PROTECTION;		else			sdata->flags &= ~IEEE80211_SDATA_USE_PROTECTION;		changes |= IEEE80211_ERP_CHANGE_PROTECTION;	}	if (preamble_mode != !(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE)) {		if (net_ratelimit()) {			printk(KERN_DEBUG "%s: switched to %s barker preamble"			       " (BSSID=%s)\n",			       dev->name,			       (preamble_mode == WLAN_ERP_PREAMBLE_SHORT) ?					"short" : "long",			       print_mac(mac, ifsta->bssid));		}		if (preamble_mode)			sdata->flags &= ~IEEE80211_SDATA_SHORT_PREAMBLE;		else			sdata->flags |= IEEE80211_SDATA_SHORT_PREAMBLE;		changes |= IEEE80211_ERP_CHANGE_PREAMBLE;	}	if (changes)		ieee80211_erp_info_change_notify(dev, changes);}static void ieee80211_sta_send_associnfo(struct net_device *dev,					 struct ieee80211_if_sta *ifsta){	char *buf;	size_t len;	int i;	union iwreq_data wrqu;	if (!ifsta->assocreq_ies && !ifsta->assocresp_ies)		return;	buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len +				ifsta->assocresp_ies_len), GFP_KERNEL);	if (!buf)		return;	len = sprintf(buf, "ASSOCINFO(");	if (ifsta->assocreq_ies) {		len += sprintf(buf + len, "ReqIEs=");		for (i = 0; i < ifsta->assocreq_ies_len; i++) {			len += sprintf(buf + len, "%02x",				       ifsta->assocreq_ies[i]);		}	}	if (ifsta->assocresp_ies) {		if (ifsta->assocreq_ies)			len += sprintf(buf + len, " ");		len += sprintf(buf + len, "RespIEs=");		for (i = 0; i < ifsta->assocresp_ies_len; i++) {			len += sprintf(buf + len, "%02x",				       ifsta->assocresp_ies[i]);		}	}	len += sprintf(buf + len, ")");	if (len > IW_CUSTOM_MAX) {		len = sprintf(buf, "ASSOCRESPIE=");		for (i = 0; i < ifsta->assocresp_ies_len; i++) {			len += sprintf(buf + len, "%02x",				       ifsta->assocresp_ies[i]);		}	}	memset(&wrqu, 0, sizeof(wrqu));	wrqu.data.length = len;	wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);	kfree(buf);}static void ieee80211_set_associated(struct net_device *dev,				     struct ieee80211_if_sta *ifsta,				     bool assoc){	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);	union iwreq_data wrqu;	if (!!(ifsta->flags & IEEE80211_STA_ASSOCIATED) == assoc)		return;	if (assoc) {		struct ieee80211_sub_if_data *sdata;		struct ieee80211_sta_bss *bss;		ifsta->flags |= IEEE80211_STA_ASSOCIATED;		sdata = IEEE80211_DEV_TO_SUB_IF(dev);		if (sdata->type != IEEE80211_IF_TYPE_STA)			return;		bss = ieee80211_rx_bss_get(dev, ifsta->bssid,					   local->hw.conf.channel,					   ifsta->ssid, ifsta->ssid_len);		if (bss) {			if (bss->has_erp_value)				ieee80211_handle_erp_ie(dev, bss->erp_value);			ieee80211_rx_bss_put(dev, bss);		}		netif_carrier_on(dev);		ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;		memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);		memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);		ieee80211_sta_send_associnfo(dev, ifsta);	} else {		ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;		netif_carrier_off(dev);		ieee80211_reset_erp_info(dev);		memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);	}	wrqu.ap_addr.sa_family = ARPHRD_ETHER;	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);	ifsta->last_probe = jiffies;	ieee80211_led_assoc(local, assoc);}static void ieee80211_set_disassoc(struct net_device *dev,				   struct ieee80211_if_sta *ifsta, int deauth){	if (deauth)		ifsta->auth_tries = 0;	ifsta->assoc_tries = 0;	ieee80211_set_associated(dev, ifsta, 0);}static void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,			     int encrypt){	struct ieee80211_sub_if_data *sdata;	struct ieee80211_tx_packet_data *pkt_data;	sdata = IEEE80211_DEV_TO_SUB_IF(dev);	skb->dev = sdata->local->mdev;	skb_set_mac_header(skb, 0);	skb_set_network_header(skb, 0);	skb_set_transport_header(skb, 0);	pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;	memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));	pkt_data->ifindex = sdata->dev->ifindex;	if (!encrypt)		pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;	dev_queue_xmit(skb);}static void ieee80211_send_auth(struct net_device *dev,				struct ieee80211_if_sta *ifsta,				int transaction, u8 *extra, size_t extra_len,				int encrypt){	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);	struct sk_buff *skb;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -