nl80211: Move event handling into a separate file
authorJouni Malinen <j@w1.fi>
Sun, 26 Oct 2014 14:13:27 +0000 (16:13 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 26 Oct 2014 15:54:56 +0000 (17:54 +0200)
Signed-off-by: Jouni Malinen <j@w1.fi>
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211.h
src/drivers/driver_nl80211_event.c [new file with mode: 0644]
src/drivers/drivers.mak
src/drivers/drivers.mk

index 5e3453f..9e0b714 100644 (file)
@@ -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[])
 {
index fdc145b..750a83b 100644 (file)
@@ -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 (file)
index 0000000..1259441
--- /dev/null
@@ -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;
+       }
+}
index 47954ba..970ebc7 100644 (file)
@@ -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
index 78ef783..cf9e132 100644 (file)
@@ -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