aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2014-10-26 14:13:27 (GMT)
committerJouni Malinen <j@w1.fi>2014-10-26 15:54:56 (GMT)
commit8a906d1251d74585849a7417fc59414f3c534717 (patch)
tree6637ac897b7e14856f283ea0e9ca3c67f0e3c8e8
parent0fafeb5454fa3271250a46088fc806974e750ee3 (diff)
downloadhostap-8a906d1251d74585849a7417fc59414f3c534717.zip
hostap-8a906d1251d74585849a7417fc59414f3c534717.tar.gz
hostap-8a906d1251d74585849a7417fc59414f3c534717.tar.bz2
nl80211: Move event handling into a separate file
Signed-off-by: Jouni Malinen <j@w1.fi>
-rw-r--r--src/drivers/driver_nl80211.c636
-rw-r--r--src/drivers/driver_nl80211.h23
-rw-r--r--src/drivers/driver_nl80211_event.c651
-rw-r--r--src/drivers/drivers.mak1
-rw-r--r--src/drivers/drivers.mk1
5 files changed, 677 insertions, 635 deletions
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 5e3453f..9e0b714 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -186,7 +186,7 @@ static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
static int i802_set_iface_flags(struct i802_bss *bss, int up);
-static const char * nl80211_command_to_string(enum nl80211_commands cmd)
+const char * nl80211_command_to_string(enum nl80211_commands cmd)
{
#define C2S(x) case x: return #x;
switch (cmd) {
@@ -1220,48 +1220,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
}
-static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
- const u8 *frame, size_t len)
-{
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
-
- if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
- drv->force_connect_cmd) {
- /*
- * Avoid reporting two association events that would confuse
- * the core code.
- */
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignore auth event when using driver SME");
- return;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
- mgmt = (const struct ieee80211_mgmt *) frame;
- if (len < 24 + sizeof(mgmt->u.auth)) {
- wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
- "frame");
- return;
- }
-
- os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
- os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
- os_memset(&event, 0, sizeof(event));
- os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
- event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
- event.auth.auth_transaction =
- le_to_host16(mgmt->u.auth.auth_transaction);
- event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
- if (len > 24 + sizeof(mgmt->u.auth)) {
- event.auth.ies = mgmt->u.auth.variable;
- event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
- }
-
- wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
-}
-
-
unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
{
struct nl_msg *msg;
@@ -1296,598 +1254,6 @@ nla_put_failure:
}
-static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
- const u8 *frame, size_t len)
-{
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
- u16 status;
-
- if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
- drv->force_connect_cmd) {
- /*
- * Avoid reporting two association events that would confuse
- * the core code.
- */
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignore assoc event when using driver SME");
- return;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Associate event");
- mgmt = (const struct ieee80211_mgmt *) frame;
- if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
- wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
- "frame");
- return;
- }
-
- status = le_to_host16(mgmt->u.assoc_resp.status_code);
- if (status != WLAN_STATUS_SUCCESS) {
- os_memset(&event, 0, sizeof(event));
- event.assoc_reject.bssid = mgmt->bssid;
- if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
- event.assoc_reject.resp_ies =
- (u8 *) mgmt->u.assoc_resp.variable;
- event.assoc_reject.resp_ies_len =
- len - 24 - sizeof(mgmt->u.assoc_resp);
- }
- event.assoc_reject.status_code = status;
-
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
- return;
- }
-
- drv->associated = 1;
- os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
- os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
-
- os_memset(&event, 0, sizeof(event));
- if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
- event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
- event.assoc_info.resp_ies_len =
- len - 24 - sizeof(mgmt->u.assoc_resp);
- }
-
- event.assoc_info.freq = drv->assoc_freq;
-
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
-}
-
-
-static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
- enum nl80211_commands cmd, struct nlattr *status,
- struct nlattr *addr, struct nlattr *req_ie,
- struct nlattr *resp_ie,
- struct nlattr *authorized,
- struct nlattr *key_replay_ctr,
- struct nlattr *ptk_kck,
- struct nlattr *ptk_kek)
-{
- union wpa_event_data event;
-
- if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
- /*
- * Avoid reporting two association events that would confuse
- * the core code.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
- "when using userspace SME", cmd);
- return;
- }
-
- if (cmd == NL80211_CMD_CONNECT)
- wpa_printf(MSG_DEBUG, "nl80211: Connect event");
- else if (cmd == NL80211_CMD_ROAM)
- wpa_printf(MSG_DEBUG, "nl80211: Roam event");
-
- os_memset(&event, 0, sizeof(event));
- if (cmd == NL80211_CMD_CONNECT &&
- nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
- if (addr)
- event.assoc_reject.bssid = nla_data(addr);
- if (resp_ie) {
- event.assoc_reject.resp_ies = nla_data(resp_ie);
- event.assoc_reject.resp_ies_len = nla_len(resp_ie);
- }
- event.assoc_reject.status_code = nla_get_u16(status);
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
- return;
- }
-
- drv->associated = 1;
- if (addr) {
- os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
- os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
- }
-
- if (req_ie) {
- event.assoc_info.req_ies = nla_data(req_ie);
- event.assoc_info.req_ies_len = nla_len(req_ie);
- }
- if (resp_ie) {
- event.assoc_info.resp_ies = nla_data(resp_ie);
- event.assoc_info.resp_ies_len = nla_len(resp_ie);
- }
-
- event.assoc_info.freq = nl80211_get_assoc_freq(drv);
-
- if (authorized && nla_get_u8(authorized)) {
- event.assoc_info.authorized = 1;
- wpa_printf(MSG_DEBUG, "nl80211: connection authorized");
- }
- if (key_replay_ctr) {
- event.assoc_info.key_replay_ctr = nla_data(key_replay_ctr);
- event.assoc_info.key_replay_ctr_len = nla_len(key_replay_ctr);
- }
- if (ptk_kck) {
- event.assoc_info.ptk_kck = nla_data(ptk_kck);
- event.assoc_info.ptk_kck_len = nla_len(ptk_kek);
- }
- if (ptk_kek) {
- event.assoc_info.ptk_kek = nla_data(ptk_kek);
- event.assoc_info.ptk_kek_len = nla_len(ptk_kek);
- }
-
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
-}
-
-
-static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
- struct nlattr *reason, struct nlattr *addr,
- struct nlattr *by_ap)
-{
- union wpa_event_data data;
- unsigned int locally_generated = by_ap == NULL;
-
- if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
- /*
- * Avoid reporting two disassociation events that could
- * confuse the core code.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
- "event when using userspace SME");
- return;
- }
-
- if (drv->ignore_next_local_disconnect) {
- drv->ignore_next_local_disconnect = 0;
- if (locally_generated) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
- "event triggered during reassociation");
- return;
- }
- wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
- "disconnect but got another disconnect "
- "event first");
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
- nl80211_mark_disconnected(drv);
- os_memset(&data, 0, sizeof(data));
- if (reason)
- data.deauth_info.reason_code = nla_get_u16(reason);
- data.deauth_info.locally_generated = by_ap == NULL;
- wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
-}
-
-
-static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
-{
- int freq1 = 0;
-
- switch (convert2width(width)) {
- case CHAN_WIDTH_20_NOHT:
- case CHAN_WIDTH_20:
- return 0;
- case CHAN_WIDTH_40:
- freq1 = cf1 - 10;
- break;
- case CHAN_WIDTH_80:
- freq1 = cf1 - 30;
- break;
- case CHAN_WIDTH_160:
- freq1 = cf1 - 70;
- break;
- case CHAN_WIDTH_UNKNOWN:
- case CHAN_WIDTH_80P80:
- /* FIXME: implement this */
- return 0;
- }
-
- return (abs(freq - freq1) / 20) % 2 == 0 ? 1 : -1;
-}
-
-
-static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
- struct nlattr *ifindex, struct nlattr *freq,
- struct nlattr *type, struct nlattr *bw,
- struct nlattr *cf1, struct nlattr *cf2)
-{
- struct i802_bss *bss;
- union wpa_event_data data;
- int ht_enabled = 1;
- int chan_offset = 0;
- int ifidx;
-
- wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
-
- if (!freq)
- return;
-
- ifidx = nla_get_u32(ifindex);
- bss = get_bss_ifindex(drv, ifidx);
- if (bss == NULL) {
- wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
- ifidx);
- return;
- }
-
- if (type) {
- enum nl80211_channel_type ch_type = nla_get_u32(type);
-
- wpa_printf(MSG_DEBUG, "nl80211: Channel type: %d", ch_type);
- switch (ch_type) {
- case NL80211_CHAN_NO_HT:
- ht_enabled = 0;
- break;
- case NL80211_CHAN_HT20:
- break;
- case NL80211_CHAN_HT40PLUS:
- chan_offset = 1;
- break;
- case NL80211_CHAN_HT40MINUS:
- chan_offset = -1;
- break;
- }
- } else if (bw && cf1) {
- /* This can happen for example with VHT80 ch switch */
- chan_offset = calculate_chan_offset(nla_get_u32(bw),
- nla_get_u32(freq),
- nla_get_u32(cf1),
- cf2 ? nla_get_u32(cf2) : 0);
- } else {
- wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail");
- }
-
- os_memset(&data, 0, sizeof(data));
- data.ch_switch.freq = nla_get_u32(freq);
- data.ch_switch.ht_enabled = ht_enabled;
- data.ch_switch.ch_offset = chan_offset;
- if (bw)
- data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
- if (cf1)
- data.ch_switch.cf1 = nla_get_u32(cf1);
- if (cf2)
- data.ch_switch.cf2 = nla_get_u32(cf2);
-
- bss->freq = data.ch_switch.freq;
-
- wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
-}
-
-
-static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
- enum nl80211_commands cmd, struct nlattr *addr)
-{
- union wpa_event_data event;
- enum wpa_event_type ev;
-
- if (nla_len(addr) != ETH_ALEN)
- return;
-
- wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
- cmd, MAC2STR((u8 *) nla_data(addr)));
-
- if (cmd == NL80211_CMD_AUTHENTICATE)
- ev = EVENT_AUTH_TIMED_OUT;
- else if (cmd == NL80211_CMD_ASSOCIATE)
- ev = EVENT_ASSOC_TIMED_OUT;
- else
- return;
-
- os_memset(&event, 0, sizeof(event));
- os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
- wpa_supplicant_event(drv->ctx, ev, &event);
-}
-
-
-static void mlme_event_mgmt(struct i802_bss *bss,
- struct nlattr *freq, struct nlattr *sig,
- const u8 *frame, size_t len)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
- u16 fc, stype;
- int ssi_signal = 0;
- int rx_freq = 0;
-
- wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
- mgmt = (const struct ieee80211_mgmt *) frame;
- if (len < 24) {
- wpa_printf(MSG_DEBUG, "nl80211: Too short management frame");
- return;
- }
-
- fc = le_to_host16(mgmt->frame_control);
- stype = WLAN_FC_GET_STYPE(fc);
-
- if (sig)
- ssi_signal = (s32) nla_get_u32(sig);
-
- os_memset(&event, 0, sizeof(event));
- if (freq) {
- event.rx_mgmt.freq = nla_get_u32(freq);
- rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq;
- }
- wpa_printf(MSG_DEBUG,
- "nl80211: RX frame sa=" MACSTR
- " freq=%d ssi_signal=%d stype=%u (%s) len=%u",
- MAC2STR(mgmt->sa), rx_freq, ssi_signal, stype, fc2str(fc),
- (unsigned int) len);
- event.rx_mgmt.frame = frame;
- event.rx_mgmt.frame_len = len;
- event.rx_mgmt.ssi_signal = ssi_signal;
- event.rx_mgmt.drv_priv = bss;
- wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
-}
-
-
-static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
- struct nlattr *cookie, const u8 *frame,
- size_t len, struct nlattr *ack)
-{
- union wpa_event_data event;
- const struct ieee80211_hdr *hdr;
- u16 fc;
-
- wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
- if (!is_ap_interface(drv->nlmode)) {
- u64 cookie_val;
-
- if (!cookie)
- return;
-
- cookie_val = nla_get_u64(cookie);
- wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
- " cookie=0%llx%s (ack=%d)",
- (long long unsigned int) cookie_val,
- cookie_val == drv->send_action_cookie ?
- " (match)" : " (unknown)", ack != NULL);
- if (cookie_val != drv->send_action_cookie)
- return;
- }
-
- hdr = (const struct ieee80211_hdr *) frame;
- fc = le_to_host16(hdr->frame_control);
-
- os_memset(&event, 0, sizeof(event));
- event.tx_status.type = WLAN_FC_GET_TYPE(fc);
- event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
- event.tx_status.dst = hdr->addr1;
- event.tx_status.data = frame;
- event.tx_status.data_len = len;
- event.tx_status.ack = ack != NULL;
- wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
-}
-
-
-static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
- enum wpa_event_type type,
- const u8 *frame, size_t len)
-{
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
- const u8 *bssid = NULL;
- u16 reason_code = 0;
-
- if (type == EVENT_DEAUTH)
- wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
- else
- wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
-
- mgmt = (const struct ieee80211_mgmt *) frame;
- if (len >= 24) {
- bssid = mgmt->bssid;
-
- if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
- !drv->associated &&
- os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 &&
- os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 &&
- os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) {
- /*
- * Avoid issues with some roaming cases where
- * disconnection event for the old AP may show up after
- * we have started connection with the new AP.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
- MAC2STR(bssid),
- MAC2STR(drv->auth_attempt_bssid));
- return;
- }
-
- if (drv->associated != 0 &&
- os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
- os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
- /*
- * We have presumably received this deauth as a
- * response to a clear_state_mismatch() outgoing
- * deauth. Don't let it take us offline!
- */
- wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
- "from Unknown BSSID " MACSTR " -- ignoring",
- MAC2STR(bssid));
- return;
- }
- }
-
- nl80211_mark_disconnected(drv);
- os_memset(&event, 0, sizeof(event));
-
- /* Note: Same offset for Reason Code in both frame subtypes */
- if (len >= 24 + sizeof(mgmt->u.deauth))
- reason_code = le_to_host16(mgmt->u.deauth.reason_code);
-
- if (type == EVENT_DISASSOC) {
- event.disassoc_info.locally_generated =
- !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
- event.disassoc_info.addr = bssid;
- event.disassoc_info.reason_code = reason_code;
- if (frame + len > mgmt->u.disassoc.variable) {
- event.disassoc_info.ie = mgmt->u.disassoc.variable;
- event.disassoc_info.ie_len = frame + len -
- mgmt->u.disassoc.variable;
- }
- } else {
- if (drv->ignore_deauth_event) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event due to previous forced deauth-during-auth");
- drv->ignore_deauth_event = 0;
- return;
- }
- event.deauth_info.locally_generated =
- !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
- if (drv->ignore_next_local_deauth) {
- drv->ignore_next_local_deauth = 0;
- if (event.deauth_info.locally_generated) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event triggered due to own deauth request");
- return;
- }
- wpa_printf(MSG_WARNING, "nl80211: Was expecting local deauth but got another disconnect event first");
- }
- event.deauth_info.addr = bssid;
- event.deauth_info.reason_code = reason_code;
- if (frame + len > mgmt->u.deauth.variable) {
- event.deauth_info.ie = mgmt->u.deauth.variable;
- event.deauth_info.ie_len = frame + len -
- mgmt->u.deauth.variable;
- }
- }
-
- wpa_supplicant_event(drv->ctx, type, &event);
-}
-
-
-static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
- enum wpa_event_type type,
- const u8 *frame, size_t len)
-{
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
- u16 reason_code = 0;
-
- if (type == EVENT_UNPROT_DEAUTH)
- wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
- else
- wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
-
- if (len < 24)
- return;
-
- mgmt = (const struct ieee80211_mgmt *) frame;
-
- os_memset(&event, 0, sizeof(event));
- /* Note: Same offset for Reason Code in both frame subtypes */
- if (len >= 24 + sizeof(mgmt->u.deauth))
- reason_code = le_to_host16(mgmt->u.deauth.reason_code);
-
- if (type == EVENT_UNPROT_DISASSOC) {
- event.unprot_disassoc.sa = mgmt->sa;
- event.unprot_disassoc.da = mgmt->da;
- event.unprot_disassoc.reason_code = reason_code;
- } else {
- event.unprot_deauth.sa = mgmt->sa;
- event.unprot_deauth.da = mgmt->da;
- event.unprot_deauth.reason_code = reason_code;
- }
-
- wpa_supplicant_event(drv->ctx, type, &event);
-}
-
-
-static void mlme_event(struct i802_bss *bss,
- enum nl80211_commands cmd, struct nlattr *frame,
- struct nlattr *addr, struct nlattr *timed_out,
- struct nlattr *freq, struct nlattr *ack,
- struct nlattr *cookie, struct nlattr *sig)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- const u8 *data;
- size_t len;
-
- if (timed_out && addr) {
- mlme_timeout_event(drv, cmd, addr);
- return;
- }
-
- if (frame == NULL) {
- wpa_printf(MSG_DEBUG,
- "nl80211: MLME event %d (%s) without frame data",
- cmd, nl80211_command_to_string(cmd));
- return;
- }
-
- data = nla_data(frame);
- len = nla_len(frame);
- if (len < 4 + 2 * ETH_ALEN) {
- wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
- MACSTR ") - too short",
- cmd, nl80211_command_to_string(cmd), bss->ifname,
- MAC2STR(bss->addr));
- return;
- }
- wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
- ") A1=" MACSTR " A2=" MACSTR, cmd,
- nl80211_command_to_string(cmd), bss->ifname,
- MAC2STR(bss->addr), MAC2STR(data + 4),
- MAC2STR(data + 4 + ETH_ALEN));
- if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
- os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
- os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
- wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
- "for foreign address", bss->ifname);
- return;
- }
- wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
- nla_data(frame), nla_len(frame));
-
- switch (cmd) {
- case NL80211_CMD_AUTHENTICATE:
- mlme_event_auth(drv, nla_data(frame), nla_len(frame));
- break;
- case NL80211_CMD_ASSOCIATE:
- mlme_event_assoc(drv, nla_data(frame), nla_len(frame));
- break;
- case NL80211_CMD_DEAUTHENTICATE:
- mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
- nla_data(frame), nla_len(frame));
- break;
- case NL80211_CMD_DISASSOCIATE:
- mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
- nla_data(frame), nla_len(frame));
- break;
- case NL80211_CMD_FRAME:
- mlme_event_mgmt(bss, freq, sig, nla_data(frame),
- nla_len(frame));
- break;
- case NL80211_CMD_FRAME_TX_STATUS:
- mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
- nla_len(frame), ack);
- break;
- case NL80211_CMD_UNPROT_DEAUTHENTICATE:
- mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
- nla_data(frame), nla_len(frame));
- break;
- case NL80211_CMD_UNPROT_DISASSOCIATE:
- mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
- nla_data(frame), nla_len(frame));
- break;
- default:
- break;
- }
-}
-
-
static void mlme_event_michael_mic_failure(struct i802_bss *bss,
struct nlattr *tb[])
{
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index fdc145b..750a83b 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -181,6 +181,7 @@ struct wpa_driver_nl80211_data {
};
struct nl_msg;
+struct nlattr;
int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss);
void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
@@ -209,6 +210,7 @@ int nl80211_get_wiphy_index(struct i802_bss *bss);
int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
enum nl80211_iftype nlmode);
void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx);
+const char * nl80211_command_to_string(enum nl80211_commands cmd);
int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv);
void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv);
@@ -220,6 +222,27 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv);
struct hostapd_hw_modes *
nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags);
+void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *status,
+ struct nlattr *addr, struct nlattr *req_ie,
+ struct nlattr *resp_ie,
+ struct nlattr *authorized,
+ struct nlattr *key_replay_ctr,
+ struct nlattr *ptk_kck,
+ struct nlattr *ptk_kek);
+void mlme_event(struct i802_bss *bss,
+ enum nl80211_commands cmd, struct nlattr *frame,
+ struct nlattr *addr, struct nlattr *timed_out,
+ struct nlattr *freq, struct nlattr *ack,
+ struct nlattr *cookie, struct nlattr *sig);
+void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *ifindex, struct nlattr *freq,
+ struct nlattr *type, struct nlattr *bw,
+ struct nlattr *cf1, struct nlattr *cf2);
+void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *reason, struct nlattr *addr,
+ struct nlattr *by_ap);
+
#ifdef ANDROID
int android_nl_socket_set_nonblocking(struct nl_handle *handle);
int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name);
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
new file mode 100644
index 0000000..1259441
--- /dev/null
+++ b/src/drivers/driver_nl80211_event.c
@@ -0,0 +1,651 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Event processing
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netlink/genl/genl.h>
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "driver_nl80211.h"
+
+
+static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ drv->force_connect_cmd) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore auth event when using driver SME");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24 + sizeof(mgmt->u.auth)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+ "frame");
+ return;
+ }
+
+ os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
+ os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
+ os_memset(&event, 0, sizeof(event));
+ os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
+ event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
+ event.auth.auth_transaction =
+ le_to_host16(mgmt->u.auth.auth_transaction);
+ event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
+ if (len > 24 + sizeof(mgmt->u.auth)) {
+ event.auth.ies = mgmt->u.auth.variable;
+ event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
+}
+
+
+static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 status;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ drv->force_connect_cmd) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore assoc event when using driver SME");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Associate event");
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+ "frame");
+ return;
+ }
+
+ status = le_to_host16(mgmt->u.assoc_resp.status_code);
+ if (status != WLAN_STATUS_SUCCESS) {
+ os_memset(&event, 0, sizeof(event));
+ event.assoc_reject.bssid = mgmt->bssid;
+ if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
+ event.assoc_reject.resp_ies =
+ (u8 *) mgmt->u.assoc_resp.variable;
+ event.assoc_reject.resp_ies_len =
+ len - 24 - sizeof(mgmt->u.assoc_resp);
+ }
+ event.assoc_reject.status_code = status;
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+ return;
+ }
+
+ drv->associated = 1;
+ os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
+ os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
+
+ os_memset(&event, 0, sizeof(event));
+ if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
+ event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
+ event.assoc_info.resp_ies_len =
+ len - 24 - sizeof(mgmt->u.assoc_resp);
+ }
+
+ event.assoc_info.freq = drv->assoc_freq;
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+}
+
+
+void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *status,
+ struct nlattr *addr, struct nlattr *req_ie,
+ struct nlattr *resp_ie,
+ struct nlattr *authorized,
+ struct nlattr *key_replay_ctr,
+ struct nlattr *ptk_kck,
+ struct nlattr *ptk_kek)
+{
+ union wpa_event_data event;
+
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
+ "when using userspace SME", cmd);
+ return;
+ }
+
+ if (cmd == NL80211_CMD_CONNECT)
+ wpa_printf(MSG_DEBUG, "nl80211: Connect event");
+ else if (cmd == NL80211_CMD_ROAM)
+ wpa_printf(MSG_DEBUG, "nl80211: Roam event");
+
+ os_memset(&event, 0, sizeof(event));
+ if (cmd == NL80211_CMD_CONNECT &&
+ nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
+ if (addr)
+ event.assoc_reject.bssid = nla_data(addr);
+ if (resp_ie) {
+ event.assoc_reject.resp_ies = nla_data(resp_ie);
+ event.assoc_reject.resp_ies_len = nla_len(resp_ie);
+ }
+ event.assoc_reject.status_code = nla_get_u16(status);
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+ return;
+ }
+
+ drv->associated = 1;
+ if (addr) {
+ os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
+ os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+ }
+
+ if (req_ie) {
+ event.assoc_info.req_ies = nla_data(req_ie);
+ event.assoc_info.req_ies_len = nla_len(req_ie);
+ }
+ if (resp_ie) {
+ event.assoc_info.resp_ies = nla_data(resp_ie);
+ event.assoc_info.resp_ies_len = nla_len(resp_ie);
+ }
+
+ event.assoc_info.freq = nl80211_get_assoc_freq(drv);
+
+ if (authorized && nla_get_u8(authorized)) {
+ event.assoc_info.authorized = 1;
+ wpa_printf(MSG_DEBUG, "nl80211: connection authorized");
+ }
+ if (key_replay_ctr) {
+ event.assoc_info.key_replay_ctr = nla_data(key_replay_ctr);
+ event.assoc_info.key_replay_ctr_len = nla_len(key_replay_ctr);
+ }
+ if (ptk_kck) {
+ event.assoc_info.ptk_kck = nla_data(ptk_kck);
+ event.assoc_info.ptk_kck_len = nla_len(ptk_kek);
+ }
+ if (ptk_kek) {
+ event.assoc_info.ptk_kek = nla_data(ptk_kek);
+ event.assoc_info.ptk_kek_len = nla_len(ptk_kek);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+}
+
+
+void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *reason, struct nlattr *addr,
+ struct nlattr *by_ap)
+{
+ union wpa_event_data data;
+ unsigned int locally_generated = by_ap == NULL;
+
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+ /*
+ * Avoid reporting two disassociation events that could
+ * confuse the core code.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+ "event when using userspace SME");
+ return;
+ }
+
+ if (drv->ignore_next_local_disconnect) {
+ drv->ignore_next_local_disconnect = 0;
+ if (locally_generated) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+ "event triggered during reassociation");
+ return;
+ }
+ wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
+ "disconnect but got another disconnect "
+ "event first");
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
+ nl80211_mark_disconnected(drv);
+ os_memset(&data, 0, sizeof(data));
+ if (reason)
+ data.deauth_info.reason_code = nla_get_u16(reason);
+ data.deauth_info.locally_generated = by_ap == NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
+}
+
+
+static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
+{
+ int freq1 = 0;
+
+ switch (convert2width(width)) {
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ return 0;
+ case CHAN_WIDTH_40:
+ freq1 = cf1 - 10;
+ break;
+ case CHAN_WIDTH_80:
+ freq1 = cf1 - 30;
+ break;
+ case CHAN_WIDTH_160:
+ freq1 = cf1 - 70;
+ break;
+ case CHAN_WIDTH_UNKNOWN:
+ case CHAN_WIDTH_80P80:
+ /* FIXME: implement this */
+ return 0;
+ }
+
+ return (abs(freq - freq1) / 20) % 2 == 0 ? 1 : -1;
+}
+
+
+void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *ifindex, struct nlattr *freq,
+ struct nlattr *type, struct nlattr *bw,
+ struct nlattr *cf1, struct nlattr *cf2)
+{
+ struct i802_bss *bss;
+ union wpa_event_data data;
+ int ht_enabled = 1;
+ int chan_offset = 0;
+ int ifidx;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
+
+ if (!freq)
+ return;
+
+ ifidx = nla_get_u32(ifindex);
+ bss = get_bss_ifindex(drv, ifidx);
+ if (bss == NULL) {
+ wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
+ ifidx);
+ return;
+ }
+
+ if (type) {
+ enum nl80211_channel_type ch_type = nla_get_u32(type);
+
+ wpa_printf(MSG_DEBUG, "nl80211: Channel type: %d", ch_type);
+ switch (ch_type) {
+ case NL80211_CHAN_NO_HT:
+ ht_enabled = 0;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_offset = 1;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ chan_offset = -1;
+ break;
+ }
+ } else if (bw && cf1) {
+ /* This can happen for example with VHT80 ch switch */
+ chan_offset = calculate_chan_offset(nla_get_u32(bw),
+ nla_get_u32(freq),
+ nla_get_u32(cf1),
+ cf2 ? nla_get_u32(cf2) : 0);
+ } else {
+ wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail");
+ }
+
+ os_memset(&data, 0, sizeof(data));
+ data.ch_switch.freq = nla_get_u32(freq);
+ data.ch_switch.ht_enabled = ht_enabled;
+ data.ch_switch.ch_offset = chan_offset;
+ if (bw)
+ data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
+ if (cf1)
+ data.ch_switch.cf1 = nla_get_u32(cf1);
+ if (cf2)
+ data.ch_switch.cf2 = nla_get_u32(cf2);
+
+ bss->freq = data.ch_switch.freq;
+
+ wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
+}
+
+
+static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *addr)
+{
+ union wpa_event_data event;
+ enum wpa_event_type ev;
+
+ if (nla_len(addr) != ETH_ALEN)
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
+ cmd, MAC2STR((u8 *) nla_data(addr)));
+
+ if (cmd == NL80211_CMD_AUTHENTICATE)
+ ev = EVENT_AUTH_TIMED_OUT;
+ else if (cmd == NL80211_CMD_ASSOCIATE)
+ ev = EVENT_ASSOC_TIMED_OUT;
+ else
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
+ wpa_supplicant_event(drv->ctx, ev, &event);
+}
+
+
+static void mlme_event_mgmt(struct i802_bss *bss,
+ struct nlattr *freq, struct nlattr *sig,
+ const u8 *frame, size_t len)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 fc, stype;
+ int ssi_signal = 0;
+ int rx_freq = 0;
+
+ wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short management frame");
+ return;
+ }
+
+ fc = le_to_host16(mgmt->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ if (sig)
+ ssi_signal = (s32) nla_get_u32(sig);
+
+ os_memset(&event, 0, sizeof(event));
+ if (freq) {
+ event.rx_mgmt.freq = nla_get_u32(freq);
+ rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq;
+ }
+ wpa_printf(MSG_DEBUG,
+ "nl80211: RX frame sa=" MACSTR
+ " freq=%d ssi_signal=%d stype=%u (%s) len=%u",
+ MAC2STR(mgmt->sa), rx_freq, ssi_signal, stype, fc2str(fc),
+ (unsigned int) len);
+ event.rx_mgmt.frame = frame;
+ event.rx_mgmt.frame_len = len;
+ event.rx_mgmt.ssi_signal = ssi_signal;
+ event.rx_mgmt.drv_priv = bss;
+ wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+}
+
+
+static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *cookie, const u8 *frame,
+ size_t len, struct nlattr *ack)
+{
+ union wpa_event_data event;
+ const struct ieee80211_hdr *hdr;
+ u16 fc;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
+ if (!is_ap_interface(drv->nlmode)) {
+ u64 cookie_val;
+
+ if (!cookie)
+ return;
+
+ cookie_val = nla_get_u64(cookie);
+ wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
+ " cookie=0%llx%s (ack=%d)",
+ (long long unsigned int) cookie_val,
+ cookie_val == drv->send_action_cookie ?
+ " (match)" : " (unknown)", ack != NULL);
+ if (cookie_val != drv->send_action_cookie)
+ return;
+ }
+
+ hdr = (const struct ieee80211_hdr *) frame;
+ fc = le_to_host16(hdr->frame_control);
+
+ os_memset(&event, 0, sizeof(event));
+ event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+ event.tx_status.dst = hdr->addr1;
+ event.tx_status.data = frame;
+ event.tx_status.data_len = len;
+ event.tx_status.ack = ack != NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
+}
+
+
+static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
+ enum wpa_event_type type,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ const u8 *bssid = NULL;
+ u16 reason_code = 0;
+
+ if (type == EVENT_DEAUTH)
+ wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
+ else
+ wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
+
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len >= 24) {
+ bssid = mgmt->bssid;
+
+ if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ !drv->associated &&
+ os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 &&
+ os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 &&
+ os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) {
+ /*
+ * Avoid issues with some roaming cases where
+ * disconnection event for the old AP may show up after
+ * we have started connection with the new AP.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
+ MAC2STR(bssid),
+ MAC2STR(drv->auth_attempt_bssid));
+ return;
+ }
+
+ if (drv->associated != 0 &&
+ os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
+ os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
+ /*
+ * We have presumably received this deauth as a
+ * response to a clear_state_mismatch() outgoing
+ * deauth. Don't let it take us offline!
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
+ "from Unknown BSSID " MACSTR " -- ignoring",
+ MAC2STR(bssid));
+ return;
+ }
+ }
+
+ nl80211_mark_disconnected(drv);
+ os_memset(&event, 0, sizeof(event));
+
+ /* Note: Same offset for Reason Code in both frame subtypes */
+ if (len >= 24 + sizeof(mgmt->u.deauth))
+ reason_code = le_to_host16(mgmt->u.deauth.reason_code);
+
+ if (type == EVENT_DISASSOC) {
+ event.disassoc_info.locally_generated =
+ !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
+ event.disassoc_info.addr = bssid;
+ event.disassoc_info.reason_code = reason_code;
+ if (frame + len > mgmt->u.disassoc.variable) {
+ event.disassoc_info.ie = mgmt->u.disassoc.variable;
+ event.disassoc_info.ie_len = frame + len -
+ mgmt->u.disassoc.variable;
+ }
+ } else {
+ if (drv->ignore_deauth_event) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event due to previous forced deauth-during-auth");
+ drv->ignore_deauth_event = 0;
+ return;
+ }
+ event.deauth_info.locally_generated =
+ !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
+ if (drv->ignore_next_local_deauth) {
+ drv->ignore_next_local_deauth = 0;
+ if (event.deauth_info.locally_generated) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event triggered due to own deauth request");
+ return;
+ }
+ wpa_printf(MSG_WARNING, "nl80211: Was expecting local deauth but got another disconnect event first");
+ }
+ event.deauth_info.addr = bssid;
+ event.deauth_info.reason_code = reason_code;
+ if (frame + len > mgmt->u.deauth.variable) {
+ event.deauth_info.ie = mgmt->u.deauth.variable;
+ event.deauth_info.ie_len = frame + len -
+ mgmt->u.deauth.variable;
+ }
+ }
+
+ wpa_supplicant_event(drv->ctx, type, &event);
+}
+
+
+static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
+ enum wpa_event_type type,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 reason_code = 0;
+
+ if (type == EVENT_UNPROT_DEAUTH)
+ wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
+ else
+ wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
+
+ if (len < 24)
+ return;
+
+ mgmt = (const struct ieee80211_mgmt *) frame;
+
+ os_memset(&event, 0, sizeof(event));
+ /* Note: Same offset for Reason Code in both frame subtypes */
+ if (len >= 24 + sizeof(mgmt->u.deauth))
+ reason_code = le_to_host16(mgmt->u.deauth.reason_code);
+
+ if (type == EVENT_UNPROT_DISASSOC) {
+ event.unprot_disassoc.sa = mgmt->sa;
+ event.unprot_disassoc.da = mgmt->da;
+ event.unprot_disassoc.reason_code = reason_code;
+ } else {
+ event.unprot_deauth.sa = mgmt->sa;
+ event.unprot_deauth.da = mgmt->da;
+ event.unprot_deauth.reason_code = reason_code;
+ }
+
+ wpa_supplicant_event(drv->ctx, type, &event);
+}
+
+
+void mlme_event(struct i802_bss *bss,
+ enum nl80211_commands cmd, struct nlattr *frame,
+ struct nlattr *addr, struct nlattr *timed_out,
+ struct nlattr *freq, struct nlattr *ack,
+ struct nlattr *cookie, struct nlattr *sig)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ const u8 *data;
+ size_t len;
+
+ if (timed_out && addr) {
+ mlme_timeout_event(drv, cmd, addr);
+ return;
+ }
+
+ if (frame == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: MLME event %d (%s) without frame data",
+ cmd, nl80211_command_to_string(cmd));
+ return;
+ }
+
+ data = nla_data(frame);
+ len = nla_len(frame);
+ if (len < 4 + 2 * ETH_ALEN) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
+ MACSTR ") - too short",
+ cmd, nl80211_command_to_string(cmd), bss->ifname,
+ MAC2STR(bss->addr));
+ return;
+ }
+ wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
+ ") A1=" MACSTR " A2=" MACSTR, cmd,
+ nl80211_command_to_string(cmd), bss->ifname,
+ MAC2STR(bss->addr), MAC2STR(data + 4),
+ MAC2STR(data + 4 + ETH_ALEN));
+ if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
+ os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+ os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
+ "for foreign address", bss->ifname);
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
+ nla_data(frame), nla_len(frame));
+
+ switch (cmd) {
+ case NL80211_CMD_AUTHENTICATE:
+ mlme_event_auth(drv, nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_ASSOCIATE:
+ mlme_event_assoc(drv, nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_DEAUTHENTICATE:
+ mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
+ nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_DISASSOCIATE:
+ mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
+ nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_FRAME:
+ mlme_event_mgmt(bss, freq, sig, nla_data(frame),
+ nla_len(frame));
+ break;
+ case NL80211_CMD_FRAME_TX_STATUS:
+ mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
+ nla_len(frame), ack);
+ break;
+ case NL80211_CMD_UNPROT_DEAUTHENTICATE:
+ mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
+ nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_UNPROT_DISASSOCIATE:
+ mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
+ nla_data(frame), nla_len(frame));
+ break;
+ default:
+ break;
+ }
+}
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 47954ba..970ebc7 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -26,6 +26,7 @@ ifdef CONFIG_DRIVER_NL80211
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
DRV_OBJS += ../src/drivers/driver_nl80211.o
DRV_OBJS += ../src/drivers/driver_nl80211_capa.o
+DRV_OBJS += ../src/drivers/driver_nl80211_event.o
DRV_OBJS += ../src/drivers/driver_nl80211_monitor.o
DRV_OBJS += ../src/utils/radiotap.o
NEED_SME=y
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 78ef783..cf9e132 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -22,6 +22,7 @@ DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
DRV_OBJS += src/drivers/driver_nl80211.c
DRV_OBJS += src/drivers/driver_nl80211_android.c
DRV_OBJS += src/drivers/driver_nl80211_capa.c
+DRV_OBJS += src/drivers/driver_nl80211_event.c
DRV_OBJS += src/drivers/driver_nl80211_monitor.c
DRV_OBJS += src/utils/radiotap.c
NEED_SME=y