#include "common/qca-vendor-attr.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/wpa_common.h"
#include "l2_packet/l2_packet.h"
#include "netlink.h"
#include "linux_defines.h"
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
/*
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);
}
static int i802_set_iface_flags(struct i802_bss *bss, int up);
static int nl80211_set_param(void *priv, const char *param);
+#ifdef CONFIG_MESH
+static int nl80211_put_mesh_config(struct nl_msg *msg,
+ struct wpa_driver_mesh_bss_params *params);
+#endif /* CONFIG_MESH */
+static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason);
/* Converts nl80211_chan_width to a common format */
struct nl80211_wiphy_data *w;
int wiphy_idx, found = 0;
struct i802_bss *tmp_bss;
+ u8 channel;
if (bss->wiphy_data != NULL)
return bss->wiphy_data;
dl_list_init(&w->bsss);
dl_list_init(&w->drvs);
- w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
- if (!w->nl_cb) {
- os_free(w);
- return NULL;
- }
- nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
- nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event,
- w);
+ /* Beacon frames not supported in IEEE 802.11ad */
+ if (ieee80211_freq_to_chan(bss->freq, &channel) !=
+ HOSTAPD_MODE_IEEE80211AD) {
+ w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!w->nl_cb) {
+ os_free(w);
+ return NULL;
+ }
+ nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+ no_seq_check, NULL);
+ nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+ process_beacon_event, w);
+
+ w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
+ "wiphy beacons");
+ if (w->nl_beacons == NULL) {
+ os_free(w);
+ return NULL;
+ }
- w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
- "wiphy beacons");
- if (w->nl_beacons == NULL) {
- os_free(w);
- return NULL;
- }
+ if (nl80211_register_beacons(bss->drv, w)) {
+ nl_destroy_handles(&w->nl_beacons);
+ os_free(w);
+ return NULL;
+ }
- if (nl80211_register_beacons(bss->drv, w)) {
- nl_destroy_handles(&w->nl_beacons);
- os_free(w);
- return NULL;
+ nl80211_register_eloop_read(&w->nl_beacons,
+ nl80211_recv_beacons, w, 0);
}
- nl80211_register_eloop_read(&w->nl_beacons, nl80211_recv_beacons, w);
-
dl_list_add(&nl80211_wiphys, &w->list);
add:
if (!dl_list_empty(&w->bsss))
return;
- nl80211_destroy_eloop_handle(&w->nl_beacons);
+ if (w->nl_beacons)
+ nl80211_destroy_eloop_handle(&w->nl_beacons, 0);
nl_cb_put(w->nl_cb);
dl_list_del(&w->list);
nl80211_check_global(drv->global);
wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
"interface");
- wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL);
+ if (wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL) < 0)
+ return -1;
return 1;
}
static struct wpa_driver_nl80211_data *
-nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
+nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len,
+ int *init_failed)
{
struct wpa_driver_nl80211_data *drv;
+ int res;
+
+ if (init_failed)
+ *init_failed = 0;
dl_list_for_each(drv, &global->interfaces,
struct wpa_driver_nl80211_data, list) {
- if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) ||
- have_ifidx(drv, idx, IFIDX_ANY))
+ res = wpa_driver_nl80211_own_ifindex(drv, idx, buf, len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Found matching own interface, but failed to complete reinitialization");
+ if (init_failed)
+ *init_failed = 1;
+ return drv;
+ }
+ if (res > 0 || have_ifidx(drv, idx, IFIDX_ANY))
return drv;
}
return NULL;
}
+static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
+ int ifindex, int notify)
+{
+ struct i802_bss *bss;
+ u8 addr[ETH_ALEN];
+
+ bss = get_bss_ifindex(drv, ifindex);
+ if (bss &&
+ linux_get_ifhwaddr(drv->global->ioctl_sock,
+ bss->ifname, addr) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: %s: failed to re-read MAC address",
+ bss->ifname);
+ } else if (bss && os_memcmp(addr, bss->addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Own MAC address on ifindex %d (%s) changed from "
+ MACSTR " to " MACSTR,
+ 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);
+ }
+}
+
+
static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
struct ifinfomsg *ifi,
u8 *buf, size_t len)
char namebuf[IFNAMSIZ];
char ifname[IFNAMSIZ + 1];
char extra[100], *pos, *end;
+ int init_failed;
extra[0] = '\0';
pos = extra;
(ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
(ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
- drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+ drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, &init_failed);
if (!drv)
goto event_newlink;
+ if (init_failed)
+ return; /* do not update interface state */
if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
namebuf[0] = '\0';
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)",
* dynamic interfaces
*/
drv = nl80211_find_drv(global, ifi->ifi_index,
- buf, len);
+ buf, len, NULL);
if (!drv)
return;
}
"event since interface %s is marked "
"removed", drv->first_bss->ifname);
} else {
- struct i802_bss *bss;
- u8 addr[ETH_ALEN];
-
/* Re-read MAC address as it may have changed */
- bss = get_bss_ifindex(drv, ifi->ifi_index);
- if (bss &&
- linux_get_ifhwaddr(drv->global->ioctl_sock,
- bss->ifname, addr) < 0) {
- wpa_printf(MSG_DEBUG,
- "nl80211: %s: failed to re-read MAC address",
- bss->ifname);
- } else if (bss &&
- os_memcmp(addr, bss->addr, ETH_ALEN) != 0) {
- wpa_printf(MSG_DEBUG,
- "nl80211: Own MAC address on ifindex %d (%s) changed from "
- MACSTR " to " MACSTR,
- ifi->ifi_index, bss->ifname,
- MAC2STR(bss->addr),
- MAC2STR(addr));
- os_memcpy(bss->addr, addr, ETH_ALEN);
- }
+ nl80211_refresh_mac(drv, ifi->ifi_index, 0);
wpa_printf(MSG_DEBUG, "nl80211: Interface up");
drv->if_disabled = 0;
(ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
(ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
- drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+ drv = nl80211_find_drv(global, ifi->ifi_index, buf, len, NULL);
if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
/* device has been removed from bridge */
}
+struct nl80211_get_assoc_freq_arg {
+ struct wpa_driver_nl80211_data *drv;
+ unsigned int assoc_freq;
+ unsigned int ibss_freq;
+ u8 assoc_bssid[ETH_ALEN];
+ u8 assoc_ssid[SSID_MAX_LEN];
+ u8 assoc_ssid_len;
+};
+
+static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *bss[NL80211_BSS_MAX + 1];
+ static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+ [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_STATUS] = { .type = NLA_U32 },
+ };
+ struct nl80211_get_assoc_freq_arg *ctx = arg;
+ enum nl80211_bss_status status;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[NL80211_ATTR_BSS] ||
+ nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
+ bss_policy) ||
+ !bss[NL80211_BSS_STATUS])
+ return NL_SKIP;
+
+ status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_FREQUENCY]) {
+ ctx->assoc_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
+ ctx->assoc_freq);
+ }
+ if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
+ bss[NL80211_BSS_FREQUENCY]) {
+ ctx->ibss_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
+ ctx->ibss_freq);
+ }
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_BSSID]) {
+ os_memcpy(ctx->assoc_bssid,
+ nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated with "
+ MACSTR, MAC2STR(ctx->assoc_bssid));
+ }
+
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
+ const u8 *ie, *ssid;
+ size_t ie_len;
+
+ ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ ssid = get_ie(ie, ie_len, WLAN_EID_SSID);
+ if (ssid && ssid[1] > 0 && ssid[1] <= SSID_MAX_LEN) {
+ ctx->assoc_ssid_len = ssid[1];
+ os_memcpy(ctx->assoc_ssid, ssid + 2, ssid[1]);
+ }
+ }
+
+ return NL_SKIP;
+}
+
+
+int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid)
+{
+ struct nl_msg *msg;
+ int ret;
+ struct nl80211_get_assoc_freq_arg arg;
+
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
+ os_memset(&arg, 0, sizeof(arg));
+ arg.drv = drv;
+ ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
+ &arg);
+ if (ret == 0) {
+ os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len);
+ return arg.assoc_ssid_len;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ return ret;
+}
+
+
unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
{
struct nl_msg *msg;
int ret;
- struct nl80211_bss_info_arg arg;
+ struct nl80211_get_assoc_freq_arg arg;
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
os_memset(&arg, 0, sizeof(arg));
arg.drv = drv;
- ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+ ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
+ &arg);
if (ret == 0) {
unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
arg.ibss_freq : arg.assoc_freq;
nl80211_register_eloop_read(&global->nl_event,
wpa_driver_nl80211_event_receive,
- global->nl_cb);
+ global->nl_cb, 0);
return 0;
{
nl80211_register_eloop_read(&bss->nl_mgmt,
wpa_driver_nl80211_event_receive,
- bss->nl_cb);
+ bss->nl_cb, 0);
}
}
+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;
wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
"handle %p", bss->nl_mgmt);
- if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
+ if (drv->nlmode == NL80211_IFTYPE_ADHOC ||
+ ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_SME))) {
u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
/* register for any AUTH message */
if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
ret = -1;
#endif /* CONFIG_INTERWORKING */
-#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
+#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
/* GAS Initial Request */
if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
ret = -1;
/* Protected GAS Comeback Response */
if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0d", 2) < 0)
ret = -1;
-#endif /* CONFIG_P2P || CONFIG_INTERWORKING */
+#endif /* CONFIG_P2P || CONFIG_INTERWORKING || CONFIG_DPP */
#ifdef CONFIG_P2P
/* P2P Public Action */
if (nl80211_register_action_frame(bss,
5) < 0)
ret = -1;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_DPP
+ /* DPP Public Action */
+ if (nl80211_register_action_frame(bss,
+ (u8 *) "\x04\x09\x50\x6f\x9a\x1a",
+ 6) < 0)
+ ret = -1;
+#endif /* CONFIG_DPP */
#ifdef CONFIG_IEEE80211W
/* SA Query Response */
if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
/* RRM Measurement Report */
if (nl80211_register_action_frame(bss, (u8 *) "\x05\x01", 2) < 0)
ret = -1;
+ /* RRM Link Measurement Report */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x05\x03", 2) < 0)
+ ret = -1;
/* RRM Neighbor Report Request */
if (nl80211_register_action_frame(bss, (u8 *) "\x05\x04", 2) < 0)
ret = -1;
if (nl80211_register_spurious_class3(bss))
goto out_err;
- if (nl80211_get_wiphy_data_ap(bss) == NULL)
- goto out_err;
-
nl80211_mgmt_handle_register_eloop(bss);
return 0;
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);
}
if (drv->hostapd || bss->static_ap)
nlmode = NL80211_IFTYPE_AP;
- else if (bss->if_dynamic)
+ else if (bss->if_dynamic ||
+ nl80211_get_ifmode(bss) == NL80211_IFTYPE_MESH_POINT)
nlmode = nl80211_get_ifmode(bss);
else
nlmode = NL80211_IFTYPE_STATION;
if (drv->vendor_cmd_test_avail)
qca_vendor_test(drv);
+ nl80211_init_connect_handle(bss);
+
return 0;
}
-static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
+static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss)
{
struct nl_msg *msg;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
drv->ifindex);
+ nl80211_put_wiphy_data_ap(bss);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
return send_and_recv_msgs(drv, msg, NULL, NULL);
}
nl80211_remove_monitor_interface(drv);
if (is_ap_interface(drv->nlmode))
- wpa_driver_nl80211_del_beacon(drv);
+ wpa_driver_nl80211_del_beacon(bss);
if (drv->eapol_sock >= 0) {
eloop_unregister_read_sock(drv->eapol_sock);
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);
switch (alg) {
case WPA_ALG_WEP:
if (key_len == 5)
- return WLAN_CIPHER_SUITE_WEP40;
- return WLAN_CIPHER_SUITE_WEP104;
+ return RSN_CIPHER_SUITE_WEP40;
+ return RSN_CIPHER_SUITE_WEP104;
case WPA_ALG_TKIP:
- return WLAN_CIPHER_SUITE_TKIP;
+ return RSN_CIPHER_SUITE_TKIP;
case WPA_ALG_CCMP:
- return WLAN_CIPHER_SUITE_CCMP;
+ return RSN_CIPHER_SUITE_CCMP;
case WPA_ALG_GCMP:
- return WLAN_CIPHER_SUITE_GCMP;
+ return RSN_CIPHER_SUITE_GCMP;
case WPA_ALG_CCMP_256:
- return WLAN_CIPHER_SUITE_CCMP_256;
+ return RSN_CIPHER_SUITE_CCMP_256;
case WPA_ALG_GCMP_256:
- return WLAN_CIPHER_SUITE_GCMP_256;
+ return RSN_CIPHER_SUITE_GCMP_256;
case WPA_ALG_IGTK:
- return WLAN_CIPHER_SUITE_AES_CMAC;
+ return RSN_CIPHER_SUITE_AES_128_CMAC;
case WPA_ALG_BIP_GMAC_128:
- return WLAN_CIPHER_SUITE_BIP_GMAC_128;
+ return RSN_CIPHER_SUITE_BIP_GMAC_128;
case WPA_ALG_BIP_GMAC_256:
- return WLAN_CIPHER_SUITE_BIP_GMAC_256;
+ return RSN_CIPHER_SUITE_BIP_GMAC_256;
case WPA_ALG_BIP_CMAC_256:
- return WLAN_CIPHER_SUITE_BIP_CMAC_256;
+ return RSN_CIPHER_SUITE_BIP_CMAC_256;
case WPA_ALG_SMS4:
- return WLAN_CIPHER_SUITE_SMS4;
+ return RSN_CIPHER_SUITE_SMS4;
case WPA_ALG_KRK:
- return WLAN_CIPHER_SUITE_KRK;
+ return RSN_CIPHER_SUITE_KRK;
case WPA_ALG_NONE:
case WPA_ALG_PMK:
wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d",
{
switch (cipher) {
case WPA_CIPHER_CCMP_256:
- return WLAN_CIPHER_SUITE_CCMP_256;
+ return RSN_CIPHER_SUITE_CCMP_256;
case WPA_CIPHER_GCMP_256:
- return WLAN_CIPHER_SUITE_GCMP_256;
+ return RSN_CIPHER_SUITE_GCMP_256;
case WPA_CIPHER_CCMP:
- return WLAN_CIPHER_SUITE_CCMP;
+ return RSN_CIPHER_SUITE_CCMP;
case WPA_CIPHER_GCMP:
- return WLAN_CIPHER_SUITE_GCMP;
+ return RSN_CIPHER_SUITE_GCMP;
case WPA_CIPHER_TKIP:
- return WLAN_CIPHER_SUITE_TKIP;
+ return RSN_CIPHER_SUITE_TKIP;
case WPA_CIPHER_WEP104:
- return WLAN_CIPHER_SUITE_WEP104;
+ return RSN_CIPHER_SUITE_WEP104;
case WPA_CIPHER_WEP40:
- return WLAN_CIPHER_SUITE_WEP40;
+ return RSN_CIPHER_SUITE_WEP40;
case WPA_CIPHER_GTK_NOT_USED:
- return WLAN_CIPHER_SUITE_NO_GROUP_ADDR;
+ return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
}
return 0;
int num_suites = 0;
if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP_256)
- suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP_256;
+ suites[num_suites++] = RSN_CIPHER_SUITE_CCMP_256;
if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP_256)
- suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP_256;
+ suites[num_suites++] = RSN_CIPHER_SUITE_GCMP_256;
if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP)
- suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
+ suites[num_suites++] = RSN_CIPHER_SUITE_CCMP;
if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP)
- suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP;
+ suites[num_suites++] = RSN_CIPHER_SUITE_GCMP;
if (num_suites < max_suites && ciphers & WPA_CIPHER_TKIP)
- suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
+ suites[num_suites++] = RSN_CIPHER_SUITE_TKIP;
if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP104)
- suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104;
+ suites[num_suites++] = RSN_CIPHER_SUITE_WEP104;
if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP40)
- suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40;
+ suites[num_suites++] = RSN_CIPHER_SUITE_WEP40;
return num_suites;
}
#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,
}
#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)
params->wep_key[i]) ||
nla_put_u32(msg, NL80211_KEY_CIPHER,
params->wep_key_len[i] == 5 ?
- WLAN_CIPHER_SUITE_WEP40 :
- WLAN_CIPHER_SUITE_WEP104) ||
+ RSN_CIPHER_SUITE_WEP40 :
+ RSN_CIPHER_SUITE_WEP104) ||
nla_put_u8(msg, NL80211_KEY_IDX, i) ||
(i == params->wep_tx_keyidx &&
nla_put_flag(msg, NL80211_KEY_DEFAULT)))
}
+static enum nl80211_auth_type get_nl_auth_type(int wpa_auth_alg)
+{
+ if (wpa_auth_alg & WPA_AUTH_ALG_OPEN)
+ return NL80211_AUTHTYPE_OPEN_SYSTEM;
+ if (wpa_auth_alg & WPA_AUTH_ALG_SHARED)
+ return NL80211_AUTHTYPE_SHARED_KEY;
+ if (wpa_auth_alg & WPA_AUTH_ALG_LEAP)
+ return NL80211_AUTHTYPE_NETWORK_EAP;
+ if (wpa_auth_alg & WPA_AUTH_ALG_FT)
+ return NL80211_AUTHTYPE_FT;
+ if (wpa_auth_alg & WPA_AUTH_ALG_SAE)
+ return NL80211_AUTHTYPE_SAE;
+ if (wpa_auth_alg & WPA_AUTH_ALG_FILS)
+ return NL80211_AUTHTYPE_FILS_SK;
+ if (wpa_auth_alg & WPA_AUTH_ALG_FILS_SK_PFS)
+ return NL80211_AUTHTYPE_FILS_SK_PFS;
+
+ return NL80211_AUTHTYPE_MAX;
+}
+
+
static int wpa_driver_nl80211_authenticate(
struct i802_bss *bss, struct wpa_driver_auth_params *params)
{
if (params->ie &&
nla_put(msg, NL80211_ATTR_IE, params->ie_len, params->ie))
goto fail;
- if (params->sae_data) {
- wpa_hexdump(MSG_DEBUG, " * SAE data", params->sae_data,
- params->sae_data_len);
- if (nla_put(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
- params->sae_data))
+ if (params->auth_data) {
+ wpa_hexdump(MSG_DEBUG, " * auth_data", params->auth_data,
+ params->auth_data_len);
+ if (nla_put(msg, NL80211_ATTR_SAE_DATA, params->auth_data_len,
+ params->auth_data))
goto fail;
}
- if (params->auth_alg & WPA_AUTH_ALG_OPEN)
- type = NL80211_AUTHTYPE_OPEN_SYSTEM;
- else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
- type = NL80211_AUTHTYPE_SHARED_KEY;
- else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
- type = NL80211_AUTHTYPE_NETWORK_EAP;
- else if (params->auth_alg & WPA_AUTH_ALG_FT)
- type = NL80211_AUTHTYPE_FT;
- else if (params->auth_alg & WPA_AUTH_ALG_SAE)
- type = NL80211_AUTHTYPE_SAE;
- else
- goto fail;
+ type = get_nl_auth_type(params->auth_alg);
wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
- if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+ if (type == NL80211_AUTHTYPE_MAX ||
+ nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
goto fail;
if (params->local_state_change) {
wpa_printf(MSG_DEBUG, " * Local state change only");
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
}
+#ifdef CONFIG_MESH
+static int nl80211_set_mesh_config(void *priv,
+ struct wpa_driver_mesh_bss_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MESH_CONFIG);
+ if (!msg)
+ return -1;
+
+ ret = nl80211_put_mesh_config(msg, params);
+ if (ret < 0) {
+ nlmsg_free(msg);
+ return ret;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Mesh config set failed: %d (%s)",
+ ret, strerror(-ret));
+ return ret;
+ }
+ return 0;
+}
+#endif /* CONFIG_MESH */
+
+
+static int nl80211_put_beacon_rate(struct nl_msg *msg, const u64 flags,
+ struct wpa_driver_ap_params *params)
+{
+ struct nlattr *bands, *band;
+ struct nl80211_txrate_vht vht_rate;
+
+ if (!params->freq ||
+ (params->beacon_rate == 0 &&
+ params->rate_type == BEACON_RATE_LEGACY))
+ return 0;
+
+ bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
+ if (!bands)
+ return -1;
+
+ switch (params->freq->mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ case HOSTAPD_MODE_IEEE80211G:
+ band = nla_nest_start(msg, NL80211_BAND_2GHZ);
+ break;
+ case HOSTAPD_MODE_IEEE80211A:
+ band = nla_nest_start(msg, NL80211_BAND_5GHZ);
+ break;
+ case HOSTAPD_MODE_IEEE80211AD:
+ band = nla_nest_start(msg, NL80211_BAND_60GHZ);
+ break;
+ default:
+ return 0;
+ }
+
+ if (!band)
+ return -1;
+
+ os_memset(&vht_rate, 0, sizeof(vht_rate));
+
+ switch (params->rate_type) {
+ case BEACON_RATE_LEGACY:
+ if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (legacy)");
+ return -1;
+ }
+
+ if (nla_put_u8(msg, NL80211_TXRATE_LEGACY,
+ (u8) params->beacon_rate / 5) ||
+ nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
+ (params->freq->vht_enabled &&
+ nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate)))
+ return -1;
+
+ wpa_printf(MSG_DEBUG, " * beacon_rate = legacy:%u (* 100 kbps)",
+ params->beacon_rate);
+ break;
+ case BEACON_RATE_HT:
+ if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_HT)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (HT)");
+ return -1;
+ }
+ if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
+ nla_put_u8(msg, NL80211_TXRATE_HT, params->beacon_rate) ||
+ (params->freq->vht_enabled &&
+ nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate)))
+ return -1;
+ wpa_printf(MSG_DEBUG, " * beacon_rate = HT-MCS %u",
+ params->beacon_rate);
+ break;
+ case BEACON_RATE_VHT:
+ if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_VHT)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (VHT)");
+ return -1;
+ }
+ vht_rate.mcs[0] = BIT(params->beacon_rate);
+ if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL))
+ return -1;
+ if (nla_put(msg, NL80211_TXRATE_HT, 0, NULL))
+ return -1;
+ if (nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate))
+ return -1;
+ wpa_printf(MSG_DEBUG, " * beacon_rate = VHT-MCS %u",
+ params->beacon_rate);
+ break;
+ }
+
+ nla_nest_end(msg, band);
+ nla_nest_end(msg, bands);
+
+ return 0;
+}
+
+
+static int nl80211_set_multicast_to_unicast(struct i802_bss *bss,
+ int multicast_to_unicast)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_MULTICAST_TO_UNICAST);
+ if (!msg ||
+ (multicast_to_unicast &&
+ nla_put_flag(msg, NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED))) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to build NL80211_CMD_SET_MULTICAST_TO_UNICAST msg for %s",
+ bss->ifname);
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+
+ switch (ret) {
+ case 0:
+ wpa_printf(MSG_DEBUG,
+ "nl80211: multicast to unicast %s on interface %s",
+ multicast_to_unicast ? "enabled" : "disabled",
+ bss->ifname);
+ break;
+ case -EOPNOTSUPP:
+ if (!multicast_to_unicast)
+ break;
+ wpa_printf(MSG_INFO,
+ "nl80211: multicast to unicast not supported on interface %s",
+ bss->ifname);
+ break;
+ default:
+ wpa_printf(MSG_ERROR,
+ "nl80211: %s multicast to unicast failed with %d (%s) on interface %s",
+ multicast_to_unicast ? "enabling" : "disabling",
+ ret, strerror(-ret), bss->ifname);
+ break;
+ }
+
+ return ret;
+}
+
+
static int wpa_driver_nl80211_set_ap(void *priv,
struct wpa_driver_ap_params *params)
{
int smps_mode;
u32 suites[10], suite;
u32 ver;
+#ifdef CONFIG_MESH
+ struct wpa_driver_mesh_bss_params mesh_params;
+#endif /* CONFIG_MESH */
beacon_set = params->reenable ? 0 : bss->beacon_set;
beacon_set);
if (beacon_set)
cmd = NL80211_CMD_SET_BEACON;
+ else if (!drv->device_ap_sme && !drv->use_monitor &&
+ !nl80211_get_wiphy_data_ap(bss))
+ return -ENOBUFS;
wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
params->head, params->head_len);
params->tail, params->tail_len);
wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex);
wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
+ wpa_printf(MSG_DEBUG, "nl80211: beacon_rate=%u", params->beacon_rate);
+ wpa_printf(MSG_DEBUG, "nl80211: rate_type=%d", params->rate_type);
wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
params->ssid, params->ssid_len);
nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
params->tail) ||
nl80211_put_beacon_int(msg, params->beacon_int) ||
+ nl80211_put_beacon_rate(msg, drv->capa.flags, params) ||
nl80211_put_dtim_period(msg, params->dtim_period) ||
nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
goto fail;
params->key_mgmt_suites);
num_suites = 0;
if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
- suites[num_suites++] = WLAN_AKM_SUITE_8021X;
+ suites[num_suites++] = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
- suites[num_suites++] = WLAN_AKM_SUITE_PSK;
+ suites[num_suites++] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
if (num_suites &&
nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
suites))
goto fail;
if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
- params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) &&
- nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
+ (!params->pairwise_ciphers ||
+ params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
+ (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
goto fail;
wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
smps_mode = NL80211_SMPS_OFF;
break;
}
- if (nla_put_u32(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
+ if (nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
goto fail;
}
nl80211_set_bss(bss, params->cts_protect, params->preamble,
params->short_slot_time, params->ht_opmode,
params->isolate, params->basic_rates);
+ nl80211_set_multicast_to_unicast(bss,
+ params->multicast_to_unicast);
if (beacon_set && params->freq &&
params->freq->bandwidth != bss->bandwidth) {
wpa_printf(MSG_DEBUG,
"nl80211: Frequency set succeeded for ht2040 coex");
bss->bandwidth = params->freq->bandwidth;
}
- } else if (!beacon_set) {
+ } else if (!beacon_set && params->freq) {
/*
* cfg80211 updates the driver on frequence change in AP
* mode only at the point when beaconing is started, so
bss->bandwidth = params->freq->bandwidth;
}
}
+
+#ifdef CONFIG_MESH
+ if (is_mesh_interface(drv->nlmode) && params->ht_opmode != -1) {
+ os_memset(&mesh_params, 0, sizeof(mesh_params));
+ mesh_params.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
+ mesh_params.ht_opmode = params->ht_opmode;
+ ret = nl80211_set_mesh_config(priv, &mesh_params);
+ if (ret < 0)
+ return ret;
+ }
+#endif /* CONFIG_MESH */
+
return ret;
fail:
nlmsg_free(msg);
wpa_printf(MSG_DEBUG, " * channel_type=%d", ct);
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
return -ENOBUFS;
+ } else {
+ wpa_printf(MSG_DEBUG, " * channel_type=%d",
+ NL80211_CHAN_NO_HT);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ NL80211_CHAN_NO_HT))
+ return -ENOBUFS;
}
return 0;
}
else
nl80211_mgmt_unsubscribe(bss, "AP teardown");
+ nl80211_put_wiphy_data_ap(bss);
bss->beacon_set = 0;
}
}
-static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
- struct wpa_driver_associate_params *params,
- struct nl_msg *msg)
+static int nl80211_put_fils_connect_params(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params,
+ struct nl_msg *msg)
{
- if (params->bssid) {
- wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
- MAC2STR(params->bssid));
- if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+ if (params->fils_erp_username_len) {
+ wpa_hexdump_ascii(MSG_DEBUG, " * FILS ERP EMSKname/username",
+ params->fils_erp_username,
+ params->fils_erp_username_len);
+ if (nla_put(msg, NL80211_ATTR_FILS_ERP_USERNAME,
+ params->fils_erp_username_len,
+ params->fils_erp_username))
return -1;
}
- if (params->bssid_hint) {
- wpa_printf(MSG_DEBUG, " * bssid_hint=" MACSTR,
- MAC2STR(params->bssid_hint));
+ if (params->fils_erp_realm_len) {
+ wpa_hexdump_ascii(MSG_DEBUG, " * FILS ERP Realm",
+ params->fils_erp_realm,
+ params->fils_erp_realm_len);
+ if (nla_put(msg, NL80211_ATTR_FILS_ERP_REALM,
+ params->fils_erp_realm_len, params->fils_erp_realm))
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, " * FILS ERP next seq %u",
+ params->fils_erp_next_seq_num);
+ if (nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
+ params->fils_erp_next_seq_num))
+ return -1;
+
+ if (params->fils_erp_rrk_len) {
+ wpa_printf(MSG_DEBUG, " * FILS ERP rRK (len=%lu)",
+ (unsigned long) params->fils_erp_rrk_len);
+ if (nla_put(msg, NL80211_ATTR_FILS_ERP_RRK,
+ params->fils_erp_rrk_len, params->fils_erp_rrk))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params,
+ struct nl_msg *msg)
+{
+ if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
+ return -1;
+
+ if (params->bssid) {
+ wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
+ MAC2STR(params->bssid));
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+ return -1;
+ }
+
+ if (params->bssid_hint) {
+ wpa_printf(MSG_DEBUG, " * bssid_hint=" MACSTR,
+ MAC2STR(params->bssid_hint));
if (nla_put(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
params->bssid_hint))
return -1;
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
- params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
- int mgmt = WLAN_AKM_SUITE_PSK;
+ params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA256 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA384 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA256 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_OWE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_DPP) {
+ int mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
switch (params->key_mgmt_suite) {
case WPA_KEY_MGMT_CCKM:
- mgmt = WLAN_AKM_SUITE_CCKM;
+ mgmt = RSN_AUTH_KEY_MGMT_CCKM;
break;
case WPA_KEY_MGMT_IEEE8021X:
- mgmt = WLAN_AKM_SUITE_8021X;
+ mgmt = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
break;
case WPA_KEY_MGMT_FT_IEEE8021X:
- mgmt = WLAN_AKM_SUITE_FT_8021X;
+ mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X;
break;
case WPA_KEY_MGMT_FT_PSK:
- mgmt = WLAN_AKM_SUITE_FT_PSK;
+ mgmt = RSN_AUTH_KEY_MGMT_FT_PSK;
break;
case WPA_KEY_MGMT_IEEE8021X_SHA256:
- mgmt = WLAN_AKM_SUITE_8021X_SHA256;
+ mgmt = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
break;
case WPA_KEY_MGMT_PSK_SHA256:
- mgmt = WLAN_AKM_SUITE_PSK_SHA256;
+ mgmt = RSN_AUTH_KEY_MGMT_PSK_SHA256;
break;
case WPA_KEY_MGMT_OSEN:
- mgmt = WLAN_AKM_SUITE_OSEN;
+ mgmt = RSN_AUTH_KEY_MGMT_OSEN;
break;
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
- mgmt = WLAN_AKM_SUITE_8021X_SUITE_B;
+ mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
break;
case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
- mgmt = WLAN_AKM_SUITE_8021X_SUITE_B_192;
+ mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
+ break;
+ case WPA_KEY_MGMT_FILS_SHA256:
+ mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA256;
+ break;
+ case WPA_KEY_MGMT_FILS_SHA384:
+ mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA384;
+ break;
+ case WPA_KEY_MGMT_FT_FILS_SHA256:
+ mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
+ break;
+ case WPA_KEY_MGMT_FT_FILS_SHA384:
+ mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
+ break;
+ case WPA_KEY_MGMT_OWE:
+ mgmt = RSN_AUTH_KEY_MGMT_OWE;
+ break;
+ case WPA_KEY_MGMT_DPP:
+ mgmt = RSN_AUTH_KEY_MGMT_DPP;
break;
case WPA_KEY_MGMT_PSK:
default:
- mgmt = WLAN_AKM_SUITE_PSK;
+ mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
break;
}
wpa_printf(MSG_DEBUG, " * akm=0x%x", mgmt);
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;
- if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
- nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
+ if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+ (params->pairwise_suite == WPA_CIPHER_NONE ||
+ params->pairwise_suite == WPA_CIPHER_WEP104 ||
+ params->pairwise_suite == WPA_CIPHER_WEP40) &&
+ (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
return -1;
if (params->rrm_used) {
drv->connect_reassoc = 1;
}
+ if ((params->auth_alg & WPA_AUTH_ALG_FILS) &&
+ nl80211_put_fils_connect_params(drv, params, msg) != 0)
+ return -1;
+
+ if ((params->auth_alg & WPA_AUTH_ALG_SAE) &&
+ (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
+ nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
+ return -1;
+
return 0;
}
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;
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++;
algs++;
if (params->auth_alg & WPA_AUTH_ALG_LEAP)
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");
goto skip_auth_type;
}
- if (params->auth_alg & WPA_AUTH_ALG_OPEN)
- type = NL80211_AUTHTYPE_OPEN_SYSTEM;
- else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
- type = NL80211_AUTHTYPE_SHARED_KEY;
- else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
- type = NL80211_AUTHTYPE_NETWORK_EAP;
- else if (params->auth_alg & WPA_AUTH_ALG_FT)
- type = NL80211_AUTHTYPE_FT;
- else
- goto fail;
-
+ type = get_nl_auth_type(params->auth_alg);
wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
- if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+ if (type == NL80211_AUTHTYPE_MAX ||
+ nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
goto fail;
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 "
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;
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
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;
}
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);
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);
+ if (nla_put(msg, NL80211_ATTR_FILS_KEK, params->fils_kek_len,
+ params->fils_kek))
+ goto fail;
+ }
+ if (params->fils_nonces) {
+ wpa_hexdump(MSG_DEBUG, " * FILS nonces (for AAD)",
+ params->fils_nonces,
+ params->fils_nonces_len);
+ if (nla_put(msg, NL80211_ATTR_FILS_NONCES,
+ params->fils_nonces_len, params->fils_nonces))
+ goto fail;
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
[NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
[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] = {
+ [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
+ [NL80211_RATE_INFO_BITRATE32] = { .type = NLA_U32 },
+ [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
+ [NL80211_RATE_INFO_VHT_MCS] = { .type = NLA_U8 },
+ [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
+ [NL80211_RATE_INFO_VHT_NSS] = { .type = NLA_U8 },
};
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
if (stats[NL80211_STA_INFO_TX_FAILED])
data->tx_retry_failed =
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,
+ stats[NL80211_STA_INFO_TX_BITRATE],
+ rate_policy) == 0) {
+ if (rate[NL80211_RATE_INFO_BITRATE32])
+ data->current_tx_rate =
+ nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
+ else if (rate[NL80211_RATE_INFO_BITRATE])
+ data->current_tx_rate =
+ nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
+
+ if (rate[NL80211_RATE_INFO_MCS]) {
+ data->tx_mcs = nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
+ data->flags |= STA_DRV_DATA_TX_MCS;
+ }
+ if (rate[NL80211_RATE_INFO_VHT_MCS]) {
+ data->tx_vhtmcs =
+ nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
+ data->flags |= STA_DRV_DATA_TX_VHT_MCS;
+ }
+ if (rate[NL80211_RATE_INFO_SHORT_GI])
+ data->flags |= STA_DRV_DATA_TX_SHORT_GI;
+ if (rate[NL80211_RATE_INFO_VHT_NSS]) {
+ data->tx_vht_nss =
+ nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
+ data->flags |= STA_DRV_DATA_TX_VHT_NSS;
+ }
+ }
+
+ if (stats[NL80211_STA_INFO_RX_BITRATE] &&
+ nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
+ stats[NL80211_STA_INFO_RX_BITRATE],
+ rate_policy) == 0) {
+ if (rate[NL80211_RATE_INFO_BITRATE32])
+ data->current_rx_rate =
+ nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
+ else if (rate[NL80211_RATE_INFO_BITRATE])
+ data->current_rx_rate =
+ nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
+
+ if (rate[NL80211_RATE_INFO_MCS]) {
+ data->rx_mcs =
+ nla_get_u8(rate[NL80211_RATE_INFO_MCS]);
+ data->flags |= STA_DRV_DATA_RX_MCS;
+ }
+ if (rate[NL80211_RATE_INFO_VHT_MCS]) {
+ data->rx_vhtmcs =
+ nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
+ data->flags |= STA_DRV_DATA_RX_VHT_MCS;
+ }
+ if (rate[NL80211_RATE_INFO_SHORT_GI])
+ data->flags |= STA_DRV_DATA_RX_SHORT_GI;
+ if (rate[NL80211_RATE_INFO_VHT_NSS]) {
+ data->rx_vht_nss =
+ nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
+ data->flags |= STA_DRV_DATA_RX_VHT_NSS;
+ }
+ }
return NL_SKIP;
}
{
struct nl_msg *msg;
- os_memset(data, 0, sizeof(*data));
-
if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_STATION)) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
nlmsg_free(msg);
struct hostap_sta_driver_data data;
int ret;
+ os_memset(&data, 0, sizeof(data));
data.inactive_msec = (unsigned long) -1;
ret = i802_read_sta_data(priv, &data, addr);
if (ret == -ENOENT)
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt mgmt;
+ u8 channel;
+
+ if (ieee80211_freq_to_chan(bss->freq, &channel) ==
+ HOSTAPD_MODE_IEEE80211AD) {
+ /* Deauthentication is not used in DMG/IEEE 802.11ad;
+ * disassociate the STA instead. */
+ return i802_sta_disassoc(priv, own_addr, addr, reason);
+ }
if (is_mesh_interface(drv->nlmode))
return -1;
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)
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 "
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;
}
}
wpa_printf(MSG_ERROR, "nl80211: Failed to "
"remove interface %s from bridge "
"%s: %s",
- ifname, brname, strerror(errno));
+ ifname, in_br, strerror(errno));
return -1;
}
}
wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
nl80211_teardown_ap(bss);
if (!bss->added_if && !drv->first_bss->next)
- wpa_driver_nl80211_del_beacon(drv);
+ wpa_driver_nl80211_del_beacon(bss);
nl80211_destroy_bss(bss);
if (!bss->added_if)
i802_set_iface_flags(bss, 0);
os_memcpy(hdr->addr2, src, ETH_ALEN);
os_memcpy(hdr->addr3, bssid, ETH_ALEN);
+ if (os_memcmp(bss->addr, src, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Use random TA " MACSTR,
+ MAC2STR(src));
+ os_memcpy(bss->rand_addr, src, ETH_ALEN);
+ } else {
+ os_memset(bss->rand_addr, 0, ETH_ALEN);
+ }
+
if (is_ap_interface(drv->nlmode) &&
(!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
(int) freq == bss->freq || drv->device_ap_sme ||
} 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;
}
nl80211_register_eloop_read(&bss->nl_preq,
wpa_driver_nl80211_event_receive,
- bss->nl_cb);
+ bss->nl_cb, 0);
return 0;
struct wpa_driver_nl80211_data *drv = bss->drv;
if (!is_ap_interface(drv->nlmode))
return -1;
- wpa_driver_nl80211_del_beacon(drv);
+ wpa_driver_nl80211_del_beacon(bss);
bss->beacon_set = 0;
/*
struct wpa_driver_nl80211_data *drv = bss->drv;
if (!is_ap_interface(drv->nlmode))
return -1;
- wpa_driver_nl80211_del_beacon(drv);
+ wpa_driver_nl80211_del_beacon(bss);
bss->beacon_set = 0;
return 0;
}
static int nl80211_set_param(void *priv, const char *param)
{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
if (param == NULL)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
#ifdef CONFIG_P2P
if (os_strstr(param, "use_p2p_group_interface=1")) {
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
-
wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
"interface");
drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
}
#endif /* CONFIG_P2P */
- if (os_strstr(param, "use_monitor=1")) {
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (os_strstr(param, "use_monitor=1"))
drv->use_monitor = 1;
- }
if (os_strstr(param, "force_connect_cmd=1")) {
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME;
drv->force_connect_cmd = 1;
}
+ if (os_strstr(param, "force_bss_selection=1"))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
+
if (os_strstr(param, "no_offchannel_tx=1")) {
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
drv->test_use_roc_tx = 1;
}
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);
}
-static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
- const u8 *pmkid)
+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)) ||
- (pmkid && nla_put(msg, NL80211_ATTR_PMKID, 16, pmkid)) ||
- (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))) {
+ (params->pmkid &&
+ nla_put(msg, NL80211_ATTR_PMKID, 16, params->pmkid)) ||
+ (params->bssid &&
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid)) ||
+ (params->ssid_len &&
+ nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
+ (params->fils_cache_id &&
+ nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2,
+ params->fils_cache_id)) ||
+ (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;
}
}
-static int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
+static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params)
{
struct i802_bss *bss = priv;
- wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid));
- return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid);
+ int ret;
+
+ if (params->bssid)
+ wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR,
+ MAC2STR(params->bssid));
+ else if (params->fils_cache_id && params->ssid_len) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add PMKSA for cache id %02x%02x SSID %s",
+ params->fils_cache_id[0], params->fils_cache_id[1],
+ wpa_ssid_txt(params->ssid, params->ssid_len));
+ }
+
+ 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, const u8 *bssid, const u8 *pmkid)
+static int nl80211_remove_pmkid(void *priv, struct wpa_pmkid_params *params)
{
struct i802_bss *bss = priv;
- wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
- MAC2STR(bssid));
- return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid);
+ int ret;
+
+ if (params->bssid)
+ wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
+ MAC2STR(params->bssid));
+ else if (params->fils_cache_id && params->ssid_len) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Delete PMKSA for cache id %02x%02x SSID %s",
+ params->fils_cache_id[0], params->fils_cache_id[1],
+ wpa_ssid_txt(params->ssid, params->ssid_len));
+ }
+
+ 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;
}
static int nl80211_flush_pmkid(void *priv)
{
struct i802_bss *bss = priv;
+ struct nl_msg *msg;
+
wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
- return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_FLUSH_PMKSA);
+ if (!msg)
+ return -ENOBUFS;
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
}
if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
!(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
nla_put(msg, NL80211_REKEY_DATA_KEK, kek_len, kek) ||
- nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck) ||
+ (kck_len && nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck)) ||
nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
replay_ctr)) {
nl80211_nlmsg_clear(msg);
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,
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;
}
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
enum nl80211_tdls_operation nl80211_oper;
+ int res;
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
return -EOPNOTSUPP;
return -ENOBUFS;
}
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ res = send_and_recv_msgs(drv, msg, NULL, NULL);
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS_OPER: oper=%d mac=" MACSTR
+ " --> res=%d (%s)", nl80211_oper, MAC2STR(peer), res,
+ strerror(-res));
+ return res;
}
const u8 *addr)
{
struct i802_bss *bss = priv;
+
+ os_memset(data, 0, sizeof(*data));
return i802_read_sta_data(bss, data, addr);
}
return send_and_recv_msgs(drv, msg, NULL, NULL);
}
+
+
+static int nl80211_disable_fils(void *priv, int disable)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Disable FILS=%d", disable);
+
+ if (!drv->set_wifi_conf_vendor_cmd_avail)
+ return -1;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS,
+ disable)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+ nla_nest_end(msg, params);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
+
+/* Reserved QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID value for wpa_supplicant */
+#define WPA_SUPPLICANT_CLIENT_ID 1
+
+static int nl80211_set_bssid_blacklist(void *priv, unsigned int num_bssid,
+ const u8 *bssid)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params, *nlbssids, *attr;
+ unsigned int i;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set blacklist BSSID (num=%u)",
+ num_bssid);
+
+ if (!drv->roam_vendor_cmd_avail)
+ return -1;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_ROAM) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID,
+ WPA_SUPPLICANT_CLIENT_ID) ||
+ nla_put_u32(msg,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID,
+ num_bssid))
+ goto fail;
+
+ nlbssids = nla_nest_start(
+ msg, QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS);
+ if (!nlbssids)
+ goto fail;
+
+ for (i = 0; i < num_bssid; i++) {
+ attr = nla_nest_start(msg, i);
+ if (!attr)
+ goto fail;
+ if (nla_put(msg,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID,
+ ETH_ALEN, &bssid[i * ETH_ALEN]))
+ goto fail;
+ wpa_printf(MSG_DEBUG, "nl80211: BSSID[%u]: " MACSTR, i,
+ MAC2STR(&bssid[i * ETH_ALEN]));
+ nla_nest_end(msg, attr);
+ }
+ nla_nest_end(msg, nlbssids);
+ nla_nest_end(msg, params);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
+static int nl80211_put_mesh_config(struct nl_msg *msg,
+ struct wpa_driver_mesh_bss_params *params)
+{
+ struct nlattr *container;
+
+ container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
+ if (!container)
+ return -1;
+
+ if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
+ nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+ params->auto_plinks)) ||
+ ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) &&
+ nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
+ params->max_peer_links)) ||
+ ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD) &&
+ nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
+ params->rssi_threshold)))
+ return -1;
+
+ /*
+ * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
+ * the timer could disconnect stations even in that case.
+ */
+ if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT) &&
+ nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
+ params->peer_link_timeout)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
+ return -1;
+ }
+
+ if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE) &&
+ nla_put_u16(msg, NL80211_MESHCONF_HT_OPMODE, params->ht_opmode)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set HT_OP_MODE");
+ return -1;
+ }
+
+ nla_nest_end(msg, container);
+
+ return 0;
+}
+
+
static int nl80211_join_mesh(struct i802_bss *bss,
struct wpa_driver_mesh_join_params *params)
{
goto fail;
nla_nest_end(msg, container);
- container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
- if (!container)
- goto fail;
-
- if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
- nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0))
- goto fail;
- if (nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
- params->max_peer_links))
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT;
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS;
+ if (nl80211_put_mesh_config(msg, ¶ms->conf) < 0)
goto fail;
- /*
- * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
- * the timer could disconnect stations even in that case.
- */
- if (nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
- params->conf.peer_link_timeout)) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
- goto fail;
- }
-
- nla_nest_end(msg, container);
-
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
return send_and_recv_msgs(drv, msg, NULL, NULL);
}
+
+static int nl80211_set_tdls_mode(void *priv, int tdls_external_control)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params;
+ int ret;
+ u32 tdls_mode;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set TDKS mode: tdls_external_control=%d",
+ tdls_external_control);
+
+ if (tdls_external_control == 1)
+ tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT |
+ QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL;
+ else
+ tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS))
+ goto fail;
+
+ params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!params)
+ goto fail;
+
+ if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE,
+ tdls_mode))
+ goto fail;
+
+ nla_nest_end(msg, params);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Set TDLS mode failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+ return 0;
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+#ifdef CONFIG_MBO
+
+static enum mbo_transition_reject_reason
+nl80211_mbo_reject_reason_mapping(enum qca_wlan_btm_candidate_status status)
+{
+ switch (status) {
+ case QCA_STATUS_REJECT_EXCESSIVE_FRAME_LOSS_EXPECTED:
+ return MBO_TRANSITION_REJECT_REASON_FRAME_LOSS;
+ case QCA_STATUS_REJECT_EXCESSIVE_DELAY_EXPECTED:
+ return MBO_TRANSITION_REJECT_REASON_DELAY;
+ case QCA_STATUS_REJECT_INSUFFICIENT_QOS_CAPACITY:
+ return MBO_TRANSITION_REJECT_REASON_QOS_CAPACITY;
+ case QCA_STATUS_REJECT_LOW_RSSI:
+ return MBO_TRANSITION_REJECT_REASON_RSSI;
+ case QCA_STATUS_REJECT_HIGH_INTERFERENCE:
+ return MBO_TRANSITION_REJECT_REASON_INTERFERENCE;
+ case QCA_STATUS_REJECT_UNKNOWN:
+ default:
+ return MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
+ }
+}
+
+
+static void nl80211_parse_btm_candidate_info(struct candidate_list *candidate,
+ struct nlattr *tb[], int num)
+{
+ enum qca_wlan_btm_candidate_status status;
+ char buf[50];
+
+ os_memcpy(candidate->bssid,
+ nla_data(tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]),
+ ETH_ALEN);
+
+ status = nla_get_u32(
+ tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS]);
+ candidate->is_accept = status == QCA_STATUS_ACCEPT;
+ candidate->reject_reason = nl80211_mbo_reject_reason_mapping(status);
+
+ if (candidate->is_accept)
+ os_snprintf(buf, sizeof(buf), "Accepted");
+ else
+ os_snprintf(buf, sizeof(buf),
+ "Rejected, Reject_reason: %d",
+ candidate->reject_reason);
+ wpa_printf(MSG_DEBUG, "nl80211: BSSID[%d]: " MACSTR " %s",
+ num, MAC2STR(candidate->bssid), buf);
+}
+
+
+static int
+nl80211_get_bss_transition_status_handler(struct nl_msg *msg, void *arg)
+{
+ struct wpa_bss_candidate_info *info = arg;
+ struct candidate_list *candidate = info->candidates;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1];
+ static struct nla_policy policy[
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1] = {
+ [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] = {
+ .minlen = ETH_ALEN
+ },
+ [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS] = {
+ .type = NLA_U32,
+ },
+ };
+ struct nlattr *attr;
+ int rem;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ u8 num;
+
+ num = info->num; /* number of candidates sent to driver */
+ info->num = 0;
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb_msg[NL80211_ATTR_VENDOR_DATA] ||
+ nla_parse_nested(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+ tb_msg[NL80211_ATTR_VENDOR_DATA], NULL) ||
+ !tb_vendor[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO])
+ return NL_SKIP;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: WNM Candidate list received from driver");
+ nla_for_each_nested(attr,
+ tb_vendor[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO],
+ rem) {
+ if (info->num >= num ||
+ nla_parse_nested(
+ tb, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX,
+ attr, policy) ||
+ !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS])
+ break;
+
+ nl80211_parse_btm_candidate_info(candidate, tb, info->num);
+
+ candidate++;
+ info->num++;
+ }
+
+ return NL_SKIP;
+}
+
+
+static struct wpa_bss_candidate_info *
+nl80211_get_bss_transition_status(void *priv, struct wpa_bss_trans_info *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *attr, *attr1, *attr2;
+ struct wpa_bss_candidate_info *info;
+ u8 i;
+ int ret;
+ u8 *pos;
+
+ if (!drv->fetch_bss_trans_status)
+ return NULL;
+
+ info = os_zalloc(sizeof(*info));
+ if (!info)
+ return NULL;
+ /* Allocate memory for number of candidates sent to driver */
+ info->candidates = os_calloc(params->n_candidates,
+ sizeof(*info->candidates));
+ if (!info->candidates) {
+ os_free(info);
+ return NULL;
+ }
+
+ /* Copy the number of candidates being sent to driver. This is used in
+ * nl80211_get_bss_transition_status_handler() to limit the number of
+ * candidates that can be populated in info->candidates and will be
+ * later overwritten with the actual number of candidates received from
+ * the driver.
+ */
+ info->num = params->n_candidates;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS))
+ goto fail;
+
+ attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!attr)
+ goto fail;
+
+ if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON,
+ params->mbo_transition_reason))
+ goto fail;
+
+ attr1 = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO);
+ if (!attr1)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: WNM Candidate list info sending to driver: mbo_transition_reason: %d n_candidates: %d",
+ params->mbo_transition_reason, params->n_candidates);
+ pos = params->bssid;
+ for (i = 0; i < params->n_candidates; i++) {
+ wpa_printf(MSG_DEBUG, "nl80211: BSSID[%d]: " MACSTR, i,
+ MAC2STR(pos));
+ attr2 = nla_nest_start(msg, i);
+ if (!attr2 ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID,
+ ETH_ALEN, pos))
+ goto fail;
+ pos += ETH_ALEN;
+ nla_nest_end(msg, attr2);
+ }
+
+ nla_nest_end(msg, attr1);
+ nla_nest_end(msg, attr);
+
+ ret = send_and_recv_msgs(drv, msg,
+ nl80211_get_bss_transition_status_handler,
+ info);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: WNM Get BSS transition status failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+ return info;
+
+fail:
+ nlmsg_free(msg);
+ os_free(info->candidates);
+ os_free(info);
+ return NULL;
+}
+
+
+/**
+ * nl80211_ignore_assoc_disallow - Configure driver to ignore assoc_disallow
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @ignore_assoc_disallow: 0 to not ignore, 1 to ignore
+ * Returns: 0 on success, -1 on failure
+ */
+static int nl80211_ignore_assoc_disallow(void *priv, int ignore_disallow)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *attr;
+ int ret = -1;
+
+ if (!drv->set_wifi_conf_vendor_cmd_avail)
+ return -1;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION))
+ goto fail;
+
+ attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!attr)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set ignore_assoc_disallow %d",
+ ignore_disallow);
+ if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED,
+ ignore_disallow))
+ goto fail;
+
+ nla_nest_end(msg, attr);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Set ignore_assoc_disallow failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+#endif /* CONFIG_MBO */
+
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
+static int nl80211_update_connection_params(
+ void *priv, struct wpa_driver_associate_params *params,
+ enum wpa_drv_update_connect_params_mask mask)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = -1;
+ enum nl80211_auth_type type;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_CONNECT_PARAMS);
+ if (!msg)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Update connection params (ifindex=%d)",
+ drv->ifindex);
+
+ if ((mask & WPA_DRV_UPDATE_ASSOC_IES) && params->wpa_ie) {
+ if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+ params->wpa_ie))
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie,
+ params->wpa_ie_len);
+ }
+
+ if (mask & WPA_DRV_UPDATE_AUTH_TYPE) {
+ type = get_nl_auth_type(params->auth_alg);
+ if (type == NL80211_AUTHTYPE_MAX ||
+ nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+ goto fail;
+ wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
+ }
+
+ if ((mask & WPA_DRV_UPDATE_FILS_ERP_INFO) &&
+ nl80211_put_fils_connect_params(drv, params, msg))
+ goto fail;
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret)
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: Update connect params command failed: ret=%d (%s)",
+ ret, strerror(-ret));
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int nl80211_send_external_auth_status(void *priv,
+ struct external_auth *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg = NULL;
+ int ret = -1;
+
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: External auth status: %u", params->status);
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_EXTERNAL_AUTH);
+ if (!msg ||
+ nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, params->status) ||
+ nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
+ params->ssid) ||
+ nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid))
+ goto fail;
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: External Auth status update failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
.get_ifindex = nl80211_get_ifindex,
#ifdef CONFIG_DRIVER_NL80211_QCA
.roaming = nl80211_roaming,
+ .disable_fils = nl80211_disable_fils,
.do_acs = wpa_driver_do_acs,
.set_band = nl80211_set_band,
.get_pref_freq_list = nl80211_get_pref_freq_list,
.set_prob_oper_freq = nl80211_set_prob_oper_freq,
.p2p_lo_start = nl80211_p2p_lo_start,
.p2p_lo_stop = nl80211_p2p_lo_stop,
+ .set_default_scan_ies = nl80211_set_default_scan_ies,
+ .set_tdls_mode = nl80211_set_tdls_mode,
+#ifdef CONFIG_MBO
+ .get_bss_transition_status = nl80211_get_bss_transition_status,
+ .ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
+#endif /* CONFIG_MBO */
+ .set_bssid_blacklist = nl80211_set_bssid_blacklist,
#endif /* CONFIG_DRIVER_NL80211_QCA */
.configure_data_frame_filters = nl80211_configure_data_frame_filters,
.get_ext_capab = nl80211_get_ext_capab,
+ .update_connect_params = nl80211_update_connection_params,
+ .send_external_auth_status = nl80211_send_external_auth_status,
};