|
@@ -19,6 +19,7 @@
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/if_arp.h>
|
|
#include <linux/if_arp.h>
|
|
#include <linux/bitmap.h>
|
|
#include <linux/bitmap.h>
|
|
|
|
+#include <linux/crc32.h>
|
|
#include <net/net_namespace.h>
|
|
#include <net/net_namespace.h>
|
|
#include <net/cfg80211.h>
|
|
#include <net/cfg80211.h>
|
|
#include <net/rtnetlink.h>
|
|
#include <net/rtnetlink.h>
|
|
@@ -563,6 +564,172 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(ieee80211_queue_delayed_work);
|
|
EXPORT_SYMBOL(ieee80211_queue_delayed_work);
|
|
|
|
|
|
|
|
+u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
|
|
|
|
+ struct ieee802_11_elems *elems,
|
|
|
|
+ u64 filter, u32 crc)
|
|
|
|
+{
|
|
|
|
+ size_t left = len;
|
|
|
|
+ u8 *pos = start;
|
|
|
|
+ bool calc_crc = filter != 0;
|
|
|
|
+
|
|
|
|
+ memset(elems, 0, sizeof(*elems));
|
|
|
|
+ elems->ie_start = start;
|
|
|
|
+ elems->total_len = len;
|
|
|
|
+
|
|
|
|
+ while (left >= 2) {
|
|
|
|
+ u8 id, elen;
|
|
|
|
+
|
|
|
|
+ id = *pos++;
|
|
|
|
+ elen = *pos++;
|
|
|
|
+ left -= 2;
|
|
|
|
+
|
|
|
|
+ if (elen > left)
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ if (calc_crc && id < 64 && (filter & (1ULL << id)))
|
|
|
|
+ crc = crc32_be(crc, pos - 2, elen + 2);
|
|
|
|
+
|
|
|
|
+ switch (id) {
|
|
|
|
+ case WLAN_EID_SSID:
|
|
|
|
+ elems->ssid = pos;
|
|
|
|
+ elems->ssid_len = elen;
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_SUPP_RATES:
|
|
|
|
+ elems->supp_rates = pos;
|
|
|
|
+ elems->supp_rates_len = elen;
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_FH_PARAMS:
|
|
|
|
+ elems->fh_params = pos;
|
|
|
|
+ elems->fh_params_len = elen;
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_DS_PARAMS:
|
|
|
|
+ elems->ds_params = pos;
|
|
|
|
+ elems->ds_params_len = elen;
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_CF_PARAMS:
|
|
|
|
+ elems->cf_params = pos;
|
|
|
|
+ elems->cf_params_len = elen;
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_TIM:
|
|
|
|
+ if (elen >= sizeof(struct ieee80211_tim_ie)) {
|
|
|
|
+ elems->tim = (void *)pos;
|
|
|
|
+ elems->tim_len = elen;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_IBSS_PARAMS:
|
|
|
|
+ elems->ibss_params = pos;
|
|
|
|
+ elems->ibss_params_len = elen;
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_CHALLENGE:
|
|
|
|
+ elems->challenge = pos;
|
|
|
|
+ elems->challenge_len = elen;
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_VENDOR_SPECIFIC:
|
|
|
|
+ if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
|
|
|
|
+ pos[2] == 0xf2) {
|
|
|
|
+ /* Microsoft OUI (00:50:F2) */
|
|
|
|
+
|
|
|
|
+ if (calc_crc)
|
|
|
|
+ crc = crc32_be(crc, pos - 2, elen + 2);
|
|
|
|
+
|
|
|
|
+ if (pos[3] == 1) {
|
|
|
|
+ /* OUI Type 1 - WPA IE */
|
|
|
|
+ elems->wpa = pos;
|
|
|
|
+ elems->wpa_len = elen;
|
|
|
|
+ } else if (elen >= 5 && pos[3] == 2) {
|
|
|
|
+ /* OUI Type 2 - WMM IE */
|
|
|
|
+ if (pos[4] == 0) {
|
|
|
|
+ elems->wmm_info = pos;
|
|
|
|
+ elems->wmm_info_len = elen;
|
|
|
|
+ } else if (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:
|
|
|
|
+ elems->erp_info = pos;
|
|
|
|
+ elems->erp_info_len = elen;
|
|
|
|
+ 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 (elen >= sizeof(struct ieee80211_ht_cap))
|
|
|
|
+ elems->ht_cap_elem = (void *)pos;
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_HT_INFORMATION:
|
|
|
|
+ if (elen >= sizeof(struct ieee80211_ht_info))
|
|
|
|
+ elems->ht_info_elem = (void *)pos;
|
|
|
|
+ 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;
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_PEER_MGMT:
|
|
|
|
+ elems->peering = pos;
|
|
|
|
+ elems->peering_len = elen;
|
|
|
|
+ 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;
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_CHANNEL_SWITCH:
|
|
|
|
+ elems->ch_switch_elem = pos;
|
|
|
|
+ elems->ch_switch_elem_len = elen;
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_QUIET:
|
|
|
|
+ if (!elems->quiet_elem) {
|
|
|
|
+ elems->quiet_elem = pos;
|
|
|
|
+ elems->quiet_elem_len = elen;
|
|
|
|
+ }
|
|
|
|
+ elems->num_of_quiet_elem++;
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_COUNTRY:
|
|
|
|
+ elems->country_elem = pos;
|
|
|
|
+ elems->country_elem_len = elen;
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_PWR_CONSTRAINT:
|
|
|
|
+ elems->pwr_constr_elem = pos;
|
|
|
|
+ elems->pwr_constr_elem_len = elen;
|
|
|
|
+ break;
|
|
|
|
+ case WLAN_EID_TIMEOUT_INTERVAL:
|
|
|
|
+ elems->timeout_int = pos;
|
|
|
|
+ elems->timeout_int_len = elen;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ left -= elen;
|
|
|
|
+ pos += elen;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return crc;
|
|
|
|
+}
|
|
|
|
+
|
|
void ieee802_11_parse_elems(u8 *start, size_t len,
|
|
void ieee802_11_parse_elems(u8 *start, size_t len,
|
|
struct ieee802_11_elems *elems)
|
|
struct ieee802_11_elems *elems)
|
|
{
|
|
{
|