📄 ieee80211_rx.c
字号:
if (memcmp(hdr->addr3, ieee->dev->dev_addr, ETH_ALEN)) is_packet_for_us = 1; } } break; default: /* ? */ break; } if (is_packet_for_us) if (!ieee80211_rx(ieee, skb, stats)) dev_kfree_skb_irq(skb); return;drop_free: dev_kfree_skb_irq(skb); ieee->stats.rx_dropped++; return;}#define MGMT_FRAME_FIXED_PART_LENGTH 0x24static 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;}#ifdef CONFIG_IEEE80211_DEBUG#define MFIE_STRING(x) case MFIE_TYPE_ ##x: return #xstatic const char *get_info_element_string(u16 id){ switch (id) { MFIE_STRING(SSID); MFIE_STRING(RATES); MFIE_STRING(FH_SET); MFIE_STRING(DS_SET); MFIE_STRING(CF_SET); MFIE_STRING(TIM); MFIE_STRING(IBSS_SET); MFIE_STRING(COUNTRY); MFIE_STRING(HOP_PARAMS); MFIE_STRING(HOP_TABLE); MFIE_STRING(REQUEST); MFIE_STRING(CHALLENGE); MFIE_STRING(POWER_CONSTRAINT); MFIE_STRING(POWER_CAPABILITY); MFIE_STRING(TPC_REQUEST); MFIE_STRING(TPC_REPORT); MFIE_STRING(SUPP_CHANNELS); MFIE_STRING(CSA); MFIE_STRING(MEASURE_REQUEST); MFIE_STRING(MEASURE_REPORT); MFIE_STRING(QUIET); MFIE_STRING(IBSS_DFS); MFIE_STRING(ERP_INFO); MFIE_STRING(RSN); MFIE_STRING(RATES_EX); MFIE_STRING(GENERIC); MFIE_STRING(QOS_PARAMETER); default: return "UNKNOWN"; }}#endifstatic int ieee80211_parse_info_param(struct ieee80211_info_element *info_element, u16 length, struct ieee80211_network *network){ u8 i;#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: network->tim.tim_count = info_element->data[0]; network->tim.tim_period = info_element->data[1]; IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: partially ignored\n"); break; case MFIE_TYPE_ERP_INFO: 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; 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; case MFIE_TYPE_QOS_PARAMETER: printk(KERN_ERR "QoS Error need to parse QOS_PARAMETER IE\n"); break; /* 802.11h */ case MFIE_TYPE_POWER_CONSTRAINT: network->power_constraint = info_element->data[0]; network->flags |= NETWORK_HAS_POWER_CONSTRAINT; break; case MFIE_TYPE_CSA: network->power_constraint = info_element->data[0]; network->flags |= NETWORK_HAS_CSA; break; case MFIE_TYPE_QUIET: network->quiet.count = info_element->data[0]; network->quiet.period = info_element->data[1]; network->quiet.duration = info_element->data[2]; network->quiet.offset = info_element->data[3]; network->flags |= NETWORK_HAS_QUIET; break; case MFIE_TYPE_IBSS_DFS: if (network->ibss_dfs) break; network->ibss_dfs = kmemdup(info_element->data, info_element->len, GFP_ATOMIC); if (!network->ibss_dfs) return 1; network->flags |= NETWORK_HAS_IBSS_DFS; break; case MFIE_TYPE_TPC_REPORT: network->tpc_report.transmit_power = info_element->data[0]; network->tpc_report.link_margin = info_element->data[1]; network->flags |= NETWORK_HAS_TPC_REPORT; break; 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]; } return 0;}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 = { .ibss_dfs = NULL, }; struct ieee80211_network *network = &network_resp; struct net_device *dev = ieee->dev; 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -