diff options
Diffstat (limited to 'drivers/net/wireless/libertas/scan.c')
| -rw-r--r-- | drivers/net/wireless/libertas/scan.c | 250 | 
1 files changed, 200 insertions, 50 deletions
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 6c95af3023c..c6a6c042b82 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -12,18 +12,19 @@  #include <net/lib80211.h>  #include "host.h" -#include "decl.h"  #include "dev.h"  #include "scan.h" +#include "assoc.h" +#include "wext.h"  #include "cmd.h"  //! Approximate amount of data needed to pass a scan result back to iwlist  #define MAX_SCAN_CELL_SIZE  (IW_EV_ADDR_LEN             \ -                             + IW_ESSID_MAX_SIZE        \ +                             + IEEE80211_MAX_SSID_LEN   \                               + IW_EV_UINT_LEN           \                               + IW_EV_FREQ_LEN           \                               + IW_EV_QUAL_LEN           \ -                             + IW_ESSID_MAX_SIZE        \ +                             + IEEE80211_MAX_SSID_LEN   \                               + IW_EV_PARAM_LEN          \                               + 40)	/* 40 for WPAIE */ @@ -121,6 +122,189 @@ static inline int is_same_network(struct bss_descriptor *src, +/*********************************************************************/ +/*                                                                   */ +/* Region channel support                                            */ +/*                                                                   */ +/*********************************************************************/ + +#define LBS_TX_PWR_DEFAULT		20	/*100mW */ +#define LBS_TX_PWR_US_DEFAULT		20	/*100mW */ +#define LBS_TX_PWR_JP_DEFAULT		16	/*50mW */ +#define LBS_TX_PWR_FR_DEFAULT		20	/*100mW */ +#define LBS_TX_PWR_EMEA_DEFAULT	20	/*100mW */ + +/* Format { channel, frequency (MHz), maxtxpower } */ +/* band: 'B/G', region: USA FCC/Canada IC */ +static struct chan_freq_power channel_freq_power_US_BG[] = { +	{1, 2412, LBS_TX_PWR_US_DEFAULT}, +	{2, 2417, LBS_TX_PWR_US_DEFAULT}, +	{3, 2422, LBS_TX_PWR_US_DEFAULT}, +	{4, 2427, LBS_TX_PWR_US_DEFAULT}, +	{5, 2432, LBS_TX_PWR_US_DEFAULT}, +	{6, 2437, LBS_TX_PWR_US_DEFAULT}, +	{7, 2442, LBS_TX_PWR_US_DEFAULT}, +	{8, 2447, LBS_TX_PWR_US_DEFAULT}, +	{9, 2452, LBS_TX_PWR_US_DEFAULT}, +	{10, 2457, LBS_TX_PWR_US_DEFAULT}, +	{11, 2462, LBS_TX_PWR_US_DEFAULT} +}; + +/* band: 'B/G', region: Europe ETSI */ +static struct chan_freq_power channel_freq_power_EU_BG[] = { +	{1, 2412, LBS_TX_PWR_EMEA_DEFAULT}, +	{2, 2417, LBS_TX_PWR_EMEA_DEFAULT}, +	{3, 2422, LBS_TX_PWR_EMEA_DEFAULT}, +	{4, 2427, LBS_TX_PWR_EMEA_DEFAULT}, +	{5, 2432, LBS_TX_PWR_EMEA_DEFAULT}, +	{6, 2437, LBS_TX_PWR_EMEA_DEFAULT}, +	{7, 2442, LBS_TX_PWR_EMEA_DEFAULT}, +	{8, 2447, LBS_TX_PWR_EMEA_DEFAULT}, +	{9, 2452, LBS_TX_PWR_EMEA_DEFAULT}, +	{10, 2457, LBS_TX_PWR_EMEA_DEFAULT}, +	{11, 2462, LBS_TX_PWR_EMEA_DEFAULT}, +	{12, 2467, LBS_TX_PWR_EMEA_DEFAULT}, +	{13, 2472, LBS_TX_PWR_EMEA_DEFAULT} +}; + +/* band: 'B/G', region: Spain */ +static struct chan_freq_power channel_freq_power_SPN_BG[] = { +	{10, 2457, LBS_TX_PWR_DEFAULT}, +	{11, 2462, LBS_TX_PWR_DEFAULT} +}; + +/* band: 'B/G', region: France */ +static struct chan_freq_power channel_freq_power_FR_BG[] = { +	{10, 2457, LBS_TX_PWR_FR_DEFAULT}, +	{11, 2462, LBS_TX_PWR_FR_DEFAULT}, +	{12, 2467, LBS_TX_PWR_FR_DEFAULT}, +	{13, 2472, LBS_TX_PWR_FR_DEFAULT} +}; + +/* band: 'B/G', region: Japan */ +static struct chan_freq_power channel_freq_power_JPN_BG[] = { +	{1, 2412, LBS_TX_PWR_JP_DEFAULT}, +	{2, 2417, LBS_TX_PWR_JP_DEFAULT}, +	{3, 2422, LBS_TX_PWR_JP_DEFAULT}, +	{4, 2427, LBS_TX_PWR_JP_DEFAULT}, +	{5, 2432, LBS_TX_PWR_JP_DEFAULT}, +	{6, 2437, LBS_TX_PWR_JP_DEFAULT}, +	{7, 2442, LBS_TX_PWR_JP_DEFAULT}, +	{8, 2447, LBS_TX_PWR_JP_DEFAULT}, +	{9, 2452, LBS_TX_PWR_JP_DEFAULT}, +	{10, 2457, LBS_TX_PWR_JP_DEFAULT}, +	{11, 2462, LBS_TX_PWR_JP_DEFAULT}, +	{12, 2467, LBS_TX_PWR_JP_DEFAULT}, +	{13, 2472, LBS_TX_PWR_JP_DEFAULT}, +	{14, 2484, LBS_TX_PWR_JP_DEFAULT} +}; + +/** + * the structure for channel, frequency and power + */ +struct region_cfp_table { +	u8 region; +	struct chan_freq_power *cfp_BG; +	int cfp_no_BG; +}; + +/** + * the structure for the mapping between region and CFP + */ +static struct region_cfp_table region_cfp_table[] = { +	{0x10,			/*US FCC */ +	 channel_freq_power_US_BG, +	 ARRAY_SIZE(channel_freq_power_US_BG), +	 } +	, +	{0x20,			/*CANADA IC */ +	 channel_freq_power_US_BG, +	 ARRAY_SIZE(channel_freq_power_US_BG), +	 } +	, +	{0x30, /*EU*/ channel_freq_power_EU_BG, +	 ARRAY_SIZE(channel_freq_power_EU_BG), +	 } +	, +	{0x31, /*SPAIN*/ channel_freq_power_SPN_BG, +	 ARRAY_SIZE(channel_freq_power_SPN_BG), +	 } +	, +	{0x32, /*FRANCE*/ channel_freq_power_FR_BG, +	 ARRAY_SIZE(channel_freq_power_FR_BG), +	 } +	, +	{0x40, /*JAPAN*/ channel_freq_power_JPN_BG, +	 ARRAY_SIZE(channel_freq_power_JPN_BG), +	 } +	, +/*Add new region here */ +}; + +/** + *  @brief This function finds the CFP in + *  region_cfp_table based on region and band parameter. + * + *  @param region  The region code + *  @param band	   The band + *  @param cfp_no  A pointer to CFP number + *  @return 	   A pointer to CFP + */ +static struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no) +{ +	int i, end; + +	lbs_deb_enter(LBS_DEB_MAIN); + +	end = ARRAY_SIZE(region_cfp_table); + +	for (i = 0; i < end ; i++) { +		lbs_deb_main("region_cfp_table[i].region=%d\n", +			region_cfp_table[i].region); +		if (region_cfp_table[i].region == region) { +			*cfp_no = region_cfp_table[i].cfp_no_BG; +			lbs_deb_leave(LBS_DEB_MAIN); +			return region_cfp_table[i].cfp_BG; +		} +	} + +	lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL"); +	return NULL; +} + +int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band) +{ +	int ret = 0; +	int i = 0; + +	struct chan_freq_power *cfp; +	int cfp_no; + +	lbs_deb_enter(LBS_DEB_MAIN); + +	memset(priv->region_channel, 0, sizeof(priv->region_channel)); + +	cfp = lbs_get_region_cfp_table(region, &cfp_no); +	if (cfp != NULL) { +		priv->region_channel[i].nrcfp = cfp_no; +		priv->region_channel[i].CFP = cfp; +	} else { +		lbs_deb_main("wrong region code %#x in band B/G\n", +		       region); +		ret = -1; +		goto out; +	} +	priv->region_channel[i].valid = 1; +	priv->region_channel[i].region = region; +	priv->region_channel[i].band = band; +	i++; +out: +	lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); +	return ret; +} + + +  /*********************************************************************/  /*                                                                   */ @@ -161,31 +345,15 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv,  	scantype = CMD_SCAN_TYPE_ACTIVE;  	for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) { -		if (priv->enable11d && (priv->connect_status != LBS_CONNECTED) -		    && (priv->mesh_connect_status != LBS_CONNECTED)) { -			/* Scan all the supported chan for the first scan */ -			if (!priv->universal_channel[rgnidx].valid) -				continue; -			scanregion = &priv->universal_channel[rgnidx]; - -			/* clear the parsed_region_chan for the first scan */ -			memset(&priv->parsed_region_chan, 0x00, -			       sizeof(priv->parsed_region_chan)); -		} else { -			if (!priv->region_channel[rgnidx].valid) -				continue; -			scanregion = &priv->region_channel[rgnidx]; -		} +		if (!priv->region_channel[rgnidx].valid) +			continue; +		scanregion = &priv->region_channel[rgnidx];  		for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) {  			struct chanscanparamset *chan = &scanchanlist[chanidx];  			cfp = scanregion->CFP + nextchan; -			if (priv->enable11d) -				scantype = lbs_get_scan_type_11d(cfp->channel, -								 &priv->parsed_region_chan); -  			if (scanregion->band == BAND_B || scanregion->band == BAND_G)  				chan->radiotype = CMD_SCAN_RADIO_TYPE_BG; @@ -519,7 +687,6 @@ static int lbs_process_bss(struct bss_descriptor *bss,  	struct ieee_ie_cf_param_set *cf;  	struct ieee_ie_ibss_param_set *ibss;  	DECLARE_SSID_BUF(ssid); -	struct ieee_ie_country_info_set *pcountryinfo;  	uint8_t *pos, *end, *p;  	uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;  	uint16_t beaconsize = 0; @@ -642,26 +809,6 @@ static int lbs_process_bss(struct bss_descriptor *bss,  			lbs_deb_scan("got IBSS IE\n");  			break; -		case WLAN_EID_COUNTRY: -			pcountryinfo = (struct ieee_ie_country_info_set *) pos; -			lbs_deb_scan("got COUNTRY IE\n"); -			if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode) -			    || pcountryinfo->header.len > 254) { -				lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n", -					     __func__, -					     pcountryinfo->header.len, -					     sizeof(pcountryinfo->countrycode)); -				ret = -1; -				goto done; -			} - -			memcpy(&bss->countryinfo, pcountryinfo, -				pcountryinfo->header.len + 2); -			lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo", -				    (uint8_t *) pcountryinfo, -				    (int) (pcountryinfo->header.len + 2)); -			break; -  		case WLAN_EID_EXT_SUPP_RATES:  			/* only process extended supported rate if data rate is  			 * already found. Data rate IE should come before @@ -812,7 +959,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,  	/* SSID */  	iwe.cmd = SIOCGIWESSID;  	iwe.u.data.flags = 1; -	iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE); +	iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IEEE80211_MAX_SSID_LEN);  	start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);  	/* Mode */ @@ -1022,9 +1169,12 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,  		return -EAGAIN;  	/* Update RSSI if current BSS is a locally created ad-hoc BSS */ -	if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) -		lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, -					     CMD_OPTION_WAITFORRSP, 0, NULL); +	if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) { +		err = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, +				CMD_OPTION_WAITFORRSP, 0, NULL); +		if (err) +			goto out; +	}  	mutex_lock(&priv->lock);  	list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { @@ -1058,7 +1208,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,  	dwrq->length = (ev - extra);  	dwrq->flags = 0; - +out:  	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);  	return err;  } @@ -1141,11 +1291,11 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,  	/* The size of the TLV buffer is equal to the entire command response  	 *   size (scanrespsize) minus the fixed fields (sizeof()'s), the  	 *   BSS Descriptions (bssdescriptsize as bytesLef) and the command -	 *   response header (S_DS_GEN) +	 *   response header (sizeof(struct cmd_header))  	 */  	tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize)  				     + sizeof(scanresp->nr_sets) -				     + S_DS_GEN); +				     + sizeof(struct cmd_header));  	/*  	 *  Process each scan response returned (scanresp->nr_sets). Save  |