struct ieee80211_elems_parse { /* must be first for kfree to work */ struct ieee802_11_elems elems;
/* The basic Multi-Link element in the original elements */ conststruct element *ml_basic_elem;
/* The reconfiguration Multi-Link element in the original elements */ conststruct element *ml_reconf_elem;
/* The EPCS Multi-Link element in the original elements */ conststruct element *ml_epcs_elem;
bool multi_link_inner; bool skip_vendor;
/* * scratch buffer that can be used for various element parsing related * tasks, e.g., element de-fragmentation etc.
*/
size_t scratch_len;
u8 *scratch_pos;
u8 scratch[] __counted_by(scratch_len);
};
if (check_inherit &&
!cfg80211_is_element_inherited(elem,
check_inherit)) continue;
switch (id) { case WLAN_EID_SSID: case WLAN_EID_SUPP_RATES: case WLAN_EID_FH_PARAMS: case WLAN_EID_DS_PARAMS: case WLAN_EID_CF_PARAMS: case WLAN_EID_TIM: case WLAN_EID_IBSS_PARAMS: case WLAN_EID_CHALLENGE: case WLAN_EID_RSN: case WLAN_EID_ERP_INFO: case WLAN_EID_EXT_SUPP_RATES: case WLAN_EID_HT_CAPABILITY: case WLAN_EID_HT_OPERATION: case WLAN_EID_VHT_CAPABILITY: case WLAN_EID_VHT_OPERATION: case WLAN_EID_MESH_ID: case WLAN_EID_MESH_CONFIG: case WLAN_EID_PEER_MGMT: case WLAN_EID_PREQ: case WLAN_EID_PREP: case WLAN_EID_PERR: case WLAN_EID_RANN: case WLAN_EID_CHANNEL_SWITCH: case WLAN_EID_EXT_CHANSWITCH_ANN: case WLAN_EID_COUNTRY: case WLAN_EID_PWR_CONSTRAINT: case WLAN_EID_TIMEOUT_INTERVAL: case WLAN_EID_SECONDARY_CHANNEL_OFFSET: case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: case WLAN_EID_CHAN_SWITCH_PARAM: case WLAN_EID_EXT_CAPABILITY: case WLAN_EID_CHAN_SWITCH_TIMING: case WLAN_EID_LINK_ID: case WLAN_EID_BSS_MAX_IDLE_PERIOD: case WLAN_EID_RSNX: case WLAN_EID_S1G_BCN_COMPAT: case WLAN_EID_S1G_CAPABILITIES: case WLAN_EID_S1G_OPERATION: case WLAN_EID_AID_RESPONSE: case WLAN_EID_S1G_SHORT_BCN_INTERVAL: /* * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible * that if the content gets bigger it might be needed more than once
*/ if (test_bit(id, seen_elems)) {
elems->parse_error |=
IEEE80211_PARSE_ERR_DUP_ELEM; continue;
} break;
}
if (elen >= 5 && pos[3] == 2) { /* OUI Type 2 - WMM IE */ if (pos[4] == 0) {
elems->wmm_info = pos;
elems->wmm_info_len = elen;
} elseif (pos[4] == 1) {
elems->wmm_param = pos;
elems->wmm_param_len = elen;
}
}
} break; case WLAN_EID_RSN:
elems->rsn = pos;
elems->rsn_len = elen; break; case WLAN_EID_ERP_INFO: if (elen >= 1)
elems->erp_info = pos; else
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_EXT_SUPP_RATES:
elems->ext_supp_rates = pos;
elems->ext_supp_rates_len = elen; break; case WLAN_EID_HT_CAPABILITY: if (params->mode < IEEE80211_CONN_MODE_HT) break; if (elen >= sizeof(struct ieee80211_ht_cap))
elems->ht_cap_elem = (void *)pos; else
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_HT_OPERATION: if (params->mode < IEEE80211_CONN_MODE_HT) break; if (elen >= sizeof(struct ieee80211_ht_operation))
elems->ht_operation = (void *)pos; else
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_VHT_CAPABILITY: if (params->mode < IEEE80211_CONN_MODE_VHT) break; if (elen >= sizeof(struct ieee80211_vht_cap))
elems->vht_cap_elem = (void *)pos; else
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_VHT_OPERATION: if (params->mode < IEEE80211_CONN_MODE_VHT) break; if (elen >= sizeof(struct ieee80211_vht_operation)) {
elems->vht_operation = (void *)pos; if (calc_crc)
crc = crc32_be(crc, pos - 2, elen + 2); break;
}
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_OPMODE_NOTIF: if (params->mode < IEEE80211_CONN_MODE_VHT) break; if (elen > 0) {
elems->opmode_notif = pos; if (calc_crc)
crc = crc32_be(crc, pos - 2, elen + 2); break;
}
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_MESH_ID:
elems->mesh_id = pos;
elems->mesh_id_len = elen; break; case WLAN_EID_MESH_CONFIG: if (elen >= sizeof(struct ieee80211_meshconf_ie))
elems->mesh_config = (void *)pos; else
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_PEER_MGMT:
elems->peering = pos;
elems->peering_len = elen; break; case WLAN_EID_MESH_AWAKE_WINDOW: if (elen >= 2)
elems->awake_window = (void *)pos; break; case WLAN_EID_PREQ:
elems->preq = pos;
elems->preq_len = elen; break; case WLAN_EID_PREP:
elems->prep = pos;
elems->prep_len = elen; break; case WLAN_EID_PERR:
elems->perr = pos;
elems->perr_len = elen; break; case WLAN_EID_RANN: if (elen >= sizeof(struct ieee80211_rann_ie))
elems->rann = (void *)pos; else
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break; case WLAN_EID_CHANNEL_SWITCH: if (elen != sizeof(struct ieee80211_channel_sw_ie)) {
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break;
}
elems->ch_switch_ie = (void *)pos; break; case WLAN_EID_EXT_CHANSWITCH_ANN: if (elen != sizeof(struct ieee80211_ext_chansw_ie)) {
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break;
}
elems->ext_chansw_ie = (void *)pos; break; case WLAN_EID_SECONDARY_CHANNEL_OFFSET: if (params->mode < IEEE80211_CONN_MODE_HT) break; if (elen != sizeof(struct ieee80211_sec_chan_offs_ie)) {
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break;
}
elems->sec_chan_offs = (void *)pos; break; case WLAN_EID_CHAN_SWITCH_PARAM: if (elen < sizeof(*elems->mesh_chansw_params_ie)) {
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break;
}
elems->mesh_chansw_params_ie = (void *)pos; break; case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: if (params->mode < IEEE80211_CONN_MODE_VHT) break;
if (!params->action) {
elem_parse_failed =
IEEE80211_PARSE_ERR_UNEXPECTED_ELEM; break;
}
if (elen < sizeof(*elems->wide_bw_chansw_ie)) {
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break;
}
elems->wide_bw_chansw_ie = (void *)pos; break; case WLAN_EID_CHANNEL_SWITCH_WRAPPER: if (params->mode < IEEE80211_CONN_MODE_VHT) break; if (params->action) {
elem_parse_failed =
IEEE80211_PARSE_ERR_UNEXPECTED_ELEM; break;
} /* * This is a bit tricky, but as we only care about * a few elements, parse them out manually.
*/
subelem = cfg80211_find_elem(WLAN_EID_WIDE_BW_CHANNEL_SWITCH,
pos, elen); if (subelem) { if (subelem->datalen >= sizeof(*elems->wide_bw_chansw_ie))
elems->wide_bw_chansw_ie =
(void *)subelem->data; else
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE;
}
if (params->mode < IEEE80211_CONN_MODE_EHT) break;
subelem = cfg80211_find_ext_elem(WLAN_EID_TX_POWER_ENVELOPE,
pos, elen); if (subelem)
ieee80211_parse_tpe(&elems->csa_tpe,
subelem->data + 1,
subelem->datalen - 1); break; case WLAN_EID_COUNTRY:
elems->country_elem = pos;
elems->country_elem_len = elen; break; case WLAN_EID_PWR_CONSTRAINT: if (elen != 1) {
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break;
}
elems->pwr_constr_elem = pos; break; case WLAN_EID_CISCO_VENDOR_SPECIFIC: /* Lots of different options exist, but we only care * about the Dynamic Transmit Power Control element. * First check for the Cisco OUI, then for the DTPC * tag (0x00).
*/ if (elen < 4) {
elem_parse_failed =
IEEE80211_PARSE_ERR_BAD_ELEM_SIZE; break;
}
if (sub->id != 0 || sub->datalen < 4) { /* not a valid BSS profile */ continue;
}
if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP ||
sub->data[1] != 2) { /* The first element of the * Nontransmitted BSSID Profile is not * the Nontransmitted BSSID Capability * element.
*/ continue;
}
if (sub->id != IEEE80211_MLE_SUBELEM_PER_STA_PROFILE) continue;
if (!ieee80211_mle_basic_sta_prof_size_ok(sub->data,
sub->datalen)) return;
control = le16_to_cpu(prof->control);
if (link_id != u16_get_bits(control,
IEEE80211_MLE_STA_CONTROL_LINK_ID)) continue;
if (!(control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE)) return;
/* the sub element can be fragmented */
sta_prof_len =
cfg80211_defragment_element(sub,
(u8 *)ml, ml_len,
elems_parse->scratch_pos,
elems_parse->scratch +
elems_parse->scratch_len -
elems_parse->scratch_pos,
IEEE80211_MLE_SUBELEM_FRAGMENT);
/* check if we have the 4 bytes for the fixed part in assoc response */ if (elems->sta_prof_len < sizeof(*prof) + prof->sta_info_len - 1 + 4) {
elems->prof = NULL;
elems->sta_prof_len = 0; return NULL;
}
/* * Skip the capability information and the status code that are expected * as part of the station profile in association response frames. Note * the -1 is because the 'sta_info_len' is accounted to as part of the * per-STA profile, but not part of the 'u8 variable[]' portion.
*/
sub->start = prof->variable + prof->sta_info_len - 1 + 4;
end = (const u8 *)prof + elems->sta_prof_len;
sub->len = end - sub->start;
/* set all TPE entries to unlimited (but invalid) */
ieee80211_clear_tpe(&elems->tpe);
ieee80211_clear_tpe(&elems->csa_tpe);
/* * If we're looking for a non-transmitted BSS then we cannot at * the same time be looking for a second link as the two can only * appear in the same frame carrying info for different BSSes. * * In any case, we only look for one at a time, as encoded by * the WARN_ON above.
*/ if (params->bss) { int nontx_len =
ieee802_11_find_bssid_profile(params->start,
params->len,
elems, params->bss,
elems_parse->scratch_pos);
sub.start = elems_parse->scratch_pos;
sub.mode = params->mode;
sub.len = nontx_len;
sub.action = params->action;
sub.link_id = params->link_id;
/* consume the space used for non-transmitted profile */
elems_parse->scratch_pos += nontx_len;
non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
sub.start, nontx_len);
} else { /* must always parse to get elems_parse->ml_basic_elem */
non_inherit = ieee80211_prep_mle_link_parse(elems_parse, params,
&sub);
multi_link_inner = true;
}
/* Override DTIM period and count if needed */ if (elems->bssid_index &&
elems->bssid_index_len >=
offsetofend(struct ieee80211_bssid_index, dtim_period))
elems->dtim_period = elems->bssid_index->dtim_period;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.