]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/drivers/driver_nl80211.c
hostapd: Add ctrl iface indications for WDS STA interface
[thirdparty/hostap.git] / src / drivers / driver_nl80211.c
index d6bf12160b679153aa9f68b50854c7a67092c6d8..0c5c6bb6f7981098a518de044382f49b12c40d8b 100644 (file)
@@ -130,7 +130,7 @@ static void nl_destroy_handles(struct nl_handle **handle)
 
 static void nl80211_register_eloop_read(struct nl_handle **handle,
                                        eloop_sock_handler handler,
-                                       void *eloop_data)
+                                       void *eloop_data, int persist)
 {
 #ifdef CONFIG_LIBNL20
        /*
@@ -151,13 +151,17 @@ static void nl80211_register_eloop_read(struct nl_handle **handle,
        nl_socket_set_nonblocking(*handle);
        eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
                                 eloop_data, *handle);
-       *handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+       if (!persist)
+               *handle = (void *) (((intptr_t) *handle) ^
+                                   ELOOP_SOCKET_INVALID);
 }
 
 
-static void nl80211_destroy_eloop_handle(struct nl_handle **handle)
+static void nl80211_destroy_eloop_handle(struct nl_handle **handle, int persist)
 {
-       *handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+       if (!persist)
+               *handle = (void *) (((intptr_t) *handle) ^
+                                   ELOOP_SOCKET_INVALID);
        eloop_unregister_read_sock(nl_socket_get_fd(*handle));
        nl_destroy_handles(handle);
 }
@@ -723,7 +727,7 @@ nl80211_get_wiphy_data_ap(struct i802_bss *bss)
                }
 
                nl80211_register_eloop_read(&w->nl_beacons,
-                                           nl80211_recv_beacons, w);
+                                           nl80211_recv_beacons, w, 0);
        }
 
        dl_list_add(&nl80211_wiphys, &w->list);
@@ -772,7 +776,7 @@ static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
                return;
 
        if (w->nl_beacons)
-               nl80211_destroy_eloop_handle(&w->nl_beacons);
+               nl80211_destroy_eloop_handle(&w->nl_beacons, 0);
 
        nl_cb_put(w->nl_cb);
        dl_list_del(&w->list);
@@ -947,7 +951,7 @@ nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len,
 
 
 static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
-                               int ifindex)
+                               int ifindex, int notify)
 {
        struct i802_bss *bss;
        u8 addr[ETH_ALEN];
@@ -966,6 +970,9 @@ static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
                           ifindex, bss->ifname,
                           MAC2STR(bss->addr), MAC2STR(addr));
                os_memcpy(bss->addr, addr, ETH_ALEN);
+               if (notify)
+                       wpa_supplicant_event(drv->ctx,
+                                            EVENT_INTERFACE_MAC_CHANGED, NULL);
        }
 }
 
@@ -1037,11 +1044,11 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                namebuf[0] = '\0';
                if (if_indextoname(ifi->ifi_index, namebuf) &&
                    linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) {
-                       /* Re-read MAC address as it may have changed */
-                       nl80211_refresh_mac(drv, ifi->ifi_index);
                        wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
                                   "event since interface %s is up", namebuf);
                        drv->ignore_if_down_event = 0;
+                       /* Re-read MAC address as it may have changed */
+                       nl80211_refresh_mac(drv, ifi->ifi_index, 1);
                        return;
                }
                wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
@@ -1087,7 +1094,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                                   "removed", drv->first_bss->ifname);
                } else {
                        /* Re-read MAC address as it may have changed */
-                       nl80211_refresh_mac(drv, ifi->ifi_index);
+                       nl80211_refresh_mac(drv, ifi->ifi_index, 0);
 
                        wpa_printf(MSG_DEBUG, "nl80211: Interface up");
                        drv->if_disabled = 0;
@@ -1631,7 +1638,7 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
 
        nl80211_register_eloop_read(&global->nl_event,
                                    wpa_driver_nl80211_event_receive,
-                                   global->nl_cb);
+                                   global->nl_cb, 0);
 
        return 0;
 
@@ -1997,7 +2004,7 @@ static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss)
 {
        nl80211_register_eloop_read(&bss->nl_mgmt,
                                    wpa_driver_nl80211_event_receive,
-                                   bss->nl_cb);
+                                   bss->nl_cb, 0);
 }
 
 
@@ -2010,6 +2017,25 @@ static int nl80211_register_action_frame(struct i802_bss *bss,
 }
 
 
+static int nl80211_init_connect_handle(struct i802_bss *bss)
+{
+       if (bss->nl_connect) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Connect handle already created (nl_connect=%p)",
+                          bss->nl_connect);
+               return -1;
+       }
+
+       bss->nl_connect = nl_create_handle(bss->nl_cb, "connect");
+       if (!bss->nl_connect)
+               return -1;
+       nl80211_register_eloop_read(&bss->nl_connect,
+                                   wpa_driver_nl80211_event_receive,
+                                   bss->nl_cb, 1);
+       return 0;
+}
+
+
 static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -2313,7 +2339,7 @@ static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
                return;
        wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
                   "(%s)", bss->nl_mgmt, reason);
-       nl80211_destroy_eloop_handle(&bss->nl_mgmt);
+       nl80211_destroy_eloop_handle(&bss->nl_mgmt, 0);
 
        nl80211_put_wiphy_data_ap(bss);
 }
@@ -2529,6 +2555,8 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
        if (drv->vendor_cmd_test_avail)
                qca_vendor_test(drv);
 
+       nl80211_init_connect_handle(bss);
+
        return 0;
 }
 
@@ -2642,6 +2670,9 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
                nl80211_del_p2pdev(bss);
        }
 
+       if (bss->nl_connect)
+               nl80211_destroy_eloop_handle(&bss->nl_connect, 1);
+
        nl80211_destroy_bss(drv->first_bss);
 
        os_free(drv->filter_ssids);
@@ -2784,6 +2815,44 @@ static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
 
+static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
+                          const u8 *key, size_t key_len,
+                          const u8 *addr)
+{
+       struct nl_msg *msg = NULL;
+       int ret;
+
+       /*
+        * If the authenticator address is not set, assume it is
+        * the current BSSID.
+        */
+       if (!addr && drv->associated)
+               addr = drv->bssid;
+       else if (!addr)
+               return -1;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Set PMK to the driver for " MACSTR,
+                  MAC2STR(addr));
+       wpa_hexdump_key(MSG_DEBUG, "nl80211: PMK", key, key_len);
+       msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_PMK);
+       if (!msg ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+           nla_put(msg, NL80211_ATTR_PMK, key_len, key)) {
+               nl80211_nlmsg_clear(msg);
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
+
+       ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)",
+                          ret, strerror(-ret));
+       }
+
+       return ret;
+}
+
+
 static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
                                      enum wpa_alg alg, const u8 *addr,
                                      int key_idx, int set_tx,
