extractedLnx/linux-2.6.38/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c_ieee80211_parse_info_param.c
int ieee80211_parse_info_param(struct ieee80211_device *ieee,
struct ieee80211_info_element *info_element,
u16 length,
struct ieee80211_network *network,
struct ieee80211_rx_stats *stats)
{
u8 i;
short offset;
u16 tmp_htcap_len=0;
u16 tmp_htinfo_len=0;
u16 ht_realtek_agg_len=0;
u8 ht_realtek_agg_buf[MAX_IE_LEN];
// u16 broadcom_len = 0;
#ifdef CONFIG_IEEE80211_DEBUG
char rates_str[64];
char *p;
#endif
while (length >= sizeof(*info_element)) {
if (sizeof(*info_element) + info_element->len > length) {
IEEE80211_DEBUG_MGMT("Info elem: parse failed: "
"info_element->len + 2 > left : "
"info_element->len+2=%zd left=%d, id=%d.\n",
info_element->len +
sizeof(*info_element),
length, info_element->id);
/* We stop processing but don't return an error here
* because some misbehaviour APs break this rule. ie.
* Orinoco AP1000. */
break;
}
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_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n",
network->ssid, network->ssid_len);
break;
case MFIE_TYPE_RATES:
#ifdef CONFIG_IEEE80211_DEBUG
p = rates_str;
#endif
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]);
#endif
if (ieee80211_is_ofdm_rate
(info_element->data[i])) {
network->flags |= NETWORK_HAS_OFDM;
if (info_element->data[i] &
IEEE80211_BASIC_RATE_MASK)
network->flags &=
~NETWORK_HAS_CCK;
}
}
IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES: '%s' (%d)\n",
rates_str, network->rates_len);
break;
case MFIE_TYPE_RATES_EX:
#ifdef CONFIG_IEEE80211_DEBUG
p = rates_str;
#endif
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]);
#endif
if (ieee80211_is_ofdm_rate
(info_element->data[i])) {
network->flags |= NETWORK_HAS_OFDM;
if (info_element->data[i] &
IEEE80211_BASIC_RATE_MASK)
network->flags &=
~NETWORK_HAS_CCK;
}
}
IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES_EX: '%s' (%d)\n",
rates_str, network->rates_ex_len);
break;
case MFIE_TYPE_DS_SET:
IEEE80211_DEBUG_MGMT("MFIE_TYPE_DS_SET: %d\n",
info_element->data[0]);
network->channel = info_element->data[0];
break;
case MFIE_TYPE_FH_SET:
IEEE80211_DEBUG_MGMT("MFIE_TYPE_FH_SET: ignored\n");
break;
case MFIE_TYPE_CF_SET:
IEEE80211_DEBUG_MGMT("MFIE_TYPE_CF_SET: ignored\n");
break;
case MFIE_TYPE_TIM:
if(info_element->len < 4)
break;
network->tim.tim_count = info_element->data[0];
network->tim.tim_period = info_element->data[1];
network->dtim_period = info_element->data[1];
if(ieee->state != IEEE80211_LINKED)
break;
network->last_dtim_sta_time[0] = stats->mac_time[0];
network->last_dtim_sta_time[1] = stats->mac_time[1];
network->dtim_data = IEEE80211_DTIM_VALID;
if(info_element->data[0] != 0)
break;
if(info_element->data[2] & 1)
network->dtim_data |= IEEE80211_DTIM_MBCAST;
offset = (info_element->data[2] >> 1)*2;
//printk("offset1:%x aid:%x\n",offset, ieee->assoc_id);
if(ieee->assoc_id < 8*offset ||
ieee->assoc_id > 8*(offset + info_element->len -3))
break;
offset = (ieee->assoc_id / 8) - offset;// + ((aid % 8)? 0 : 1) ;
if(info_element->data[3+offset] & (1<<(ieee->assoc_id%8)))
network->dtim_data |= IEEE80211_DTIM_UCAST;
//IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: partially ignored\n");
break;
case MFIE_TYPE_ERP:
network->erp_value = info_element->data[0];
network->flags |= NETWORK_HAS_ERP_VALUE;
IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
network->erp_value);
break;
case MFIE_TYPE_IBSS_SET:
network->atim_window = info_element->data[0];
IEEE80211_DEBUG_MGMT("MFIE_TYPE_IBSS_SET: %d\n",
network->atim_window);
break;
case MFIE_TYPE_CHALLENGE:
IEEE80211_DEBUG_MGMT("MFIE_TYPE_CHALLENGE: ignored\n");
break;
case MFIE_TYPE_GENERIC:
IEEE80211_DEBUG_MGMT("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 &&
info_element->data[2] == 0xf2 &&
info_element->data[3] == 0x01) {
network->wpa_ie_len = min(info_element->len + 2,
MAX_WPA_IE_LEN);
memcpy(network->wpa_ie, info_element,
network->wpa_ie_len);
break;
}
#ifdef THOMAS_TURBO
if (info_element->len == 7 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0xe0 &&
info_element->data[2] == 0x4c &&
info_element->data[3] == 0x01 &&
info_element->data[4] == 0x02) {
network->Turbo_Enable = 1;
}
#endif
//for HTcap and HTinfo parameters
if(tmp_htcap_len == 0){
if(info_element->len >= 4 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x90 &&
info_element->data[2] == 0x4c &&
info_element->data[3] == 0x033){
tmp_htcap_len = min(info_element->len,(u8)MAX_IE_LEN);
if(tmp_htcap_len != 0){
network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC;
network->bssht.bdHTCapLen = tmp_htcap_len > sizeof(network->bssht.bdHTCapBuf)?\
sizeof(network->bssht.bdHTCapBuf):tmp_htcap_len;
memcpy(network->bssht.bdHTCapBuf,info_element->data,network->bssht.bdHTCapLen);
}
}
if(tmp_htcap_len != 0)
network->bssht.bdSupportHT = true;
else
network->bssht.bdSupportHT = false;
}
if(tmp_htinfo_len == 0){
if(info_element->len >= 4 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x90 &&
info_element->data[2] == 0x4c &&
info_element->data[3] == 0x034){
tmp_htinfo_len = min(info_element->len,(u8)MAX_IE_LEN);
if(tmp_htinfo_len != 0){
network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC;
if(tmp_htinfo_len){
network->bssht.bdHTInfoLen = tmp_htinfo_len > sizeof(network->bssht.bdHTInfoBuf)?\
sizeof(network->bssht.bdHTInfoBuf):tmp_htinfo_len;
memcpy(network->bssht.bdHTInfoBuf,info_element->data,network->bssht.bdHTInfoLen);
}
}
}
}
if(ieee->aggregation){
if(network->bssht.bdSupportHT){
if(info_element->len >= 4 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0xe0 &&
info_element->data[2] == 0x4c &&
info_element->data[3] == 0x02){
ht_realtek_agg_len = min(info_element->len,(u8)MAX_IE_LEN);
memcpy(ht_realtek_agg_buf,info_element->data,info_element->len);
}
if(ht_realtek_agg_len >= 5){
network->bssht.bdRT2RTAggregation = true;
if((ht_realtek_agg_buf[4] == 1) && (ht_realtek_agg_buf[5] & 0x02))
network->bssht.bdRT2RTLongSlotTime = true;
}
}
}
//if(tmp_htcap_len !=0 || tmp_htinfo_len != 0)
{
if((info_element->len >= 3 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x05 &&
info_element->data[2] == 0xb5) ||
(info_element->len >= 3 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x0a &&
info_element->data[2] == 0xf7) ||
(info_element->len >= 3 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x10 &&
info_element->data[2] == 0x18)){
network->broadcom_cap_exist = true;
}
}
if(info_element->len >= 3 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x0c &&
info_element->data[2] == 0x43)
{
network->ralink_cap_exist = true;
}
else
network->ralink_cap_exist = false;
//added by amy for atheros AP
if((info_element->len >= 3 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x03 &&
info_element->data[2] == 0x7f) ||
(info_element->len >= 3 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x13 &&
info_element->data[2] == 0x74))
{
printk("========>%s(): athros AP is exist\n",__FUNCTION__);
network->atheros_cap_exist = true;
}
else
network->atheros_cap_exist = false;
if(info_element->len >= 3 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x40 &&
info_element->data[2] == 0x96)
{
network->cisco_cap_exist = true;
}
else
network->cisco_cap_exist = false;
//added by amy for LEAP of cisco
if(info_element->len > 4 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x40 &&
info_element->data[2] == 0x96 &&
info_element->data[3] == 0x01)
{
if(info_element->len == 6)
{
memcpy(network->CcxRmState, &info_element[4], 2);
if(network->CcxRmState[0] != 0)
{
network->bCcxRmEnable = true;
}
else
network->bCcxRmEnable = false;
//
// CCXv4 Table 59-1 MBSSID Masks.
//
network->MBssidMask = network->CcxRmState[1] & 0x07;
if(network->MBssidMask != 0)
{
network->bMBssidValid = true;
network->MBssidMask = 0xff << (network->MBssidMask);
cpMacAddr(network->MBssid, network->bssid);
network->MBssid[5] &= network->MBssidMask;
}
else
{
network->bMBssidValid = false;
}
}
else
{
network->bCcxRmEnable = false;
}
}
if(info_element->len > 4 &&
info_element->data[0] == 0x00 &&
info_element->data[1] == 0x40 &&
info_element->data[2] == 0x96 &&
info_element->data[3] == 0x03)
{
if(info_element->len == 5)
{
network->bWithCcxVerNum = true;
network->BssCcxVerNumber = info_element->data[4];
}
else
{
network->bWithCcxVerNum = false;
network->BssCcxVerNumber = 0;
}
}
break;
case MFIE_TYPE_RSN:
IEEE80211_DEBUG_MGMT("MFIE_TYPE_RSN: %d bytes\n",
info_element->len);
network->rsn_ie_len = min(info_element->len + 2,
MAX_WPA_IE_LEN);
memcpy(network->rsn_ie, info_element,
network->rsn_ie_len);
break;
//HT related element.
case MFIE_TYPE_HT_CAP:
IEEE80211_DEBUG_SCAN("MFIE_TYPE_HT_CAP: %d bytes\n",
info_element->len);
tmp_htcap_len = min(info_element->len,(u8)MAX_IE_LEN);
if(tmp_htcap_len != 0){
network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC;
network->bssht.bdHTCapLen = tmp_htcap_len > sizeof(network->bssht.bdHTCapBuf)?\
sizeof(network->bssht.bdHTCapBuf):tmp_htcap_len;
memcpy(network->bssht.bdHTCapBuf,info_element->data,network->bssht.bdHTCapLen);
//If peer is HT, but not WMM, call QosSetLegacyWMMParamWithHT()
// windows driver will update WMM parameters each beacon received once connected
// Linux driver is a bit different.
network->bssht.bdSupportHT = true;
}
else
network->bssht.bdSupportHT = false;
break;
case MFIE_TYPE_HT_INFO:
IEEE80211_DEBUG_SCAN("MFIE_TYPE_HT_INFO: %d bytes\n",
info_element->len);
tmp_htinfo_len = min(info_element->len,(u8)MAX_IE_LEN);
if(tmp_htinfo_len){
network->bssht.bdHTSpecVer = HT_SPEC_VER_IEEE;
network->bssht.bdHTInfoLen = tmp_htinfo_len > sizeof(network->bssht.bdHTInfoBuf)?\
sizeof(network->bssht.bdHTInfoBuf):tmp_htinfo_len;
memcpy(network->bssht.bdHTInfoBuf,info_element->data,network->bssht.bdHTInfoLen);
}
break;
case MFIE_TYPE_AIRONET:
IEEE80211_DEBUG_SCAN("MFIE_TYPE_AIRONET: %d bytes\n",
info_element->len);
if(info_element->len >IE_CISCO_FLAG_POSITION)
{
network->bWithAironetIE = true;
// CCX 1 spec v1.13, A01.1 CKIP Negotiation (page23):
// "A Cisco access point advertises support for CKIP in beacon and probe response packets,
// by adding an Aironet element and setting one or both of the CKIP negotiation bits."
if( (info_element->data[IE_CISCO_FLAG_POSITION]&SUPPORT_CKIP_MIC) ||
(info_element->data[IE_CISCO_FLAG_POSITION]&SUPPORT_CKIP_PK) )
{
network->bCkipSupported = true;
}
else
{
network->bCkipSupported = false;
}
}
else
{
network->bWithAironetIE = false;
network->bCkipSupported = false;
}
break;
case MFIE_TYPE_QOS_PARAMETER:
printk(KERN_ERR
"QoS Error need to parse QOS_PARAMETER IE\n");
break;
case MFIE_TYPE_COUNTRY:
IEEE80211_DEBUG_SCAN("MFIE_TYPE_COUNTRY: %d bytes\n",
info_element->len);
//printk("=====>Receive <%s> Country IE\n",network->ssid);
ieee80211_extract_country_ie(ieee, info_element, network, network->bssid);//addr2 is same as addr3 when from an AP
break;
/* TODO */
default:
IEEE80211_DEBUG_MGMT
("Unsupported info element: %s (%d)\n",
get_info_element_string(info_element->id),
info_element->id);
break;
}
length -= sizeof(*info_element) + info_element->len;
info_element =
(struct ieee80211_info_element *)&info_element->
data[info_element->len];
}
if(!network->atheros_cap_exist && !network->broadcom_cap_exist &&
!network->cisco_cap_exist && !network->ralink_cap_exist && !network->bssht.bdRT2RTAggregation)
{
network->unknown_cap_exist = true;
}
else
{
network->unknown_cap_exist = false;
}
return 0;
}
Generated by GNU enscript 1.6.4.