#include "ap/wps_hostapd.h"
#include "ap/ctrl_iface_ap.h"
#include "ap/ap_drv_ops.h"
+#include "ap/wpa_auth.h"
#include "wps/wps_defs.h"
#include "wps/wps.h"
#include "config_file.h"
/* send disassociation frame after time-out */
if (disassoc_timer) {
struct sta_info *sta;
+ int timeout, beacon_int;
+
+ /*
+ * Prevent STA from reconnecting using cached PMKSA to force
+ * full authentication with the authentication server (which may
+ * decide to reject the connection),
+ */
+ wpa_auth_pmksa_remove(hapd->wpa_auth, addr);
sta = ap_get_sta(hapd, addr);
if (sta == NULL) {
return -1;
}
+ beacon_int = hapd->iconf->beacon_int;
+ if (beacon_int < 1)
+ beacon_int = 100; /* best guess */
+ /* Calculate timeout in ms based on beacon_int in TU */
+ timeout = disassoc_timer * beacon_int * 128 / 125;
+ wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
+ " set to %d ms", MAC2STR(addr), timeout);
+
sta->timeout_next = STA_DISASSOC_FROM_CLI;
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
- eloop_register_timeout(disassoc_timer / 1000,
- disassoc_timer % 1000 * 1000,
+ eloop_register_timeout(timeout / 1000,
+ timeout % 1000 * 1000,
ap_handle_timer, hapd, sta);
}
}
-static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
- struct rsn_pmksa_cache_entry *entry)
+void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry)
{
struct rsn_pmksa_cache_entry *pos, *prev;
const u8 *aa, const u8 *pmkid);
void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol);
+void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry);
#endif /* PMKSA_CACHE_H */
}
+void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr)
+{
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ if (wpa_auth == NULL || wpa_auth->pmksa == NULL)
+ return;
+ pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
+ if (pmksa) {
+ wpa_printf(MSG_DEBUG, "WPA: Remove PMKSA cache entry for "
+ MACSTR " based on request", MAC2STR(sta_addr));
+ pmksa_cache_free_entry(wpa_auth->pmksa, pmksa);
+ }
+}
+
+
static struct wpa_group *
wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
{
const u8 *pmk, size_t len, const u8 *sta_addr,
int session_timeout,
struct eapol_state_machine *eapol);
+void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr);
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int ack);
#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
+/* IEEE Std 802.11-2012 - Table 8-253 */
+enum bss_trans_mgmt_status_code {
+ WNM_BSS_TM_ACCEPT = 0,
+ WNM_BSS_TM_REJECT_UNSPECIFIED = 1,
+ WNM_BSS_TM_REJECT_INSUFFICIENT_BEACON = 2,
+ WNM_BSS_TM_REJECT_INSUFFICIENT_CAPABITY = 3,
+ WNM_BSS_TM_REJECT_UNDESIRED = 4,
+ WNM_BSS_TM_REJECT_DELAY_REQUEST = 5,
+ WNM_BSS_TM_REJECT_STA_CANDIDATE_LIST_PROVIDED = 6,
+ WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES = 7,
+ WNM_BSS_TM_REJECT_LEAVING_ESS = 8
+};
+
#define WNM_NEIGHBOR_TSF 1
#define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING 2
#define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE 3
#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
#define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
+/* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */
+#define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT "
+
#define INTERWORKING_AP "INTERWORKING-AP "
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
return "STATION";
case NL80211_IFTYPE_AP:
return "AP";
+ case NL80211_IFTYPE_AP_VLAN:
+ return "AP_VLAN";
+ case NL80211_IFTYPE_WDS:
+ return "WDS";
case NL80211_IFTYPE_MONITOR:
return "MONITOR";
+ case NL80211_IFTYPE_MESH_POINT:
+ return "MESH_POINT";
case NL80211_IFTYPE_P2P_CLIENT:
return "P2P_CLIENT";
case NL80211_IFTYPE_P2P_GO:
* @persistent_group: Whether this is an invitation to reinvoke a
* persistent group (instead of invitation to join an active
* group)
+ * @channels: Available operating channels for the group
* Returns: Status code (P2P_SC_*)
*
* This optional callback can be used to implement persistent reconnect
u8 (*invitation_process)(void *ctx, const u8 *sa, const u8 *bssid,
const u8 *go_dev_addr, const u8 *ssid,
size_t ssid_len, int *go, u8 *group_bssid,
- int *force_freq, int persistent_group);
+ int *force_freq, int persistent_group,
+ const struct p2p_channels *channels);
/**
* invitation_received - Callback on Invitation Request RX
goto fail;
}
+ p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+ &intersection);
+
if (p2p->cfg->invitation_process) {
status = p2p->cfg->invitation_process(
p2p->cfg->cb_ctx, sa, msg.group_bssid, msg.group_id,
msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN,
- &go, group_bssid, &op_freq, persistent);
+ &go, group_bssid, &op_freq, persistent, &intersection);
}
if (op_freq) {
goto fail;
}
- p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
- &intersection);
if (!p2p_channels_includes(&intersection, reg_class, channel))
{
p2p_dbg(p2p, "forced freq %d MHz not in the supported channels interaction",
} else {
p2p_dbg(p2p, "No forced channel from invitation processing - figure out best one to use");
- p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
- &intersection);
/* Default to own configuration as a starting point */
p2p->op_reg_class = p2p->cfg->op_reg_class;
p2p->op_channel = p2p->cfg->op_channel;
pmksa->pmksa = pos->next;
else
prev->next = pos->next;
- wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
- "the current AP");
- pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
/*
* If OKC is used, there may be other PMKSA cache
* entries based on the same PMK. These needs to be
* flushed so that a new entry can be created based on
- * the new PMK.
+ * the new PMK. Only clear other entries if they have a
+ * matching PMK and this PMK has been used successfully
+ * with the current AP, i.e., if opportunistic flag has
+ * been cleared in wpa_supplicant_key_neg_complete().
*/
- pmksa_cache_flush(pmksa, network_ctx);
+ wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
+ "the current AP and any PMKSA cache entry "
+ "that was based on the old PMK");
+ if (!pos->opportunistic)
+ pmksa_cache_flush(pmksa, network_ctx, pos->pmk,
+ pos->pmk_len);
+ pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
break;
}
prev = pos;
* pmksa_cache_flush - Flush PMKSA cache entries for a specific network
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @network_ctx: Network configuration context or %NULL to flush all entries
+ * @pmk: PMK to match for or %NYLL to match all PMKs
+ * @pmk_len: PMK length
*/
-void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+ const u8 *pmk, size_t pmk_len)
{
struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
int removed = 0;
entry = pmksa->pmksa;
while (entry) {
- if (entry->network_ctx == network_ctx || network_ctx == NULL) {
+ if ((entry->network_ctx == network_ctx ||
+ network_ctx == NULL) &&
+ (pmk == NULL ||
+ (pmk_len == entry->pmk_len &&
+ os_memcmp(pmk, entry->pmk, pmk_len) == 0))) {
wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
"for " MACSTR, MAC2STR(entry->aa));
if (prev)
struct rsn_pmksa_cache_entry *
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
void *network_ctx, const u8 *aa);
-void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx);
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+ const u8 *pmk, size_t pmk_len);
#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
#endif /* CONFIG_TDLS_TESTING */
#define TPK_LIFETIME 43200 /* 12 hours */
-#define TPK_RETRY_COUNT 3
-#define TPK_TIMEOUT 5000 /* in milliseconds */
+#define TPK_M1_RETRY_COUNT 3
+#define TPK_M1_TIMEOUT 5000 /* in milliseconds */
+#define TPK_M2_RETRY_COUNT 10
+#define TPK_M2_TIMEOUT 500 /* in milliseconds */
#define TDLS_MIC_LEN 16
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
- peer->sm_tmr.count = TPK_RETRY_COUNT;
- peer->sm_tmr.timer = TPK_TIMEOUT;
+ if (action_code == WLAN_TDLS_SETUP_RESPONSE) {
+ peer->sm_tmr.count = TPK_M2_RETRY_COUNT;
+ peer->sm_tmr.timer = TPK_M2_TIMEOUT;
+ } else {
+ peer->sm_tmr.count = TPK_M1_RETRY_COUNT;
+ peer->sm_tmr.timer = TPK_M1_TIMEOUT;
+ }
/* Copy message to resend on timeout */
os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN);
wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered "
"(action_code=%u)", action_code);
- eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+ eloop_register_timeout(peer->sm_tmr.timer / 1000,
+ (peer->sm_tmr.timer % 1000) * 1000,
wpa_tdls_tpk_retry_timeout, sm, peer);
return 0;
}
if (peer->sm_tmr.count) {
peer->sm_tmr.count--;
- peer->sm_tmr.timer = TPK_TIMEOUT;
wpa_printf(MSG_INFO, "TDLS: Retrying sending of message "
"(action_code=%u)",
}
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
- eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+ eloop_register_timeout(peer->sm_tmr.timer / 1000,
+ (peer->sm_tmr.timer % 1000) * 1000,
wpa_tdls_tpk_retry_timeout, sm, peer);
} else {
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
}
+int wpa_sm_pmf_enabled(struct wpa_sm *sm)
+{
+ struct wpa_ie_data rsn;
+
+ if (sm->mfp == NO_MGMT_FRAME_PROTECTION || !sm->ap_rsn_ie)
+ return 0;
+
+ if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn) >= 0 &&
+ rsn.capabilities & (WPA_CAPABILITY_MFPR | WPA_CAPABILITY_MFPC))
+ return 1;
+
+ return 0;
+}
+
+
/**
* wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
* @sm: Pointer to WPA state machine data from wpa_sm_init()
void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
{
#ifndef CONFIG_NO_WPA2
- pmksa_cache_flush(sm->pmksa, network_ctx);
+ pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0);
#endif /* CONFIG_NO_WPA2 */
}
int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose);
+int wpa_sm_pmf_enabled(struct wpa_sm *sm);
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
return -1;
}
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Considering connect request: reassociate: %d selected: "
+ MACSTR " bssid: " MACSTR " pending: " MACSTR
+ " wpa_state: %s ssid=%p current_ssid=%p",
+ wpa_s->reassociate, MAC2STR(selected->bssid),
+ MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+ wpa_supplicant_state_txt(wpa_s->wpa_state),
+ ssid, wpa_s->current_ssid);
+
/*
* Do not trigger new association unless the BSSID has changed or if
* reassociation is requested. If we are in process of associating with
(os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
((wpa_s->wpa_state != WPA_ASSOCIATING &&
wpa_s->wpa_state != WPA_AUTHENTICATING) ||
- os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
- 0))) {
+ (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+ os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
+ 0) ||
+ (is_zero_ether_addr(wpa_s->pending_bssid) &&
+ ssid != wpa_s->current_ssid)))) {
if (wpa_supplicant_scard_init(wpa_s, ssid)) {
wpa_supplicant_req_new_scan(wpa_s, 10, 0);
return 0;
}
- wpa_msg(wpa_s, MSG_DEBUG, "Request association: "
- "reassociate: %d selected: "MACSTR " bssid: " MACSTR
- " pending: " MACSTR " wpa_state: %s",
- wpa_s->reassociate, MAC2STR(selected->bssid),
- MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
- wpa_supplicant_state_txt(wpa_s->wpa_state));
+ wpa_msg(wpa_s, MSG_DEBUG, "Request association with " MACSTR,
+ MAC2STR(selected->bssid));
wpa_supplicant_associate(wpa_s, selected, ssid);
} else {
- wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with the "
- "selected AP");
+ wpa_dbg(wpa_s, MSG_DEBUG, "Already associated or trying to "
+ "connect with the selected AP");
}
return 0;
}
+static int freq_included(const struct p2p_channels *channels, unsigned int freq)
+{
+ if (channels == NULL)
+ return 1; /* Assume no restrictions */
+ return p2p_channels_includes_freq(channels, freq);
+
+}
+
+
static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
const u8 *go_dev_addr, const u8 *ssid,
size_t ssid_len, int *go, u8 *group_bssid,
- int *force_freq, int persistent_group)
+ int *force_freq, int persistent_group,
+ const struct p2p_channels *channels)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *s;
wpas_p2p_set_own_freq_preference(wpa_s, res);
}
+ if (*force_freq > 0 &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+ if (*go == 0) {
+ /* We are the client */
+ wpa_printf(MSG_DEBUG, "P2P: Peer was found to be "
+ "running a GO but we are capable of MCC, "
+ "figure out the best channel to use");
+ *force_freq = 0;
+ } else if (!freq_included(channels, *force_freq)) {
+ /* We are the GO, and *force_freq is not in the
+ * intersection */
+ wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+ "in intersection but we are capable of MCC, "
+ "figure out the best channel to use",
+ *force_freq);
+ *force_freq = 0;
+ }
+ }
+
return P2P_SC_SUCCESS;
}
}
-static int freq_included(const struct p2p_channels *channels, unsigned int freq)
-{
- if (channels == NULL)
- return 1; /* Assume no restrictions */
- return p2p_channels_includes_freq(channels, freq);
-}
-
-
static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
int freq, int ht40,
/*
* wpa_supplicant - WNM
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "rsn_supp/wpa.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
}
-static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s,
- u8 dialog_token, u8 status,
- u8 delay, const u8 *target_bssid)
+static void wnm_send_bss_transition_mgmt_resp(
+ struct wpa_supplicant *wpa_s, u8 dialog_token,
+ enum bss_trans_mgmt_status_code status, u8 delay,
+ const u8 *target_bssid)
{
u8 buf[1000], *pos;
struct ieee80211_mgmt *mgmt;
if (wpa_s->wnm_reply) {
wnm_send_bss_transition_mgmt_resp(wpa_s,
wpa_s->wnm_dialog_token,
- 0, /* Accept */
+ WNM_BSS_TM_ACCEPT,
0, NULL);
}
if (wpa_s->wnm_reply) {
wnm_send_bss_transition_mgmt_resp(wpa_s,
wpa_s->wnm_dialog_token,
- 1 /* Reject - unspecified */,
+ WNM_BSS_TM_REJECT_UNSPECIFIED,
0, NULL);
}
return;
pos += 5;
- if (wpa_s->wnm_mode & 0x08) {
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
if (pos + 12 > end) {
wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
return;
pos += 12; /* BSS Termination Duration */
}
- if (wpa_s->wnm_mode & 0x10) {
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
char url[256];
+ unsigned int beacon_int;
+
if (pos + 1 > end || pos + 1 + pos[0] > end) {
wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
"Management Request (URL)");
os_memcpy(url, pos + 1, pos[0]);
url[pos[0]] = '\0';
pos += 1 + pos[0];
- wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation Imminent - "
- "session_info_url=%s", url);
+
+ if (wpa_s->current_bss)
+ beacon_int = wpa_s->current_bss->beacon_int;
+ else
+ beacon_int = 100; /* best guess */
+
+ wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s",
+ wpa_sm_pmf_enabled(wpa_s->wpa),
+ wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url);
}
- if (wpa_s->wnm_mode & 0x04) {
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
"Disassociation Timer %u", wpa_s->wnm_dissoc_timer);
if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) {
}
}
- if (wpa_s->wnm_mode & 0x01) {
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
wpa_s->wnm_num_neighbor_report = 0;
os_free(wpa_s->wnm_neighbor_report_elements);
wpa_s->scan_res_handler = wnm_scan_response;
wpa_supplicant_req_scan(wpa_s, 0, 0);
} else if (reply) {
- wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management "
- "Request Mode is zero");
+ enum bss_trans_mgmt_status_code status;
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT)
+ status = WNM_BSS_TM_ACCEPT;
+ else {
+ wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates");
+ status = WNM_BSS_TM_REJECT_UNSPECIFIED;
+ }
wnm_send_bss_transition_mgmt_resp(wpa_s,
wpa_s->wnm_dialog_token,
- 1 /* Reject - unspecified */,
- 0, NULL);
+ status, 0, NULL);
}
}
/*
* WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
static const char *action_file = NULL;
static int ping_interval = 5;
static int interactive = 0;
+static char *ifname_prefix = NULL;
#if defined(CONFIG_P2P) && defined(ANDROID_P2P)
static char* redirect_interface = NULL;
#endif
static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
+static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */
static void print_help(const char *cmd);
printf("Not connected to hostapd - command dropped.\n");
return -1;
}
+ if (ifname_prefix) {
+ os_snprintf(buf, sizeof(buf), "IFNAME=%s %s",
+ ifname_prefix, cmd);
+ buf[sizeof(buf) - 1] = '\0';
+ cmd = buf;
+ }
len = sizeof(buf) - 1;
ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
wpa_cli_msg_cb);
{
char **res;
int i, count;
+ struct cli_txt_entry *e;
count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
- res = os_calloc(count, sizeof(char *));
+ count += dl_list_len(&p2p_groups);
+ count += dl_list_len(&ifnames);
+ res = os_calloc(count + 1, sizeof(char *));
if (res == NULL)
return NULL;
break;
}
+ dl_list_for_each(e, &p2p_groups, struct cli_txt_entry, list) {
+ size_t len = 8 + os_strlen(e->txt);
+ res[i] = os_malloc(len);
+ if (res[i] == NULL)
+ break;
+ os_snprintf(res[i], len, "ifname=%s", e->txt);
+ i++;
+ }
+
+ dl_list_for_each(e, &ifnames, struct cli_txt_entry, list) {
+ res[i] = os_strdup(e->txt);
+ if (res[i] == NULL)
+ break;
+ i++;
+ }
+
return res;
}
const char *end;
char *cmd;
+ if (pos > 7 && os_strncasecmp(str, "IFNAME=", 7) == 0) {
+ end = os_strchr(str, ' ');
+ if (end && pos > end - str) {
+ pos -= end - str + 1;
+ str = end + 1;
+ }
+ }
+
end = os_strchr(str, ' ');
if (end == NULL || str + pos < end)
return wpa_list_cmd_list();
int count;
int ret = 0;
+ if (argc > 1 && os_strncasecmp(argv[0], "IFNAME=", 7) == 0) {
+ ifname_prefix = argv[0] + 7;
+ argv = &argv[1];
+ argc--;
+ } else
+ ifname_prefix = NULL;
+
+ if (argc == 0)
+ return -1;
+
count = 0;
cmd = wpa_cli_commands;
while (cmd->cmd) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
} else if (str_match(pos, AP_STA_DISCONNECTED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_match(pos, ESS_DISASSOC_IMMINENT)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
printf("wpa_supplicant is terminating - stop monitoring\n");
wpa_cli_quit = 1;
}
+static void update_ifnames(struct wpa_ctrl *ctrl)
+{
+ char buf[4096];
+ size_t len = sizeof(buf);
+ int ret;
+ char *cmd = "INTERFACES";
+ char *pos, *end;
+ char txt[200];
+
+ cli_txt_list_flush(&ifnames);
+
+ if (ctrl == NULL)
+ return;
+ ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
+ if (ret < 0)
+ return;
+ buf[len] = '\0';
+
+ pos = buf;
+ while (pos) {
+ end = os_strchr(pos, '\n');
+ if (end == NULL)
+ break;
+ *end = '\0';
+ ret = os_snprintf(txt, sizeof(txt), "ifname=%s", pos);
+ if (ret > 0 && ret < (int) sizeof(txt))
+ cli_txt_list_add(&ifnames, txt);
+ pos = end + 1;
+ }
+}
+
+
static void try_connection(void *eloop_ctx, void *timeout_ctx)
{
if (ctrl_conn)
cli_txt_list_flush(&p2p_peers);
cli_txt_list_flush(&p2p_groups);
cli_txt_list_flush(&bsses);
+ cli_txt_list_flush(&ifnames);
if (edit_started)
edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
os_free(hfile);
}
if (interactive) {
+ update_ifnames(ctrl_conn);
mon_conn = wpa_ctrl_open(global);
if (mon_conn) {
if (wpa_ctrl_attach(mon_conn) == 0) {
wpa_supplicant_cancel_sched_scan(wpa_s);
}
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+ if (wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
}
}