nl80211: Add QCA vendor specific query of device/driver features
[mech_eap.git] / src / drivers / driver_nl80211_event.c
index ef80eb9..f422174 100644 (file)
@@ -129,6 +129,8 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
        C2S(NL80211_CMD_CHANNEL_SWITCH)
        C2S(NL80211_CMD_VENDOR)
        C2S(NL80211_CMD_SET_QOS_MAP)
+       C2S(NL80211_CMD_ADD_TX_TS)
+       C2S(NL80211_CMD_DEL_TX_TS)
        default:
                return "NL80211_CMD_UNKNOWN";
        }
@@ -280,6 +282,7 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
                               struct nlattr *ptk_kek)
 {
        union wpa_event_data event;
+       u16 status_code;
 
        if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
                /*
@@ -291,21 +294,41 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
                return;
        }
 
-       if (cmd == NL80211_CMD_CONNECT)
-               wpa_printf(MSG_DEBUG, "nl80211: Connect event");
-       else if (cmd == NL80211_CMD_ROAM)
+       status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS;
+
+       if (cmd == NL80211_CMD_CONNECT) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Connect event (status=%u ignore_next_local_disconnect=%d)",
+                          status_code, drv->ignore_next_local_disconnect);
+       } 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 (cmd == NL80211_CMD_CONNECT && status_code != WLAN_STATUS_SUCCESS) {
                if (addr)
                        event.assoc_reject.bssid = nla_data(addr);
+               if (drv->ignore_next_local_disconnect) {
+                       drv->ignore_next_local_disconnect = 0;
+                       if (!event.assoc_reject.bssid ||
+                           (os_memcmp(event.assoc_reject.bssid,
+                                      drv->auth_attempt_bssid,
+                                      ETH_ALEN) != 0)) {
+                               /*
+                                * Ignore the event that came without a BSSID or
+                                * for the old connection since this is likely
+                                * not relevant to the new Connect command.
+                                */
+                               wpa_printf(MSG_DEBUG,
+                                          "nl80211: Ignore connection failure event triggered during reassociation");
+                               return;
+                       }
+               }
                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);
+               event.assoc_reject.status_code = status_code;
                wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
                return;
        }
@@ -538,8 +561,9 @@ static void mlme_event_mgmt(struct i802_bss *bss,
        }
        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),
+                  " 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,
+                  le_to_host16(mgmt->seq_ctrl), stype, fc2str(fc),
                   (unsigned int) len);
        event.rx_mgmt.frame = frame;
        event.rx_mgmt.frame_len = len;
@@ -992,7 +1016,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
                        freqs[num_freqs] = nla_get_u32(nl);
                        res = os_snprintf(pos, end - pos, " %d",
                                          freqs[num_freqs]);
-                       if (res > 0 && end - pos > res)
+                       if (!os_snprintf_error(end - pos, res))
                                pos += res;
                        num_freqs++;
                        if (num_freqs == MAX_REPORT_FREQS - 1)
@@ -1467,6 +1491,33 @@ static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
+                                  const u8 *data, size_t len)
+{
+       struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1];
+       union wpa_event_data event;
+
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: ACS channel selection vendor event received");
+
+       if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX,
+                     (struct nlattr *) data, len, NULL))
+               return;
+
+       if (!tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL] ||
+           !tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL])
+               return;
+
+       os_memset(&event, 0, sizeof(event));
+       event.acs_selected_channels.pri_channel =
+               nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
+       event.acs_selected_channels.sec_channel =
+               nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
+
+       wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event);
+}
+
+
 static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv,
                                      const u8 *data, size_t len)
 {
@@ -1510,6 +1561,9 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
        case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH:
                qca_nl80211_key_mgmt_auth(drv, data, len);
                break;
+       case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
+               qca_nl80211_acs_select_ch(drv, data, len);
+               break;
        default:
                wpa_printf(MSG_DEBUG,
                           "nl80211: Ignore unsupported QCA vendor event %u",
@@ -1636,7 +1690,8 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
        wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
                   cmd, nl80211_command_to_string(cmd), bss->ifname);
 
-       if (cmd == NL80211_CMD_ROAM && drv->roam_auth_vendor_event_avail) {
+       if (cmd == NL80211_CMD_ROAM &&
+           (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
                /*
                 * Device will use roam+auth vendor event to indicate
                 * roaming, so ignore the regular roam event.