[PATCH] ieee80211: Add QoS (WME) support to the ieee80211 subsystem
tree a3ad796273e98036eb0e9fc063225070fa24508a parent 1b9c0aeb377abf8e4a43a86cff42382f74ca0259 author Mohamed Abbas <mabbas@linux.intel.com> 1124447069 -0500 committer James Ketrenos <jketreno@linux.intel.com> 1127313435 -0500 Add QoS (WME) support to the ieee80211 subsystem. NOTE: This requires drivers that use the ieee80211 hard_start_xmit (ipw2100 and ipw2200) to add the priority parameter to their callback. Signed-off-by: James Ketrenos <jketreno@linux.intel.com> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
This commit is contained in:
parent
2c0aa2a5c2
commit
9e8571affd
|
@ -92,6 +92,7 @@
|
|||
#define IEEE80211_STYPE_CFACK 0x0050
|
||||
#define IEEE80211_STYPE_CFPOLL 0x0060
|
||||
#define IEEE80211_STYPE_CFACKPOLL 0x0070
|
||||
#define IEEE80211_STYPE_QOS_DATA 0x0080
|
||||
|
||||
#define IEEE80211_SCTL_FRAG 0x000F
|
||||
#define IEEE80211_SCTL_SEQ 0xFFF0
|
||||
|
@ -153,6 +154,7 @@ const char *escape_essid(const char *essid, u8 essid_len);
|
|||
|
||||
#define IEEE80211_DL_TX (1<<8)
|
||||
#define IEEE80211_DL_RX (1<<9)
|
||||
#define IEEE80211_DL_QOS (1<<31)
|
||||
|
||||
#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a)
|
||||
#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a)
|
||||
|
@ -166,6 +168,7 @@ const char *escape_essid(const char *essid, u8 essid_len);
|
|||
#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a)
|
||||
#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a)
|
||||
#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a)
|
||||
#define IEEE80211_DEBUG_QOS(f, a...) IEEE80211_DEBUG(IEEE80211_DL_QOS, f, ## a)
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/if_arp.h> /* ARPHRD_ETHER */
|
||||
|
@ -493,6 +496,7 @@ enum ieee80211_mfie {
|
|||
MFIE_TYPE_RSN = 48,
|
||||
MFIE_TYPE_RATES_EX = 50,
|
||||
MFIE_TYPE_GENERIC = 221,
|
||||
MFIE_TYPE_QOS_PARAMETER = 222,
|
||||
};
|
||||
|
||||
/* Minimal header; can be used for passing 802.11 frames with sufficient
|
||||
|
@ -540,6 +544,29 @@ struct ieee80211_hdr_4addr {
|
|||
u8 payload[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieee80211_hdr_3addrqos {
|
||||
u16 frame_ctl;
|
||||
u16 duration_id;
|
||||
u8 addr1[ETH_ALEN];
|
||||
u8 addr2[ETH_ALEN];
|
||||
u8 addr3[ETH_ALEN];
|
||||
u16 seq_ctl;
|
||||
u8 payload[0];
|
||||
u16 qos_ctl;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieee80211_hdr_4addrqos {
|
||||
u16 frame_ctl;
|
||||
u16 duration_id;
|
||||
u8 addr1[ETH_ALEN];
|
||||
u8 addr2[ETH_ALEN];
|
||||
u8 addr3[ETH_ALEN];
|
||||
u16 seq_ctl;
|
||||
u8 addr4[ETH_ALEN];
|
||||
u8 payload[0];
|
||||
u16 qos_ctl;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieee80211_info_element {
|
||||
u8 id;
|
||||
u8 len;
|
||||
|
@ -645,6 +672,65 @@ struct ieee80211_txb {
|
|||
#define NETWORK_HAS_OFDM (1<<1)
|
||||
#define NETWORK_HAS_CCK (1<<2)
|
||||
|
||||
/* QoS structure */
|
||||
#define NETWORK_HAS_QOS_PARAMETERS (1<<3)
|
||||
#define NETWORK_HAS_QOS_INFORMATION (1<<4)
|
||||
#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | NETWORK_HAS_QOS_INFORMATION)
|
||||
|
||||
#define QOS_QUEUE_NUM 4
|
||||
#define QOS_OUI_LEN 3
|
||||
#define QOS_OUI_TYPE 2
|
||||
#define QOS_ELEMENT_ID 221
|
||||
#define QOS_OUI_INFO_SUB_TYPE 0
|
||||
#define QOS_OUI_PARAM_SUB_TYPE 1
|
||||
#define QOS_VERSION_1 1
|
||||
#define QOS_AIFSN_MIN_VALUE 2
|
||||
|
||||
struct ieee80211_qos_information_element {
|
||||
u8 elementID;
|
||||
u8 length;
|
||||
u8 qui[QOS_OUI_LEN];
|
||||
u8 qui_type;
|
||||
u8 qui_subtype;
|
||||
u8 version;
|
||||
u8 ac_info;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieee80211_qos_ac_parameter {
|
||||
u8 aci_aifsn;
|
||||
u8 ecw_min_max;
|
||||
u16 tx_op_limit;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieee80211_qos_parameter_info {
|
||||
struct ieee80211_qos_information_element info_element;
|
||||
u8 reserved;
|
||||
struct ieee80211_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieee80211_qos_parameters {
|
||||
u16 cw_min[QOS_QUEUE_NUM];
|
||||
u16 cw_max[QOS_QUEUE_NUM];
|
||||
u8 aifs[QOS_QUEUE_NUM];
|
||||
u8 flag[QOS_QUEUE_NUM];
|
||||
u16 tx_op_limit[QOS_QUEUE_NUM];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ieee80211_qos_data {
|
||||
struct ieee80211_qos_parameters parameters;
|
||||
int active;
|
||||
int supported;
|
||||
u8 param_count;
|
||||
u8 old_param_count;
|
||||
};
|
||||
|
||||
struct ieee80211_tim_parameters {
|
||||
u8 tim_count;
|
||||
u8 tim_period;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*******************************************************/
|
||||
|
||||
struct ieee80211_network {
|
||||
/* These entries are used to identify a unique network */
|
||||
u8 bssid[ETH_ALEN];
|
||||
|
@ -653,6 +739,8 @@ struct ieee80211_network {
|
|||
u8 ssid[IW_ESSID_MAX_SIZE + 1];
|
||||
u8 ssid_len;
|
||||
|
||||
struct ieee80211_qos_data qos_data;
|
||||
|
||||
/* These are network statistics */
|
||||
struct ieee80211_rx_stats stats;
|
||||
u16 capability;
|
||||
|
@ -672,6 +760,7 @@ struct ieee80211_network {
|
|||
size_t wpa_ie_len;
|
||||
u8 rsn_ie[MAX_WPA_IE_LEN];
|
||||
size_t rsn_ie_len;
|
||||
struct ieee80211_tim_parameters tim;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
|
@ -769,10 +858,13 @@ struct ieee80211_device {
|
|||
void (*set_security) (struct net_device * dev,
|
||||
struct ieee80211_security * sec);
|
||||
int (*hard_start_xmit) (struct ieee80211_txb * txb,
|
||||
struct net_device * dev);
|
||||
struct net_device * dev, int pri);
|
||||
int (*reset_port) (struct net_device * dev);
|
||||
int (*is_queue_full) (struct net_device * dev, int pri);
|
||||
|
||||
int (*handle_management) (struct net_device * dev,
|
||||
struct ieee80211_network * network, u16 type);
|
||||
|
||||
/* Typical STA methods */
|
||||
int (*handle_auth) (struct net_device * dev,
|
||||
struct ieee80211_auth * auth);
|
||||
|
@ -854,11 +946,14 @@ extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee,
|
|||
extern inline int ieee80211_get_hdrlen(u16 fc)
|
||||
{
|
||||
int hdrlen = IEEE80211_3ADDR_LEN;
|
||||
u16 stype = WLAN_FC_GET_STYPE(fc);
|
||||
|
||||
switch (WLAN_FC_GET_TYPE(fc)) {
|
||||
case IEEE80211_FTYPE_DATA:
|
||||
if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
|
||||
hdrlen = IEEE80211_4ADDR_LEN;
|
||||
if (stype & IEEE80211_STYPE_QOS_DATA)
|
||||
hdrlen += 2;
|
||||
break;
|
||||
case IEEE80211_FTYPE_CTL:
|
||||
switch (WLAN_FC_GET_STYPE(fc)) {
|
||||
|
|
|
@ -534,6 +534,9 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
|||
|
||||
/* Nullfunc frames may have PS-bit set, so they must be passed to
|
||||
* hostap_handle_sta_rx() before being dropped here. */
|
||||
|
||||
stype &= ~IEEE80211_STYPE_QOS_DATA;
|
||||
|
||||
if (stype != IEEE80211_STYPE_DATA &&
|
||||
stype != IEEE80211_STYPE_DATA_CFACK &&
|
||||
stype != IEEE80211_STYPE_DATA_CFPOLL &&
|
||||
|
@ -758,6 +761,264 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
|||
|
||||
#define MGMT_FRAME_FIXED_PART_LENGTH 0x24
|
||||
|
||||
static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
|
||||
|
||||
/*
|
||||
* Make ther structure we read from the beacon packet has
|
||||
* the right values
|
||||
*/
|
||||
static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element
|
||||
*info_element, int sub_type)
|
||||
{
|
||||
|
||||
if (info_element->qui_subtype != sub_type)
|
||||
return -1;
|
||||
if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN))
|
||||
return -1;
|
||||
if (info_element->qui_type != QOS_OUI_TYPE)
|
||||
return -1;
|
||||
if (info_element->version != QOS_VERSION_1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a QoS parameter element
|
||||
*/
|
||||
static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info
|
||||
*element_param, struct ieee80211_info_element
|
||||
*info_element)
|
||||
{
|
||||
int ret = 0;
|
||||
u16 size = sizeof(struct ieee80211_qos_parameter_info) - 2;
|
||||
|
||||
if ((info_element == NULL) || (element_param == NULL))
|
||||
return -1;
|
||||
|
||||
if (info_element->id == QOS_ELEMENT_ID && info_element->len == size) {
|
||||
memcpy(element_param->info_element.qui, info_element->data,
|
||||
info_element->len);
|
||||
element_param->info_element.elementID = info_element->id;
|
||||
element_param->info_element.length = info_element->len;
|
||||
} else
|
||||
ret = -1;
|
||||
if (ret == 0)
|
||||
ret = ieee80211_verify_qos_info(&element_param->info_element,
|
||||
QOS_OUI_PARAM_SUB_TYPE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a QoS information element
|
||||
*/
|
||||
static int ieee80211_read_qos_info_element(struct
|
||||
ieee80211_qos_information_element
|
||||
*element_info, struct ieee80211_info_element
|
||||
*info_element)
|
||||
{
|
||||
int ret = 0;
|
||||
u16 size = sizeof(struct ieee80211_qos_information_element) - 2;
|
||||
|
||||
if (element_info == NULL)
|
||||
return -1;
|
||||
if (info_element == NULL)
|
||||
return -1;
|
||||
|
||||
if ((info_element->id == QOS_ELEMENT_ID) && (info_element->len == size)) {
|
||||
memcpy(element_info->qui, info_element->data,
|
||||
info_element->len);
|
||||
element_info->elementID = info_element->id;
|
||||
element_info->length = info_element->len;
|
||||
} else
|
||||
ret = -1;
|
||||
|
||||
if (ret == 0)
|
||||
ret = ieee80211_verify_qos_info(element_info,
|
||||
QOS_OUI_INFO_SUB_TYPE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write QoS parameters from the ac parameters.
|
||||
*/
|
||||
static int ieee80211_qos_convert_ac_to_parameters(struct
|
||||
ieee80211_qos_parameter_info
|
||||
*param_elm, struct
|
||||
ieee80211_qos_parameters
|
||||
*qos_param)
|
||||
{
|
||||
int rc = 0;
|
||||
int i;
|
||||
struct ieee80211_qos_ac_parameter *ac_params;
|
||||
u32 txop;
|
||||
u8 cw_min;
|
||||
u8 cw_max;
|
||||
|
||||
for (i = 0; i < QOS_QUEUE_NUM; i++) {
|
||||
ac_params = &(param_elm->ac_params_record[i]);
|
||||
|
||||
qos_param->aifs[i] = (ac_params->aci_aifsn) & 0x0F;
|
||||
qos_param->aifs[i] -= (qos_param->aifs[i] < 2) ? 0 : 2;
|
||||
|
||||
cw_min = ac_params->ecw_min_max & 0x0F;
|
||||
qos_param->cw_min[i] = (u16) ((1 << cw_min) - 1);
|
||||
|
||||
cw_max = (ac_params->ecw_min_max & 0xF0) >> 4;
|
||||
qos_param->cw_max[i] = (u16) ((1 << cw_max) - 1);
|
||||
|
||||
qos_param->flag[i] =
|
||||
(ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00;
|
||||
|
||||
txop = le16_to_cpu(ac_params->tx_op_limit) * 32;
|
||||
qos_param->tx_op_limit[i] = (u16) txop;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* we have a generic data element which it may contain QoS information or
|
||||
* parameters element. check the information element length to decide
|
||||
* which type to read
|
||||
*/
|
||||
static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element
|
||||
*info_element,
|
||||
struct ieee80211_network *network)
|
||||
{
|
||||
int rc = 0;
|
||||
struct ieee80211_qos_parameters *qos_param = NULL;
|
||||
struct ieee80211_qos_information_element qos_info_element;
|
||||
|
||||
rc = ieee80211_read_qos_info_element(&qos_info_element, info_element);
|
||||
|
||||
if (rc == 0) {
|
||||
network->qos_data.param_count = qos_info_element.ac_info & 0x0F;
|
||||
network->flags |= NETWORK_HAS_QOS_INFORMATION;
|
||||
} else {
|
||||
struct ieee80211_qos_parameter_info param_element;
|
||||
|
||||
rc = ieee80211_read_qos_param_element(¶m_element,
|
||||
info_element);
|
||||
if (rc == 0) {
|
||||
qos_param = &(network->qos_data.parameters);
|
||||
ieee80211_qos_convert_ac_to_parameters(¶m_element,
|
||||
qos_param);
|
||||
network->flags |= NETWORK_HAS_QOS_PARAMETERS;
|
||||
network->qos_data.param_count =
|
||||
param_element.info_element.ac_info & 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
IEEE80211_DEBUG_QOS("QoS is supported\n");
|
||||
network->qos_data.supported = 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response
|
||||
*frame, struct ieee80211_rx_stats *stats)
|
||||
{
|
||||
struct ieee80211_network network_resp;
|
||||
struct ieee80211_network *network = &network_resp;
|
||||
struct ieee80211_info_element *info_element;
|
||||
struct net_device *dev = ieee->dev;
|
||||
u16 left;
|
||||
|
||||
network->flags = 0;
|
||||
network->qos_data.active = 0;
|
||||
network->qos_data.supported = 0;
|
||||
network->qos_data.param_count = 0;
|
||||
network->qos_data.old_param_count = 0;
|
||||
|
||||
//network->atim_window = le16_to_cpu(frame->aid) & (0x3FFF);
|
||||
network->atim_window = le16_to_cpu(frame->aid);
|
||||
network->listen_interval = le16_to_cpu(frame->status);
|
||||
|
||||
info_element = frame->info_element;
|
||||
left = stats->len - sizeof(*frame);
|
||||
|
||||
while (left >= sizeof(struct ieee80211_info_element)) {
|
||||
if (sizeof(struct ieee80211_info_element) +
|
||||
info_element->len > left) {
|
||||
IEEE80211_DEBUG_QOS("ASSOC RESP: parse failed: "
|
||||
"info_element->len + 2 > left : "
|
||||
"info_element->len+2=%zd left=%d, id=%d.\n",
|
||||
info_element->len +
|
||||
sizeof(struct
|
||||
ieee80211_info_element),
|
||||
left, info_element->id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (info_element->id) {
|
||||
case MFIE_TYPE_SSID:
|
||||
if (ieee80211_is_empty_essid(info_element->data,
|
||||
info_element->len)) {
|
||||
network->flags |= NETWORK_EMPTY_ESSID;
|
||||
break;
|
||||
}
|
||||
|
||||
network->ssid_len = min(info_element->len,
|
||||
(u8) IW_ESSID_MAX_SIZE);
|
||||
memcpy(network->ssid, info_element->data,
|
||||
network->ssid_len);
|
||||
if (network->ssid_len < IW_ESSID_MAX_SIZE)
|
||||
memset(network->ssid + network->ssid_len, 0,
|
||||
IW_ESSID_MAX_SIZE - network->ssid_len);
|
||||
|
||||
IEEE80211_DEBUG_QOS("MFIE_TYPE_SSID: '%s' len=%d.\n",
|
||||
network->ssid, network->ssid_len);
|
||||
break;
|
||||
|
||||
case MFIE_TYPE_TIM:
|
||||
IEEE80211_DEBUG_QOS("MFIE_TYPE_TIM: ignored\n");
|
||||
break;
|
||||
|
||||
case MFIE_TYPE_IBSS_SET:
|
||||
IEEE80211_DEBUG_QOS("MFIE_TYPE_IBSS_SET: ignored\n");
|
||||
break;
|
||||
|
||||
case MFIE_TYPE_CHALLENGE:
|
||||
IEEE80211_DEBUG_QOS("MFIE_TYPE_CHALLENGE: ignored\n");
|
||||
break;
|
||||
|
||||
case MFIE_TYPE_GENERIC:
|
||||
IEEE80211_DEBUG_QOS("MFIE_TYPE_GENERIC: %d bytes\n",
|
||||
info_element->len);
|
||||
ieee80211_parse_qos_info_param_IE(info_element,
|
||||
network);
|
||||
break;
|
||||
|
||||
case MFIE_TYPE_RSN:
|
||||
IEEE80211_DEBUG_QOS("MFIE_TYPE_RSN: %d bytes\n",
|
||||
info_element->len);
|
||||
break;
|
||||
|
||||
case MFIE_TYPE_QOS_PARAMETER:
|
||||
printk("QoS Error need to parse QOS_PARAMETER IE\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
IEEE80211_DEBUG_QOS("unsupported IE %d\n",
|
||||
info_element->id);
|
||||
break;
|
||||
}
|
||||
|
||||
left -= sizeof(struct ieee80211_info_element) +
|
||||
info_element->len;
|
||||
info_element = (struct ieee80211_info_element *)
|
||||
&info_element->data[info_element->len];
|
||||
}
|
||||
|
||||
if (ieee->handle_assoc_response != NULL)
|
||||
ieee->handle_assoc_response(dev, frame, network);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
|
||||
static inline int ieee80211_is_ofdm_rate(u8 rate)
|
||||
{
|
||||
switch (rate & ~IEEE80211_BASIC_RATE_MASK) {
|
||||
|
@ -786,6 +1047,9 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i
|
|||
struct ieee80211_info_element *info_element;
|
||||
u16 left;
|
||||
u8 i;
|
||||
network->qos_data.active = 0;
|
||||
network->qos_data.supported = 0;
|
||||
network->qos_data.param_count = 0;
|
||||
|
||||
/* Pull out fixed field data */
|
||||
memcpy(network->bssid, beacon->header.addr3, ETH_ALEN);
|
||||
|
@ -813,13 +1077,11 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i
|
|||
|
||||
info_element = beacon->info_element;
|
||||
left = stats->len - sizeof(*beacon);
|
||||
while (left >= sizeof(struct ieee80211_info_element)) {
|
||||
if (sizeof(struct ieee80211_info_element) + info_element->len >
|
||||
left) {
|
||||
while (left >= sizeof(*info_element)) {
|
||||
if (sizeof(*info_element) + info_element->len > left) {
|
||||
IEEE80211_DEBUG_SCAN
|
||||
("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%Zd left=%d.\n",
|
||||
info_element->len +
|
||||
sizeof(struct ieee80211_info_element), left);
|
||||
info_element->len + sizeof(*info_element), left);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -847,15 +1109,14 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i
|
|||
#ifdef CONFIG_IEEE80211_DEBUG
|
||||
p = rates_str;
|
||||
#endif
|
||||
network->rates_len =
|
||||
min(info_element->len, MAX_RATES_LENGTH);
|
||||
network->rates_len = min(info_element->len,
|
||||
MAX_RATES_LENGTH);
|
||||
for (i = 0; i < network->rates_len; i++) {
|
||||
network->rates[i] = info_element->data[i];
|
||||
#ifdef CONFIG_IEEE80211_DEBUG
|
||||
p += snprintf(p,
|
||||
sizeof(rates_str) - (p -
|
||||
rates_str),
|
||||
"%02X ", network->rates[i]);
|
||||
p += snprintf(p, sizeof(rates_str) -
|
||||
(p - rates_str), "%02X ",
|
||||
network->rates[i]);
|
||||
#endif
|
||||
if (ieee80211_is_ofdm_rate
|
||||
(info_element->data[i])) {
|
||||
|
@ -875,15 +1136,14 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i
|
|||
#ifdef CONFIG_IEEE80211_DEBUG
|
||||
p = rates_str;
|
||||
#endif
|
||||
network->rates_ex_len =
|
||||
min(info_element->len, MAX_RATES_EX_LENGTH);
|
||||
network->rates_ex_len = min(info_element->len,
|
||||
MAX_RATES_EX_LENGTH);
|
||||
for (i = 0; i < network->rates_ex_len; i++) {
|
||||
network->rates_ex[i] = info_element->data[i];
|
||||
#ifdef CONFIG_IEEE80211_DEBUG
|
||||
p += snprintf(p,
|
||||
sizeof(rates_str) - (p -
|
||||
rates_str),
|
||||
"%02X ", network->rates[i]);
|
||||
p += snprintf(p, sizeof(rates_str) -
|
||||
(p - rates_str), "%02X ",
|
||||
network->rates[i]);
|
||||
#endif
|
||||
if (ieee80211_is_ofdm_rate
|
||||
(info_element->data[i])) {
|
||||
|
@ -929,6 +1189,10 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i
|
|||
case MFIE_TYPE_GENERIC:
|
||||
IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n",
|
||||
info_element->len);
|
||||
if (!ieee80211_parse_qos_info_param_IE(info_element,
|
||||
network))
|
||||
break;
|
||||
|
||||
if (info_element->len >= 4 &&
|
||||
info_element->data[0] == 0x00 &&
|
||||
info_element->data[1] == 0x50 &&
|
||||
|
@ -950,14 +1214,18 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i
|
|||
network->rsn_ie_len);
|
||||
break;
|
||||
|
||||
case MFIE_TYPE_QOS_PARAMETER:
|
||||
printk(KERN_ERR
|
||||
"QoS Error need to parse QOS_PARAMETER IE\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
IEEE80211_DEBUG_SCAN("unsupported IE %d\n",
|
||||
info_element->id);
|
||||
break;
|
||||
}
|
||||
|
||||
left -= sizeof(struct ieee80211_info_element) +
|
||||
info_element->len;
|
||||
left -= sizeof(*info_element) + info_element->len;
|
||||
info_element = (struct ieee80211_info_element *)
|
||||
&info_element->data[info_element->len];
|
||||
}
|
||||
|
@ -1004,6 +1272,9 @@ static inline int is_same_network(struct ieee80211_network *src,
|
|||
static inline void update_network(struct ieee80211_network *dst,
|
||||
struct ieee80211_network *src)
|
||||
{
|
||||
int qos_active;
|
||||
u8 old_param;
|
||||
|
||||
memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats));
|
||||
dst->capability = src->capability;
|
||||
memcpy(dst->rates, src->rates, src->rates_len);
|
||||
|
@ -1026,6 +1297,28 @@ static inline void update_network(struct ieee80211_network *dst,
|
|||
dst->rsn_ie_len = src->rsn_ie_len;
|
||||
|
||||
dst->last_scanned = jiffies;
|
||||
qos_active = src->qos_data.active;
|
||||
old_param = dst->qos_data.old_param_count;
|
||||
if (dst->flags & NETWORK_HAS_QOS_MASK)
|
||||
memcpy(&dst->qos_data, &src->qos_data,
|
||||
sizeof(struct ieee80211_qos_data));
|
||||
else {
|
||||
dst->qos_data.supported = src->qos_data.supported;
|
||||
dst->qos_data.param_count = src->qos_data.param_count;
|
||||
}
|
||||
|
||||
if (dst->qos_data.supported == 1) {
|
||||
if (dst->ssid_len)
|
||||
IEEE80211_DEBUG_QOS
|
||||
("QoS the network %s is QoS supported\n",
|
||||
dst->ssid);
|
||||
else
|
||||
IEEE80211_DEBUG_QOS
|
||||
("QoS the network is QoS supported\n");
|
||||
}
|
||||
dst->qos_data.active = qos_active;
|
||||
dst->qos_data.old_param_count = old_param;
|
||||
|
||||
/* dst->last_associate is not overwritten */
|
||||
}
|
||||
|
||||
|
@ -1167,6 +1460,9 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
|
|||
IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n",
|
||||
WLAN_FC_GET_STYPE(le16_to_cpu
|
||||
(header->frame_ctl)));
|
||||
ieee80211_handle_assoc_resp(ieee,
|
||||
(struct ieee80211_assoc_response *)
|
||||
header, stats);
|
||||
break;
|
||||
|
||||
case IEEE80211_STYPE_REASSOC_RESP:
|
||||
|
|
|
@ -465,7 +465,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
dev_kfree_skb_any(skb);
|
||||
|
||||
if (txb) {
|
||||
int ret = (*ieee->hard_start_xmit) (txb, dev);
|
||||
int ret = (*ieee->hard_start_xmit) (txb, dev, priority);
|
||||
if (ret == 0) {
|
||||
stats->tx_packets++;
|
||||
stats->tx_bytes += txb->payload_size;
|
||||
|
@ -500,6 +500,7 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee,
|
|||
unsigned long flags;
|
||||
struct net_device_stats *stats = &ieee->stats;
|
||||
struct sk_buff *skb_frag;
|
||||
int priority = -1;
|
||||
|
||||
spin_lock_irqsave(&ieee->lock, flags);
|
||||
|
||||
|
@ -540,7 +541,7 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee,
|
|||
spin_unlock_irqrestore(&ieee->lock, flags);
|
||||
|
||||
if (txb) {
|
||||
if ((*ieee->hard_start_xmit) (txb, ieee->dev) == 0) {
|
||||
if ((*ieee->hard_start_xmit) (txb, ieee->dev, priority) == 0) {
|
||||
stats->tx_packets++;
|
||||
stats->tx_bytes += txb->payload_size;
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue