P2P: Allow P2P listen being offloaded to the driver/firmware
[mech_eap.git] / src / drivers / driver_nl80211_event.c
index d1c6cd5..762e3ac 100644 (file)
@@ -265,10 +265,12 @@ 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 *timed_out,
                               struct nlattr *authorized,
                               struct nlattr *key_replay_ctr,
                               struct nlattr *ptk_kck,
-                              struct nlattr *ptk_kek)
+                              struct nlattr *ptk_kek,
+                              struct nlattr *subnet_status)
 {
        union wpa_event_data event;
        const u8 *ssid;
@@ -284,6 +286,8 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
                return;
        }
 
+       drv->connect_reassoc = 0;
+
        status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS;
 
        if (cmd == NL80211_CMD_CONNECT) {
@@ -319,6 +323,7 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
                        event.assoc_reject.resp_ies_len = nla_len(resp_ie);
                }
                event.assoc_reject.status_code = status_code;
+               event.assoc_reject.timed_out = timed_out != NULL;
                wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
                return;
        }
@@ -334,9 +339,9 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
                event.assoc_info.req_ies_len = nla_len(req_ie);
 
                if (cmd == NL80211_CMD_ROAM) {
-                       ssid = nl80211_get_ie(event.assoc_info.req_ies,
-                                             event.assoc_info.req_ies_len,
-                                             WLAN_EID_SSID);
+                       ssid = get_ie(event.assoc_info.req_ies,
+                                     event.assoc_info.req_ies_len,
+                                     WLAN_EID_SSID);
                        if (ssid && ssid[1] > 0 && ssid[1] <= 32) {
                                drv->ssid_len = ssid[1];
                                os_memcpy(drv->ssid, ssid + 2, ssid[1]);
@@ -367,6 +372,17 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
                event.assoc_info.ptk_kek_len = nla_len(ptk_kek);
        }
 
+       if (subnet_status) {
+               /*
+                * At least for now, this is only available from
+                * QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS and that
+                * attribute has the same values 0, 1, 2 as are used in the
+                * variable here, so no mapping between different values are
+                * needed.
+                */
+               event.assoc_info.subnet_status = nla_get_u8(subnet_status);
+       }
+
        wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
 }
 
@@ -560,9 +576,10 @@ static void mlme_event_mgmt(struct i802_bss *bss,
                rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq;
        }
        wpa_printf(MSG_DEBUG,
-                  "nl80211: RX frame sa=" MACSTR
+                  "nl80211: RX frame da=" MACSTR " sa=" MACSTR " bssid=" MACSTR
                   " freq=%d ssi_signal=%d fc=0x%x seq_ctrl=0x%x stype=%u (%s) len=%u",
-                  MAC2STR(mgmt->sa), rx_freq, ssi_signal, fc,
+                  MAC2STR(mgmt->da), MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid),
+                  rx_freq, ssi_signal, fc,
                   le_to_host16(mgmt->seq_ctrl), stype, fc2str(fc),
                   (unsigned int) len);
        event.rx_mgmt.frame = frame;
@@ -639,10 +656,39 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
                         * 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.
+                        * In case of locally generated event clear
+                        * ignore_next_local_deauth as well, to avoid next local
+                        * deauth event be wrongly ignored.
+                        */
+                       if (!os_memcmp(mgmt->sa, drv->first_bss->addr,
+                                      ETH_ALEN)) {
+                               wpa_printf(MSG_DEBUG,
+                                          "nl80211: Received a locally generated deauth event. Clear ignore_next_local_deauth flag");
+                               drv->ignore_next_local_deauth = 0;
+                       } else {
+                               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->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+                   drv->connect_reassoc && drv->associated &&
+                   os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0 &&
+                   os_memcmp(bssid, drv->auth_attempt_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));
+                        wpa_printf(MSG_DEBUG,
+                                   "nl80211: Ignore deauth/disassoc event from old AP "
+                                   MACSTR
+                                   " when already connecting with " MACSTR,
+                                   MAC2STR(bssid),
+                                   MAC2STR(drv->auth_attempt_bssid));
                        return;
                }
 
@@ -679,13 +725,15 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
                                mgmt->u.disassoc.variable;
                }
        } else {
+               event.deauth_info.locally_generated =
+                       !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
                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;
+                       if (event.deauth_info.locally_generated)
+                               drv->ignore_next_local_deauth = 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) {
@@ -868,6 +916,7 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
                                 struct nlattr *tb[])
 {
        unsigned int freq;
+       union wpa_event_data event;
 
        if (tb[NL80211_ATTR_MAC] == NULL) {
                wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
@@ -887,7 +936,10 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
                drv->first_bss->freq = freq;
        }
 
-       wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+       os_memset(&event, 0, sizeof(event));
+       event.assoc_info.freq = freq;
+
+       wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
 }
 
 
@@ -1006,7 +1058,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
                }
        }
        if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
-               char msg[200], *pos, *end;
+               char msg[300], *pos, *end;
                int res;
 
                pos = msg;
@@ -1111,7 +1163,7 @@ static void nl80211_new_peer_candidate(struct wpa_driver_nl80211_data *drv,
                return;
 
        addr = nla_data(tb[NL80211_ATTR_MAC]);
-       wpa_printf(MSG_DEBUG, "nl80211: New peer candidate" MACSTR,
+       wpa_printf(MSG_DEBUG, "nl80211: New peer candidate " MACSTR,
                   MAC2STR(addr));
 
        os_memset(&data, 0, sizeof(data));
@@ -1156,6 +1208,7 @@ static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
 
 
 static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
+                                     struct i802_bss *bss,
                                      struct nlattr **tb)
 {
        u8 *addr;
@@ -1168,7 +1221,7 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
                   MAC2STR(addr));
 
        if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
-               drv_event_disassoc(drv->ctx, addr);
+               drv_event_disassoc(bss->ctx, addr);
                return;
        }
 
@@ -1177,7 +1230,7 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
 
        os_memset(&data, 0, sizeof(data));
        os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
-       wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
+       wpa_supplicant_event(bss->ctx, EVENT_IBSS_PEER_LOST, &data);
 }
 
 
@@ -1597,10 +1650,12 @@ static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv,
                           tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID],
                           tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE],
                           tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE],
+                          NULL,
                           tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED],
                           tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR],
                           tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK],
-                          tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK]);
+                          tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK],
+                          tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS]);
 }
 
 
@@ -1753,7 +1808,7 @@ static void send_vendor_scan_event(struct wpa_driver_nl80211_data *drv,
        }
 
        if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) {
-               char msg[200], *pos, *end;
+               char msg[300], *pos, *end;
                int res;
 
                pos = msg;
@@ -1821,6 +1876,31 @@ static void qca_nl80211_scan_done_event(struct wpa_driver_nl80211_data *drv,
                               external_scan);
 }
 
+
+static void qca_nl80211_p2p_lo_stop_event(struct wpa_driver_nl80211_data *drv,
+                                         u8 *data, size_t len)
+{
+       struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1];
+       union wpa_event_data event;
+
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: P2P listen offload stop vendor event received");
+
+       if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX,
+                     (struct nlattr *) data, len, NULL) ||
+           !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON])
+               return;
+
+       os_memset(&event, 0, sizeof(event));
+       event.p2p_lo_stop.reason_code =
+               nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON]);
+
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: P2P Listen offload stop reason: %d",
+                  event.p2p_lo_stop.reason_code);
+       wpa_supplicant_event(drv->ctx, EVENT_P2P_LO_STOP, &event);
+}
+
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
 
@@ -1854,6 +1934,9 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
        case QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE:
                qca_nl80211_scan_done_event(drv, data, len);
                break;
+       case QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP:
+               qca_nl80211_p2p_lo_stop_event(drv, data, len);
+               break;
 #endif /* CONFIG_DRIVER_NL80211_QCA */
        default:
                wpa_printf(MSG_DEBUG,
@@ -2084,7 +2167,8 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
                                   tb[NL80211_ATTR_MAC],
                                   tb[NL80211_ATTR_REQ_IE],
                                   tb[NL80211_ATTR_RESP_IE],
-                                  NULL, NULL, NULL, NULL);
+                                  tb[NL80211_ATTR_TIMED_OUT],
+                                  NULL, NULL, NULL, NULL, NULL);
                break;
        case NL80211_CMD_CH_SWITCH_NOTIFY:
                mlme_event_ch_switch(drv,
@@ -2129,7 +2213,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
                nl80211_new_station_event(drv, bss, tb);
                break;
        case NL80211_CMD_DEL_STATION:
-               nl80211_del_station_event(drv, tb);
+               nl80211_del_station_event(drv, bss, tb);
                break;
        case NL80211_CMD_SET_REKEY_OFFLOAD:
                nl80211_rekey_offload_event(drv, tb);