2008-01-25 01:38:38 +07:00
|
|
|
/*
|
|
|
|
* Wireless utility functions
|
|
|
|
*
|
2009-04-20 19:31:42 +07:00
|
|
|
* Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
|
2008-01-25 01:38:38 +07:00
|
|
|
*/
|
2009-04-20 19:31:42 +07:00
|
|
|
#include <linux/bitops.h>
|
|
|
|
#include <net/cfg80211.h>
|
2008-01-25 01:38:38 +07:00
|
|
|
#include "core.h"
|
|
|
|
|
2008-10-30 02:00:45 +07:00
|
|
|
struct ieee80211_rate *
|
|
|
|
ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
|
2009-01-21 21:13:48 +07:00
|
|
|
u32 basic_rates, int bitrate)
|
2008-10-30 02:00:45 +07:00
|
|
|
{
|
|
|
|
struct ieee80211_rate *result = &sband->bitrates[0];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < sband->n_bitrates; i++) {
|
|
|
|
if (!(basic_rates & BIT(i)))
|
|
|
|
continue;
|
|
|
|
if (sband->bitrates[i].bitrate > bitrate)
|
|
|
|
continue;
|
|
|
|
result = &sband->bitrates[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(ieee80211_get_response_rate);
|
|
|
|
|
2008-01-25 01:38:38 +07:00
|
|
|
int ieee80211_channel_to_frequency(int chan)
|
|
|
|
{
|
|
|
|
if (chan < 14)
|
|
|
|
return 2407 + chan * 5;
|
|
|
|
|
|
|
|
if (chan == 14)
|
|
|
|
return 2484;
|
|
|
|
|
|
|
|
/* FIXME: 802.11j 17.3.8.3.2 */
|
|
|
|
return (chan + 1000) * 5;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(ieee80211_channel_to_frequency);
|
|
|
|
|
|
|
|
int ieee80211_frequency_to_channel(int freq)
|
|
|
|
{
|
|
|
|
if (freq == 2484)
|
|
|
|
return 14;
|
|
|
|
|
|
|
|
if (freq < 2484)
|
|
|
|
return (freq - 2407) / 5;
|
|
|
|
|
|
|
|
/* FIXME: 802.11j 17.3.8.3.2 */
|
|
|
|
return freq/5 - 1000;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(ieee80211_frequency_to_channel);
|
|
|
|
|
2008-03-26 20:14:55 +07:00
|
|
|
struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
|
|
|
|
int freq)
|
2008-03-17 00:34:33 +07:00
|
|
|
{
|
|
|
|
enum ieee80211_band band;
|
|
|
|
struct ieee80211_supported_band *sband;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
|
|
|
sband = wiphy->bands[band];
|
|
|
|
|
|
|
|
if (!sband)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (i = 0; i < sband->n_channels; i++) {
|
|
|
|
if (sband->channels[i].center_freq == freq)
|
|
|
|
return &sband->channels[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-03-26 20:14:55 +07:00
|
|
|
EXPORT_SYMBOL(__ieee80211_get_channel);
|
2008-03-17 00:34:33 +07:00
|
|
|
|
2008-01-25 01:38:38 +07:00
|
|
|
static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
|
|
|
|
enum ieee80211_band band)
|
|
|
|
{
|
|
|
|
int i, want;
|
|
|
|
|
|
|
|
switch (band) {
|
|
|
|
case IEEE80211_BAND_5GHZ:
|
|
|
|
want = 3;
|
|
|
|
for (i = 0; i < sband->n_bitrates; i++) {
|
|
|
|
if (sband->bitrates[i].bitrate == 60 ||
|
|
|
|
sband->bitrates[i].bitrate == 120 ||
|
|
|
|
sband->bitrates[i].bitrate == 240) {
|
|
|
|
sband->bitrates[i].flags |=
|
|
|
|
IEEE80211_RATE_MANDATORY_A;
|
|
|
|
want--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
WARN_ON(want);
|
|
|
|
break;
|
|
|
|
case IEEE80211_BAND_2GHZ:
|
|
|
|
want = 7;
|
|
|
|
for (i = 0; i < sband->n_bitrates; i++) {
|
|
|
|
if (sband->bitrates[i].bitrate == 10) {
|
|
|
|
sband->bitrates[i].flags |=
|
|
|
|
IEEE80211_RATE_MANDATORY_B |
|
|
|
|
IEEE80211_RATE_MANDATORY_G;
|
|
|
|
want--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sband->bitrates[i].bitrate == 20 ||
|
|
|
|
sband->bitrates[i].bitrate == 55 ||
|
|
|
|
sband->bitrates[i].bitrate == 110 ||
|
|
|
|
sband->bitrates[i].bitrate == 60 ||
|
|
|
|
sband->bitrates[i].bitrate == 120 ||
|
|
|
|
sband->bitrates[i].bitrate == 240) {
|
|
|
|
sband->bitrates[i].flags |=
|
|
|
|
IEEE80211_RATE_MANDATORY_G;
|
|
|
|
want--;
|
|
|
|
}
|
|
|
|
|
2008-01-30 23:36:10 +07:00
|
|
|
if (sband->bitrates[i].bitrate != 10 &&
|
|
|
|
sband->bitrates[i].bitrate != 20 &&
|
|
|
|
sband->bitrates[i].bitrate != 55 &&
|
|
|
|
sband->bitrates[i].bitrate != 110)
|
2008-01-25 01:38:38 +07:00
|
|
|
sband->bitrates[i].flags |=
|
|
|
|
IEEE80211_RATE_ERP_G;
|
|
|
|
}
|
2008-02-03 05:53:10 +07:00
|
|
|
WARN_ON(want != 0 && want != 3 && want != 6);
|
2008-01-25 01:38:38 +07:00
|
|
|
break;
|
|
|
|
case IEEE80211_NUM_BANDS:
|
|
|
|
WARN_ON(1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
|
|
|
|
{
|
|
|
|
enum ieee80211_band band;
|
|
|
|
|
|
|
|
for (band = 0; band < IEEE80211_NUM_BANDS; band++)
|
|
|
|
if (wiphy->bands[band])
|
|
|
|
set_mandatory_flags_band(wiphy->bands[band], band);
|
|
|
|
}
|
2009-05-11 18:54:58 +07:00
|
|
|
|
|
|
|
int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
|
|
|
|
const u8 *mac_addr)
|
|
|
|
{
|
|
|
|
if (key_idx > 5)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Disallow pairwise keys with non-zero index unless it's WEP
|
|
|
|
* (because current deployments use pairwise WEP keys with
|
|
|
|
* non-zero indizes but 802.11i clearly specifies to use zero)
|
|
|
|
*/
|
|
|
|
if (mac_addr && key_idx &&
|
|
|
|
params->cipher != WLAN_CIPHER_SUITE_WEP40 &&
|
|
|
|
params->cipher != WLAN_CIPHER_SUITE_WEP104)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* TODO: add definitions for the lengths to linux/ieee80211.h */
|
|
|
|
switch (params->cipher) {
|
|
|
|
case WLAN_CIPHER_SUITE_WEP40:
|
|
|
|
if (params->key_len != 5)
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
|
|
|
case WLAN_CIPHER_SUITE_TKIP:
|
|
|
|
if (params->key_len != 32)
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
|
|
|
case WLAN_CIPHER_SUITE_CCMP:
|
|
|
|
if (params->key_len != 16)
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
|
|
|
case WLAN_CIPHER_SUITE_WEP104:
|
|
|
|
if (params->key_len != 13)
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
|
|
|
case WLAN_CIPHER_SUITE_AES_CMAC:
|
|
|
|
if (params->key_len != 16)
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2009-05-15 16:38:32 +07:00
|
|
|
if (params->seq) {
|
|
|
|
switch (params->cipher) {
|
|
|
|
case WLAN_CIPHER_SUITE_WEP40:
|
|
|
|
case WLAN_CIPHER_SUITE_WEP104:
|
|
|
|
/* These ciphers do not use key sequence */
|
|
|
|
return -EINVAL;
|
|
|
|
case WLAN_CIPHER_SUITE_TKIP:
|
|
|
|
case WLAN_CIPHER_SUITE_CCMP:
|
|
|
|
case WLAN_CIPHER_SUITE_AES_CMAC:
|
|
|
|
if (params->seq_len != 6)
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-11 18:54:58 +07:00
|
|
|
return 0;
|
|
|
|
}
|