@@ -2822,6 +2891,10 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
        }
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
+       if (alg == WPA_ALG_PMK &&
+           (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+               return nl80211_set_pmk(drv, key, key_len, addr);
+
        if (alg == WPA_ALG_NONE) {
                msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
                if (!msg)
@@ -3275,11 +3348,11 @@ retry:
        msg = NULL;
        if (ret) {
                wpa_dbg(drv->ctx, MSG_DEBUG,
-                       "nl80211: MLME command failed (auth): ret=%d (%s)",
-                       ret, strerror(-ret));
+                       "nl80211: MLME command failed (auth): count=%d ret=%d (%s)",
+                       count, ret, strerror(-ret));
                count++;
-               if (ret == -EALREADY && count == 1 && params->bssid &&
-                   !params->local_state_change) {
+               if ((ret == -EALREADY || ret == -EEXIST) && count == 1 &&
+                   params->bssid && !params->local_state_change) {
                        /*
                         * mac80211 does not currently accept new
                         * authentication if we are already authenticated. As a
@@ -5319,6 +5392,14 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
                        return -1;
        }
 
+       /* Add PSK in case of 4-way handshake offload */
+       if (params->psk &&
+           (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) {
+               wpa_hexdump_key(MSG_DEBUG, "  * PSK", params->psk, 32);
+               if (nla_put(msg, NL80211_ATTR_PMK, 32, params->psk))
+                       return -1;
+       }
+
        if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
                return -1;
 
@@ -5330,10 +5411,6 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
             nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
                return -1;
 
-       if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
-           nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
-               return -1;
-
        if (params->rrm_used) {
                u32 drv_rrm_flags = drv->capa.rrm_flags;
                if ((!((drv_rrm_flags &
@@ -5381,7 +5458,8 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
 
 static int wpa_driver_nl80211_try_connect(
        struct wpa_driver_nl80211_data *drv,
-       struct wpa_driver_associate_params *params)
+       struct wpa_driver_associate_params *params,
+       struct nl_handle *nl_connect)
 {
        struct nl_msg *msg;
        enum nl80211_auth_type type;
@@ -5409,6 +5487,15 @@ static int wpa_driver_nl80211_try_connect(
        if (ret)
                goto fail;
 
+       if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
+           nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
+               goto fail;
+
+       if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_OPTIONAL &&
+           (drv->capa.flags & WPA_DRIVER_FLAGS_MFP_OPTIONAL) &&
+           nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_OPTIONAL))
+               goto fail;
+
        algs = 0;
        if (params->auth_alg & WPA_AUTH_ALG_OPEN)
                algs++;
@@ -5418,6 +5505,8 @@ static int wpa_driver_nl80211_try_connect(
                algs++;
        if (params->auth_alg & WPA_AUTH_ALG_FILS)
                algs++;
+       if (params->auth_alg & WPA_AUTH_ALG_FT)
+               algs++;
        if (algs > 1) {
                wpa_printf(MSG_DEBUG, "  * Leave out Auth Type for automatic "
                           "selection");
@@ -5435,7 +5524,11 @@ skip_auth_type:
        if (ret)
                goto fail;
 
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (nl_connect)
+               ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL);
+       else
+               ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+
        msg = NULL;
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
@@ -5454,7 +5547,8 @@ fail:
 
 static int wpa_driver_nl80211_connect(
        struct wpa_driver_nl80211_data *drv,
-       struct wpa_driver_associate_params *params)
+       struct wpa_driver_associate_params *params,
+       struct nl_handle *nl_connect)
 {
        int ret;
 
@@ -5464,7 +5558,7 @@ static int wpa_driver_nl80211_connect(
        else
                os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
 
-       ret = wpa_driver_nl80211_try_connect(drv, params);
+       ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
        if (ret == -EALREADY) {
                /*
                 * cfg80211 does not currently accept new connections if
@@ -5477,7 +5571,7 @@ static int wpa_driver_nl80211_connect(
                if (wpa_driver_nl80211_disconnect(
                            drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
                        return -1;
-               ret = wpa_driver_nl80211_try_connect(drv, params);
+               ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
        }
        return ret;
 }
@@ -5502,10 +5596,13 @@ static int wpa_driver_nl80211_associate(
        if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
                enum nl80211_iftype nlmode = params->p2p ?
                        NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+               struct nl_handle *nl_connect = NULL;
 
                if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
                        return -1;
-               return wpa_driver_nl80211_connect(drv, params);
+               if (params->auth_alg & WPA_AUTH_ALG_SAE)
+                       nl_connect = bss->nl_connect;
+               return wpa_driver_nl80211_connect(drv, params, nl_connect);
        }
 
        nl80211_mark_disconnected(drv);
@@ -5520,6 +5617,10 @@ static int wpa_driver_nl80211_associate(
        if (ret)
                goto fail;
 
+       if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
+           nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
+               goto fail;
+
        if (params->fils_kek) {
                wpa_printf(MSG_DEBUG, "  * FILS KEK (len=%u)",
                           (unsigned int) params->fils_kek_len);
@@ -5953,6 +6054,7 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
                [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
                [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
                [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
+               [NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 },
        };
        struct nlattr *rate[NL80211_RATE_INFO_MAX + 1];
        static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -6015,6 +6117,11 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
                        nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
        if (stats[NL80211_STA_INFO_SIGNAL])
                data->signal = nla_get_u8(stats[NL80211_STA_INFO_SIGNAL]);
+       if (stats[NL80211_STA_INFO_ACK_SIGNAL]) {
+               data->last_ack_rssi =
+                       nla_get_u8(stats[NL80211_STA_INFO_ACK_SIGNAL]);
+               data->flags |= STA_DRV_DATA_LAST_ACK_RSSI;
+       }
 
        if (stats[NL80211_STA_INFO_TX_BITRATE] &&
            nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
@@ -6404,6 +6511,7 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        char name[IFNAMSIZ + 1];
+       union wpa_event_data event;
 
        os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
        if (ifname_wds)
@@ -6422,6 +6530,14 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
                            linux_br_add_if(drv->global->ioctl_sock,
                                            bridge_ifname, name) < 0)
                                return -1;
+
+                       os_memset(&event, 0, sizeof(event));
+                       event.wds_sta_interface.sta_addr = addr;
+                       event.wds_sta_interface.ifname = name;
+                       event.wds_sta_interface.istatus = INTERFACE_ADDED;
+                       wpa_supplicant_event(drv->ctx,
+                                            EVENT_WDS_STA_INTERFACE_STATUS,
+                                            &event);
                }
                if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
                        wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
@@ -6435,6 +6551,12 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
 
                i802_set_sta_vlan(priv, addr, bss->ifname, 0);
                nl80211_remove_iface(drv, if_nametoindex(name));
+               os_memset(&event, 0, sizeof(event));
+               event.wds_sta_interface.sta_addr = addr;
+               event.wds_sta_interface.ifname = name;
+               event.wds_sta_interface.istatus = INTERFACE_REMOVED;
+               wpa_supplicant_event(drv->ctx, EVENT_WDS_STA_INTERFACE_STATUS,
+                                    &event);
                return 0;
        }
 }
@@ -7215,7 +7337,7 @@ static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
                } else if (bss->nl_preq) {
                        wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
                                   "reporting nl_preq=%p", bss->nl_preq);
-                       nl80211_destroy_eloop_handle(&bss->nl_preq);
+                       nl80211_destroy_eloop_handle(&bss->nl_preq, 0);
                }
                return 0;
        }
@@ -7240,7 +7362,7 @@ static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
 
        nl80211_register_eloop_read(&bss->nl_preq,
                                    wpa_driver_nl80211_event_receive,
-                                   bss->nl_cb);
+                                   bss->nl_cb, 0);
 
        return 0;
 
@@ -7555,7 +7677,7 @@ static void nl80211_global_deinit(void *priv)
        nl_destroy_handles(&global->nl);
 
        if (global->nl_event)
-               nl80211_destroy_eloop_handle(&global->nl_event);
+               nl80211_destroy_eloop_handle(&global->nl_event, 0);
 
        nl_cb_put(global->nl_cb);
 
@@ -7578,6 +7700,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd,
                         struct wpa_pmkid_params *params)
 {
        struct nl_msg *msg;
+       const size_t PMK_MAX_LEN = 48; /* current cfg80211 limit */
 
        if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
            (params->pmkid &&
@@ -7589,7 +7712,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd,
            (params->fils_cache_id &&
             nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2,
                     params->fils_cache_id)) ||
-           (params->pmk_len &&
+           (params->pmk_len && params->pmk_len <= PMK_MAX_LEN &&
             nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
                nlmsg_free(msg);
                return -ENOBUFS;
@@ -7602,6 +7725,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd,
 static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params)
 {
        struct i802_bss *bss = priv;
+       int ret;
 
        if (params->bssid)
                wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR,
@@ -7613,13 +7737,21 @@ static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params)
                           wpa_ssid_txt(params->ssid, params->ssid_len));
        }
 
-       return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params);
+       ret = nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params);
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: NL80211_CMD_SET_PMKSA failed: %d (%s)",
+                          ret, strerror(-ret));
+       }
+
+       return ret;
 }
 
 
 static int nl80211_remove_pmkid(void *priv, struct wpa_pmkid_params *params)
 {
        struct i802_bss *bss = priv;
+       int ret;
 
        if (params->bssid)
                wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
@@ -7631,7 +7763,14 @@ static int nl80211_remove_pmkid(void *priv, struct wpa_pmkid_params *params)
                           wpa_ssid_txt(params->ssid, params->ssid_len));
        }
 
-       return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params);
+       ret = nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params);
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: NL80211_CMD_DEL_PMKSA failed: %d (%s)",
+                          ret, strerror(-ret));
+       }
+
+       return ret;
 }
 
 
@@ -7927,6 +8066,7 @@ static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
 static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
 {
        struct nl_msg *msg;
+       int ret;
 
        if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
            nla_put_u32(msg, NL80211_ATTR_PS_STATE,
@@ -7934,7 +8074,15 @@ static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
                nlmsg_free(msg);
                return -ENOBUFS;
        }
-       return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+
+       ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Setting PS state %s failed: %d (%s)",
+                          enabled ? "enabled" : "disabled",
+                          ret, strerror(-ret));
+       }
+       return ret;
 }