aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2013-08-26 12:09:05 -0700
committerDmitry Shmidt <dimitrysh@google.com>2013-08-26 12:09:05 -0700
commitb7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15 (patch)
tree5c3debc3660836db47e9d01a3801a3587e74446b
parent0c18dcd2bd94644d9215995225c076d146d6ad82 (diff)
downloadwpa_supplicant_8-b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15.tar.gz
Cumulative patch from commit 853b49a030c00fd6b2dde14e183ca2bf108eaa16
853b49a tests: Increase test_ap_wps_init connection timeout 28de68a P2P: Update peer operating channel from GO Negotiation Confirm 6701fdc P2P: Use the first pref_chan entry as operating channel preference 99d7c76 P2P: Add more debug info on operating channel selection 8d660e0 P2P: Add GO negotiation results into the P2P-GO-NEG-SUCCESS event 2c6f8cf Replace perror() with wpa_printf(strerror) in ctrl_iface calls e743db4 IBSS RSN: Add IBSS-RSN-COMPLETED event message 4c55901 P2P: Add state info to global STATUS command ae8c27f Add STATUS command to global control interface 42868f1 Add SAVE_CONFIG command to global control interface 1b9b31c Add SET command for global control interface 0185007 hostapd: Add survey dump support 245e026 hostapd: Split up channel checking into helpers ba873bd wired: Wait for the link to become active before sending packets d393de1 P2P: Validate the freq in p2p_group_add 973622c wpa_supplicant: Fix AP mode frequency initialization d99ca89 P2P: Skip non-P2P interface in p2p_group_remove * 239abaf WPS: Set currently used RF band in RF Bands attribute bf83eab nl80211: Start P2P Device when rfkill is unblocked 60b13c2 nl80211: Do not change type to station on P2P interfaces e0591c3 wpa_supplicant: Reduce wait time for control interfaces 5046eb4 P2P: Allow separate interface GO to disconnect low-ack STAs 5bcd5c5 FT RRB: Clear pad field to avoid sending out uninitialized data b378c41 nl80211: Fix deinit path to unregister nl_mgmt socket a235aca Fix DETACH command debug prints to avoid use of freed memory 8d6e035 Make global UNIX socket non-blocking for ctrl_iface 86bd141 Change WEP network selection to reject WPA/WPA2 APs 2e145e9 WPS: Fix failure path to allow WSC_NACK and EAP-Failure to be exchanged 3351a38 WPS: Add control interface command for fetching latest status e96872a WPS: Track peer MAC address from the last operations ae23935 WPS: Track PBC status 61b6520 WPS: Track result of the latest WPS operation 50396e2 WPS: Add PBC mode activated/disabled events 961750c WPS: Share a common function for error strings 30158a0 nl80211: Update the assoc_freq during connect 83e7bb0 nl80211: Add more debug prints for DEL_STATION commands Bug: 9056601 Change-Id: I8bc671eb13f4c2c388a4c15cf1ba968c24c9656a Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
-rw-r--r--hostapd/ctrl_iface.c82
-rw-r--r--hostapd/hostapd_cli.c9
-rw-r--r--src/ap/ap_drv_ops.h10
-rw-r--r--src/ap/drv_callbacks.c69
-rw-r--r--src/ap/hostapd.h35
-rw-r--r--src/ap/hw_features.c156
-rw-r--r--src/ap/wpa_auth_ft.c3
-rw-r--r--src/ap/wps_hostapd.c77
-rw-r--r--src/common/wpa_ctrl.h7
-rw-r--r--src/drivers/driver.h108
-rw-r--r--src/drivers/driver_common.c1
-rw-r--r--src/drivers/driver_nl80211.c223
-rw-r--r--src/drivers/driver_wired.c39
-rw-r--r--src/p2p/p2p.c20
-rw-r--r--src/p2p/p2p.h11
-rw-r--r--src/p2p/p2p_go_neg.c8
-rw-r--r--src/p2p/p2p_utils.c9
-rw-r--r--src/wps/wps.c19
-rw-r--r--src/wps/wps.h24
-rw-r--r--src/wps/wps_common.c33
-rw-r--r--src/wps/wps_defs.h1
-rw-r--r--src/wps/wps_dev_attr.c5
-rw-r--r--src/wps/wps_dev_attr.h3
-rw-r--r--src/wps/wps_enrollee.c26
-rw-r--r--src/wps/wps_i.h9
-rw-r--r--src/wps/wps_registrar.c36
-rw-r--r--wpa_supplicant/ap.c23
-rw-r--r--wpa_supplicant/ctrl_iface.c108
-rw-r--r--wpa_supplicant/ctrl_iface_udp.c10
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c91
-rw-r--r--wpa_supplicant/events.c32
-rw-r--r--wpa_supplicant/ibss_rsn.c30
-rw-r--r--wpa_supplicant/ibss_rsn.h6
-rw-r--r--wpa_supplicant/p2p_supplicant.c18
-rw-r--r--wpa_supplicant/scan.c13
-rw-r--r--wpa_supplicant/wpa_supplicant.c4
-rw-r--r--wpa_supplicant/wps_supplicant.c44
37 files changed, 1190 insertions, 212 deletions
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 021cbe57..be941c44 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -487,6 +487,75 @@ static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
}
+
+
+static const char * pbc_status_str(enum pbc_status status)
+{
+ switch (status) {
+ case WPS_PBC_STATUS_DISABLE:
+ return "Disabled";
+ case WPS_PBC_STATUS_ACTIVE:
+ return "Active";
+ case WPS_PBC_STATUS_TIMEOUT:
+ return "Timed-out";
+ case WPS_PBC_STATUS_OVERLAP:
+ return "Overlap";
+ default:
+ return "Unknown";
+ }
+}
+
+
+static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+ int ret;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
+ pbc_status_str(hapd->wps_stats.pbc_status));
+
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n",
+ (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
+ "Success":
+ (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
+ "Failed" : "None")));
+
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ /* If status == Failure - Add possible Reasons */
+ if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
+ hapd->wps_stats.failure_reason > 0) {
+ ret = os_snprintf(pos, end - pos,
+ "Failure Reason: %s\n",
+ wps_ei_str(hapd->wps_stats.failure_reason));
+
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (hapd->wps_stats.status) {
+ ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
+ MAC2STR(hapd->wps_stats.peer_addr));
+
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
#endif /* CONFIG_WPS */
@@ -1003,6 +1072,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) {
+ reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply,
+ reply_size);
#ifdef CONFIG_WPS_NFC
} else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
@@ -1256,7 +1328,10 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
"directory not empty - leaving it "
"behind");
} else {
- perror("rmdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR,
+ "rmdir[ctrl_interface=%s]: %s",
+ hapd->conf->ctrl_interface,
+ strerror(errno));
}
}
}
@@ -1486,7 +1561,10 @@ void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
"directory not empty - leaving it "
"behind");
} else {
- perror("rmdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR,
+ "rmdir[ctrl_interface=%s]: %s",
+ interfaces->global_iface_path,
+ strerror(errno));
}
}
os_free(interfaces->global_iface_path);
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 70715944..7187abcf 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -79,6 +79,7 @@ static const char *commands_help =
#endif /* CONFIG_WPS_NFC */
" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
" wps_config <SSID> <auth> <encr> <key> configure AP\n"
+" wps_get_status show current WPS status\n"
#endif /* CONFIG_WPS */
" get_config show current configuration\n"
" help show this usage help\n"
@@ -522,6 +523,13 @@ static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
}
+static int hostapd_cli_cmd_wps_get_status(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "WPS_GET_STATUS");
+}
+
+
static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -823,6 +831,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
#endif /* CONFIG_WPS_NFC */
{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
{ "wps_config", hostapd_cli_cmd_wps_config },
+ { "wps_get_status", hostapd_cli_cmd_wps_get_status },
#endif /* CONFIG_WPS */
{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index cfc30ce4..23277b6b 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -225,4 +225,14 @@ static inline void hostapd_drv_poll_client(struct hostapd_data *hapd,
hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos);
}
+static inline int hostapd_drv_get_survey(struct hostapd_data *hapd,
+ unsigned int freq)
+{
+ if (hapd->driver == NULL)
+ return -1;
+ if (!hapd->driver->get_survey)
+ return -1;
+ return hapd->driver->get_survey(hapd->drv_priv, freq);
+}
+
#endif /* AP_DRV_OPS */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index fa4b5e4b..e3ba224e 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -715,6 +715,72 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
}
+static struct hostapd_channel_data * hostapd_get_mode_channel(
+ struct hostapd_iface *iface, unsigned int freq)
+{
+ int i;
+ struct hostapd_channel_data *chan;
+
+ for (i = 0; i < iface->current_mode->num_channels; i++) {
+ chan = &iface->current_mode->channels[i];
+ if (!chan)
+ return NULL;
+ if ((unsigned int) chan->freq == freq)
+ return chan;
+ }
+
+ return NULL;
+}
+
+
+static void hostapd_update_nf(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan,
+ struct freq_survey *survey)
+{
+ if (!iface->chans_surveyed) {
+ chan->min_nf = survey->nf;
+ iface->lowest_nf = survey->nf;
+ } else {
+ if (dl_list_empty(&chan->survey_list))
+ chan->min_nf = survey->nf;
+ else if (survey->nf < chan->min_nf)
+ chan->min_nf = survey->nf;
+ if (survey->nf < iface->lowest_nf)
+ iface->lowest_nf = survey->nf;
+ }
+}
+
+
+static void hostapd_event_get_survey(struct hostapd_data *hapd,
+ struct survey_results *survey_results)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ struct freq_survey *survey, *tmp;
+ struct hostapd_channel_data *chan;
+
+ if (dl_list_empty(&survey_results->survey_list)) {
+ wpa_printf(MSG_DEBUG, "No survey data received");
+ return;
+ }
+
+ dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
+ struct freq_survey, list) {
+ chan = hostapd_get_mode_channel(iface, survey->freq);
+ if (!chan)
+ continue;
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+
+ dl_list_del(&survey->list);
+ dl_list_add_tail(&chan->survey_list, &survey->list);
+
+ hostapd_update_nf(iface, chan, survey);
+
+ iface->chans_surveyed++;
+ }
+}
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -856,6 +922,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
hapd, data->connect_failed_reason.addr,
data->connect_failed_reason.code);
break;
+ case EVENT_SURVEY:
+ hostapd_event_get_survey(hapd, &data->survey_results);
+ break;
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 75d9c66a..673dd34a 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -47,6 +47,11 @@ struct hapd_interfaces {
struct hostapd_dynamic_iface **dynamic_iface;
};
+enum hostapd_chan_status {
+ HOSTAPD_CHAN_VALID = 0, /* channel is ready */
+ HOSTAPD_CHAN_INVALID = 1, /* no usable channel found */
+ HOSTAPD_CHAN_ACS = 2, /* ACS work being performed */
+};
struct hostapd_probereq_cb {
int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,
@@ -67,6 +72,25 @@ struct hostapd_frame_info {
int ssi_signal; /* dBm */
};
+enum wps_status {
+ WPS_STATUS_SUCCESS = 1,
+ WPS_STATUS_FAILURE
+};
+
+enum pbc_status {
+ WPS_PBC_STATUS_DISABLE,
+ WPS_PBC_STATUS_ACTIVE,
+ WPS_PBC_STATUS_TIMEOUT,
+ WPS_PBC_STATUS_OVERLAP
+};
+
+struct wps_stat {
+ enum wps_status status;
+ enum wps_error_indication failure_reason;
+ enum pbc_status pbc_status;
+ u8 peer_addr[ETH_ALEN];
+};
+
/**
* struct hostapd_data - hostapd per-BSS data structure
@@ -147,6 +171,8 @@ struct hostapd_data {
unsigned int ap_pin_failures_consecutive;
struct upnp_wps_device_sm *wps_upnp;
unsigned int ap_pin_lockout_time;
+
+ struct wps_stat wps_stats;
#endif /* CONFIG_WPS */
struct hostapd_probereq_cb *probereq_cb;
@@ -275,6 +301,15 @@ struct hostapd_iface {
int olbc_ht;
u16 ht_op_mode;
+
+ /* surveying helpers */
+
+ /* number of channels surveyed */
+ unsigned int chans_surveyed;
+
+ /* lowest observed noise floor in dBm */
+ s8 lowest_nf;
+
void (*scan_cb)(struct hostapd_iface *iface);
};
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 37112bd0..bf0dd953 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -634,6 +634,81 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
}
+static int hostapd_is_usable_chan(struct hostapd_iface *iface,
+ int channel, int primary)
+{
+ int i;
+ struct hostapd_channel_data *chan;
+
+ for (i = 0; i < iface->current_mode->num_channels; i++) {
+ chan = &iface->current_mode->channels[i];
+ if (chan->chan != channel)
+ continue;
+
+ if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
+ return 1;
+
+ wpa_printf(MSG_DEBUG,
+ "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s%s",
+ primary ? "" : "Configured HT40 secondary ",
+ i, chan->chan, chan->flag,
+ chan->flag & HOSTAPD_CHAN_NO_IBSS ? " NO-IBSS" : "",
+ chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN ?
+ " PASSIVE-SCAN" : "",
+ chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
+ }
+
+ return 0;
+}
+
+
+static int hostapd_is_usable_chans(struct hostapd_iface *iface)
+{
+ if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
+ return 0;
+
+ if (!iface->conf->secondary_channel)
+ return 1;
+
+ return hostapd_is_usable_chan(iface, iface->conf->channel +
+ iface->conf->secondary_channel * 4, 0);
+}
+
+
+static enum hostapd_chan_status
+hostapd_check_chans(struct hostapd_iface *iface)
+{
+ if (iface->conf->channel) {
+ if (hostapd_is_usable_chans(iface))
+ return HOSTAPD_CHAN_VALID;
+ else
+ return HOSTAPD_CHAN_INVALID;
+ }
+
+ /*
+ * The user set channel=0 which is used to trigger ACS,
+ * which we do not yet support.
+ */
+ return HOSTAPD_CHAN_INVALID;
+}
+
+
+static void hostapd_notify_bad_chans(struct hostapd_iface *iface)
+{
+ hostapd_logger(iface->bss[0], NULL,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING,
+ "Configured channel (%d) not found from the "
+ "channel list of current mode (%d) %s",
+ iface->conf->channel,
+ iface->current_mode->mode,
+ hostapd_hw_mode_txt(iface->current_mode->mode));
+ hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING,
+ "Hardware does not support configured channel");
+}
+
+
/**
* hostapd_select_hw_mode - Select the hardware mode
* @iface: Pointer to interface data.
@@ -644,7 +719,7 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
*/
int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
- int i, j, ok;
+ int i;
if (iface->num_hw_features < 1)
return -1;
@@ -669,80 +744,15 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
return -2;
}
- ok = 0;
- for (j = 0; j < iface->current_mode->num_channels; j++) {
- struct hostapd_channel_data *chan =
- &iface->current_mode->channels[j];
- if (chan->chan == iface->conf->channel) {
- if (chan->flag & HOSTAPD_CHAN_DISABLED) {
- wpa_printf(MSG_ERROR,
- "channel [%i] (%i) is disabled for "
- "use in AP mode, flags: 0x%x%s%s%s",
- j, chan->chan, chan->flag,
- chan->flag & HOSTAPD_CHAN_NO_IBSS ?
- " NO-IBSS" : "",
- chan->flag &
- HOSTAPD_CHAN_PASSIVE_SCAN ?
- " PASSIVE-SCAN" : "",
- chan->flag & HOSTAPD_CHAN_RADAR ?
- " RADAR" : "");
- } else {
- ok = 1;
- break;
- }
- }
- }
- if (ok && iface->conf->secondary_channel) {
- int sec_ok = 0;
- int sec_chan = iface->conf->channel +
- iface->conf->secondary_channel * 4;
- for (j = 0; j < iface->current_mode->num_channels; j++) {
- struct hostapd_channel_data *chan =
- &iface->current_mode->channels[j];
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
- (chan->chan == sec_chan)) {
- sec_ok = 1;
- break;
- }
- }
- if (!sec_ok) {
- hostapd_logger(iface->bss[0], NULL,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_WARNING,
- "Configured HT40 secondary channel "
- "(%d) not found from the channel list "
- "of current mode (%d) %s",
- sec_chan, iface->current_mode->mode,
- hostapd_hw_mode_txt(
- iface->current_mode->mode));
- ok = 0;
- }
- }
- if (iface->conf->channel == 0) {
- /* TODO: could request a scan of neighboring BSSes and select
- * the channel automatically */
- wpa_printf(MSG_ERROR, "Channel not configured "
- "(hw_mode/channel in hostapd.conf)");
+ switch (hostapd_check_chans(iface)) {
+ case HOSTAPD_CHAN_VALID:
+ return 0;
+ case HOSTAPD_CHAN_ACS: /* ACS not supported yet */
+ case HOSTAPD_CHAN_INVALID:
+ default:
+ hostapd_notify_bad_chans(iface);
return -3;
}
- if (ok == 0 && iface->conf->channel != 0) {
- hostapd_logger(iface->bss[0], NULL,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_WARNING,
- "Configured channel (%d) not found from the "
- "channel list of current mode (%d) %s",
- iface->conf->channel,
- iface->current_mode->mode,
- hostapd_hw_mode_txt(iface->current_mode->mode));
- iface->current_mode = NULL;
- }
-
- if (iface->current_mode == NULL) {
- hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_WARNING,
- "Hardware does not support configured channel");
- return -4;
- }
return 0;
}
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 1bb5d97a..29d9d29e 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -329,6 +329,7 @@ static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth,
os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
os_memcpy(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
+ os_memset(f.pad, 0, sizeof(f.pad));
if (aes_wrap(r0kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
f.nonce, frame.nonce) < 0)
@@ -1317,6 +1318,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
WPA_PMK_NAME_LEN);
r.pairwise = host_to_le16(pairwise);
+ os_memset(r.pad, 0, sizeof(r.pad));
if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
r.nonce, resp.nonce) < 0) {
@@ -1620,6 +1622,7 @@ static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
os_get_time(&now);
WPA_PUT_LE32(f.timestamp, now.sec);
f.pairwise = host_to_le16(pairwise);
+ os_memset(f.pad, 0, sizeof(f.pad));
if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
f.timestamp, frame.timestamp) < 0)
return;
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 69b34fef..3304c063 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -707,6 +707,12 @@ static int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx)
static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
struct wps_event_pwd_auth_fail *data)
{
+ /* Update WPS Status - Authentication Failure */
+ wpa_printf(MSG_DEBUG, "WPS: Authentication failure update");
+ hapd->wps_stats.status = WPS_STATUS_FAILURE;
+ hapd->wps_stats.failure_reason = WPS_EI_AUTH_FAILURE;
+ os_memcpy(hapd->wps_stats.peer_addr, data->peer_macaddr, ETH_ALEN);
+
hostapd_wps_for_each(hapd, wps_pwd_auth_fail, data);
}
@@ -734,21 +740,59 @@ static void hostapd_wps_ap_pin_success(struct hostapd_data *hapd)
}
-static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = {
- "No Error", /* WPS_EI_NO_ERROR */
- "TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */
- "WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */
-};
+static void hostapd_wps_event_pbc_overlap(struct hostapd_data *hapd)
+{
+ /* Update WPS Status - PBC Overlap */
+ hapd->wps_stats.pbc_status = WPS_PBC_STATUS_OVERLAP;
+}
+
+
+static void hostapd_wps_event_pbc_timeout(struct hostapd_data *hapd)
+{
+ /* Update WPS PBC Status:PBC Timeout */
+ hapd->wps_stats.pbc_status = WPS_PBC_STATUS_TIMEOUT;
+}
+
+
+static void hostapd_wps_event_pbc_active(struct hostapd_data *hapd)
+{
+ /* Update WPS PBC status - Active */
+ hapd->wps_stats.pbc_status = WPS_PBC_STATUS_ACTIVE;
+}
+
+
+static void hostapd_wps_event_pbc_disable(struct hostapd_data *hapd)
+{
+ /* Update WPS PBC status - Active */
+ hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE;
+}
+
+
+static void hostapd_wps_event_success(struct hostapd_data *hapd,
+ struct wps_event_success *success)
+{
+ /* Update WPS status - Success */
+ hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE;
+ hapd->wps_stats.status = WPS_STATUS_SUCCESS;
+ os_memcpy(hapd->wps_stats.peer_addr, success->peer_macaddr, ETH_ALEN);
+}
+
static void hostapd_wps_event_fail(struct hostapd_data *hapd,
struct wps_event_fail *fail)
{
+ /* Update WPS status - Failure */
+ hapd->wps_stats.status = WPS_STATUS_FAILURE;
+ os_memcpy(hapd->wps_stats.peer_addr, fail->peer_macaddr, ETH_ALEN);
+
+ hapd->wps_stats.failure_reason = fail->error_indication;
+
if (fail->error_indication > 0 &&
fail->error_indication < NUM_WPS_EI_VALUES) {
wpa_msg(hapd->msg_ctx, MSG_INFO,
WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
fail->msg, fail->config_error, fail->error_indication,
- wps_event_fail_reason[fail->error_indication]);
+ wps_ei_str(fail->error_indication));
} else {
wpa_msg(hapd->msg_ctx, MSG_INFO,
WPS_EVENT_FAIL "msg=%d config_error=%d",
@@ -770,17 +814,28 @@ static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
hostapd_wps_event_fail(hapd, &data->fail);
break;
case WPS_EV_SUCCESS:
+ hostapd_wps_event_success(hapd, &data->success);
wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS);
break;
case WPS_EV_PWD_AUTH_FAIL:
hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
break;
case WPS_EV_PBC_OVERLAP:
+ hostapd_wps_event_pbc_overlap(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP);
break;
case WPS_EV_PBC_TIMEOUT:
+ hostapd_wps_event_pbc_timeout(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT);
break;
+ case WPS_EV_PBC_ACTIVE:
+ hostapd_wps_event_pbc_active(hapd);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ACTIVE);
+ break;
+ case WPS_EV_PBC_DISABLE:
+ hostapd_wps_event_pbc_disable(hapd);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_DISABLE);
+ break;
case WPS_EV_ER_AP_ADD:
break;
case WPS_EV_ER_AP_REMOVE:
@@ -802,6 +857,15 @@ static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
}
+static int hostapd_wps_rf_band_cb(void *ctx)
+{
+ struct hostapd_data *hapd = ctx;
+
+ return hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
+ WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+}
+
+
static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
{
wpabuf_free(hapd->wps_beacon_ie);
@@ -909,6 +973,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wps->cred_cb = hostapd_wps_cred_cb;
wps->event_cb = hostapd_wps_event_cb;
+ wps->rf_band_cb = hostapd_wps_rf_band_cb;
wps->cb_ctx = hapd;
os_memset(&cfg, 0, sizeof(cfg));
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 0c05a41d..63829fe1 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -67,6 +67,9 @@ extern "C" {
#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
#endif
+/** RSN IBSS 4-way handshakes completed with specified peer */
+#define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED "
+
/** WPS overlap detected in PBC mode */
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
/** Available WPS AP with active PBC found in scan results */
@@ -88,6 +91,10 @@ extern "C" {
#define WPS_EVENT_SUCCESS "WPS-SUCCESS "
/** WPS enrollment attempt timed out and was terminated */
#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT "
+/* PBC mode was activated */
+#define WPS_EVENT_ACTIVE "WPS-PBC-ACTIVE "
+/* PBC mode was disabled */
+#define WPS_EVENT_DISABLE "WPS-PBC-DISABLE "
#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 160ac0c7..e875d224 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -20,6 +20,7 @@
#define WPA_SUPPLICANT_DRIVER_VERSION 4
#include "common/defs.h"
+#include "utils/list.h"
#define HOSTAPD_CHAN_DISABLED 0x00000001
#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
@@ -55,9 +56,20 @@ struct hostapd_channel_data {
int flag;
/**
- * max_tx_power - maximum transmit power in dBm
+ * max_tx_power - Maximum transmit power in dBm
*/
u8 max_tx_power;
+
+ /*
+ * survey_list - Linked list of surveys
+ */
+ struct dl_list survey_list;
+
+ /**
+ * min_nf - Minimum observed noise floor, in dBm, based on all
+ * surveyed channel data
+ */
+ s8 min_nf;
};
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
@@ -2161,8 +2173,9 @@ struct wpa_driver_ops {
* Returns: 0 on success, -1 on failure (or if not supported)
*
* This optional function can be used to disable AP mode related
- * configuration and change the driver mode to station mode to allow
- * normal station operations like scanning to be completed.
+ * configuration. If the interface was not dynamically added,
+ * change the driver mode to station mode to allow normal station
+ * operations like scanning to be completed.
*/
int (*deinit_ap)(void *priv);
@@ -2171,8 +2184,9 @@ struct wpa_driver_ops {
* @priv: Private driver interface data
* Returns: 0 on success, -1 on failure (or if not supported)
*
- * This optional function can be used to disable P2P client mode. It
- * can be used to change the interface type back to station mode.
+ * This optional function can be used to disable P2P client mode. If the
+ * interface was not dynamically added, change the interface type back
+ * to station mode.
*/
int (*deinit_p2p_cli)(void *priv);
@@ -2737,6 +2751,31 @@ struct wpa_driver_ops {
* mode.
*/
int (*stop_ap)(void *priv);
+
+ /**
+ * get_survey - Retrieve survey data
+ * @priv: Private driver interface data
+ * @freq: If set, survey data for the specified frequency is only
+ * being requested. If not set, all survey data is requested.
+ * Returns: 0 on success, -1 on failure
+ *
+ * Use this to retrieve:
+ *
+ * - the observed channel noise floor
+ * - the amount of time we have spent on the channel
+ * - the amount of time during which we have spent on the channel that
+ * the radio has determined the medium is busy and we cannot
+ * transmit
+ * - the amount of time we have spent receiving data
+ * - the amount of time we have spent transmitting data
+ *
+ * This data can be used for spectrum heuristics. One example is
+ * Automatic Channel Selection (ACS). The channel survey data is
+ * kept on a linked list on the channel data, one entry is added
+ * for each survey. The min_nf of the channel is updated for each
+ * survey.
+ */
+ int (*get_survey)(void *priv, unsigned int freq);
};
@@ -3221,11 +3260,57 @@ enum wpa_event_type {
*
* The channel which was previously unavailable is now available again.
*/
- EVENT_DFS_NOP_FINISHED
+ EVENT_DFS_NOP_FINISHED,
+
+ /*
+ * EVENT_SURVEY - Received survey data
+ *
+ * This event gets triggered when a driver query is issued for survey
+ * data and the requested data becomes available. The returned data is
+ * stored in struct survey_results. The results provide at most one
+ * survey entry for each frequency and at minimum will provide one survey
+ * entry for one frequency. The survey data can be os_malloc()'d and
+ * then os_free()'d, so the event callback must only copy data.
+ */
+ EVENT_SURVEY
};
/**
+ * struct freq_survey - Channel survey info
+ *
+ * @ifidx: Interface index in which this survey was observed
+ * @freq: Center of frequency of the surveyed channel
+ * @nf: Channel noise floor in dBm
+ * @channel_time: Amount of time in ms the radio spent on the channel
+ * @channel_time_busy: Amount of time in ms the radio detected some signal
+ * that indicated to the radio the channel was not clear
+ * @channel_time_rx: Amount of time the radio spent receiving data
+ * @channel_time_tx: Amount of time the radio spent transmitting data
+ * @filled: bitmask indicating which fields have been reported, see
+ * SURVEY_HAS_* defines.
+ * @list: Internal list pointers
+ */
+struct freq_survey {
+ u32 ifidx;
+ unsigned int freq;
+ s8 nf;
+ u64 channel_time;
+ u64 channel_time_busy;
+ u64 channel_time_rx;
+ u64 channel_time_tx;
+ unsigned int filled;
+ struct dl_list list;
+};
+
+#define SURVEY_HAS_NF BIT(0)
+#define SURVEY_HAS_CHAN_TIME BIT(1)
+#define SURVEY_HAS_CHAN_TIME_BUSY BIT(2)
+#define SURVEY_HAS_CHAN_TIME_RX BIT(3)
+#define SURVEY_HAS_CHAN_TIME_TX BIT(4)
+
+
+/**
* union wpa_event_data - Additional data for wpa_supplicant_event() calls
*/
union wpa_event_data {
@@ -3867,6 +3952,17 @@ union wpa_event_data {
struct dfs_event {
int freq;
} dfs_event;
+
+ /**
+ * survey_results - Survey result data for EVENT_SURVEY
+ * @freq_filter: Requested frequency survey filter, 0 if request
+ * was for all survey data
+ * @survey_list: Linked list of survey data
+ */
+ struct survey_results {
+ unsigned int freq_filter;
+ struct dl_list survey_list; /* struct freq_survey */
+ } survey_results;
};
/**
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 12ccc142..8d1d22eb 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -84,6 +84,7 @@ const char * event_to_string(enum wpa_event_type event)
E2S(DFS_CAC_FINISHED);
E2S(DFS_CAC_ABORTED);
E2S(DFS_NOP_FINISHED);
+ E2S(SURVEY);
}
return "UNKNOWN";
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 2b364c1b..a3ff189b 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -197,6 +197,7 @@ struct i802_bss {
u8 addr[ETH_ALEN];
int freq;
+ int if_dynamic;
void *ctx;
struct nl_handle *nl_preq, *nl_mgmt;
@@ -364,6 +365,8 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
static int wpa_driver_nl80211_authenticate_retry(
struct wpa_driver_nl80211_data *drv);
+static int i802_set_iface_flags(struct i802_bss *bss, int up);
+
static const char * nl80211_command_to_string(enum nl80211_commands cmd)
{
@@ -1294,7 +1297,9 @@ static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
"associated BSS from scan results: %u MHz",
arg.assoc_freq);
- return arg.assoc_freq ? arg.assoc_freq : drv->assoc_freq;
+ if (arg.assoc_freq)
+ drv->assoc_freq = arg.assoc_freq;
+ return drv->assoc_freq;
}
wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
"(%s)", ret, strerror(-ret));
@@ -3515,8 +3520,7 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
{
struct wpa_driver_nl80211_data *drv = ctx;
wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
- if (linux_set_iface_flags(drv->global->ioctl_sock,
- drv->first_bss.ifname, 1)) {
+ if (i802_set_iface_flags(&drv->first_bss, 1)) {
wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
"after rfkill unblock");
return;
@@ -4034,15 +4038,14 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
#endif /* HOSTAPD */
struct i802_bss *bss = &drv->first_bss;
int send_rfkill_event = 0;
- int dynamic_if;
drv->ifindex = if_nametoindex(bss->ifname);
bss->ifindex = drv->ifindex;
bss->wdev_id = drv->global->if_add_wdevid;
bss->wdev_id_set = drv->global->if_add_wdevid_set;
- dynamic_if = drv->ifindex == drv->global->if_add_ifindex;
- dynamic_if = dynamic_if || drv->global->if_add_wdevid_set;
+ bss->if_dynamic = drv->ifindex == drv->global->if_add_ifindex;
+ bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set;
drv->global->if_add_wdevid_set = 0;
if (wpa_driver_nl80211_capa(drv))
@@ -4052,7 +4055,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
bss->ifname, drv->phyname);
#ifndef HOSTAPD
- if (dynamic_if)
+ if (bss->if_dynamic)
nlmode = nl80211_get_ifmode(bss);
/*
@@ -4191,6 +4194,7 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
(void) i802_set_iface_flags(bss, 0);
if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
+ nl80211_mgmt_unsubscribe(bss, "deinit");
} else {
nl80211_mgmt_unsubscribe(bss, "deinit");
nl80211_del_p2pdev(bss);
@@ -6710,6 +6714,9 @@ static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
+ " --> %d (%s)",
+ bss->ifname, MAC2STR(addr), ret, strerror(-ret));
if (ret == -ENOENT)
return 0;
return ret;
@@ -7669,7 +7676,9 @@ static int wpa_driver_nl80211_try_connect(
if (params->freq) {
wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
- }
+ drv->assoc_freq = params->freq;
+ } else
+ drv->assoc_freq = 0;
if (params->bg_scan_period >= 0) {
wpa_printf(MSG_DEBUG, " * bg scan period=%d",
params->bg_scan_period);
@@ -8401,6 +8410,8 @@ static int i802_flush(void *priv)
if (!msg)
return -1;
+ wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
+ bss->ifname);
nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
/*
@@ -9567,6 +9578,14 @@ static int wpa_driver_nl80211_deinit_ap(void *priv)
if (!is_ap_interface(drv->nlmode))
return -1;
wpa_driver_nl80211_del_beacon(drv);
+
+ /*
+ * If the P2P GO interface was dynamically added, then it is
+ * possible that the interface change to station is not possible.
+ */
+ if (drv->nlmode == NL80211_IFTYPE_P2P_GO && bss->if_dynamic)
+ return 0;
+
return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
}
@@ -9589,6 +9608,14 @@ static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
struct wpa_driver_nl80211_data *drv = bss->drv;
if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
return -1;
+
+ /*
+ * If the P2P Client interface was dynamically added, then it is
+ * possible that the interface change to station is not possible.
+ */
+ if (bss->if_dynamic)
+ return 0;
+
return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
}
@@ -9995,6 +10022,185 @@ static int nl80211_flush_pmkid(void *priv)
}
+static void clean_survey_results(struct survey_results *survey_results)
+{
+ struct freq_survey *survey, *tmp;
+
+ if (dl_list_empty(&survey_results->survey_list))
+ return;
+
+ dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
+ struct freq_survey, list) {
+ dl_list_del(&survey->list);
+ os_free(survey);
+ }
+}
+
+
+static void add_survey(struct nlattr **sinfo, u32 ifidx,
+ struct dl_list *survey_list)
+{
+ struct freq_survey *survey;
+
+ survey = os_zalloc(sizeof(struct freq_survey));
+ if (!survey)
+ return;
+
+ survey->ifidx = ifidx;
+ survey->freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
+ survey->filled = 0;
+
+ if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
+ survey->nf = (int8_t)
+ nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+ survey->filled |= SURVEY_HAS_NF;
+ }
+
+ if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) {
+ survey->channel_time =
+ nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
+ survey->filled |= SURVEY_HAS_CHAN_TIME;
+ }
+
+ if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
+ survey->channel_time_busy =
+ nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
+ survey->filled |= SURVEY_HAS_CHAN_TIME_BUSY;
+ }
+
+ if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) {
+ survey->channel_time_rx =
+ nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]);
+ survey->filled |= SURVEY_HAS_CHAN_TIME_RX;
+ }
+
+ if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) {
+ survey->channel_time_tx =
+ nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]);
+ survey->filled |= SURVEY_HAS_CHAN_TIME_TX;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Freq survey dump event (freq=%d MHz noise=%d channel_time=%ld busy_time=%ld tx_time=%ld rx_time=%ld filled=%04x)",
+ survey->freq,
+ survey->nf,
+ (unsigned long int) survey->channel_time,
+ (unsigned long int) survey->channel_time_busy,
+ (unsigned long int) survey->channel_time_tx,
+ (unsigned long int) survey->channel_time_rx,
+ survey->filled);
+
+ dl_list_add_tail(survey_list, &survey->list);
+}
+
+
+static int check_survey_ok(struct nlattr **sinfo, u32 surveyed_freq,
+ unsigned int freq_filter)
+{
+ if (!freq_filter)
+ return 1;
+
+ return freq_filter == surveyed_freq;
+}
+
+
+static int survey_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+ struct survey_results *survey_results;
+ u32 surveyed_freq = 0;
+ u32 ifidx;
+
+ static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+ [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+ };
+
+ survey_results = (struct survey_results *) arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+
+ if (!tb[NL80211_ATTR_SURVEY_INFO])
+ return NL_SKIP;
+
+ if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+ tb[NL80211_ATTR_SURVEY_INFO],
+ survey_policy))
+ return NL_SKIP;
+
+ if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) {
+ wpa_printf(MSG_ERROR, "nl80211: Invalid survey data");
+ return NL_SKIP;
+ }
+
+ surveyed_freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
+
+ if (!check_survey_ok(sinfo, surveyed_freq,
+ survey_results->freq_filter))
+ return NL_SKIP;
+
+ if (survey_results->freq_filter &&
+ survey_results->freq_filter != surveyed_freq) {
+ wpa_printf(MSG_EXCESSIVE, "nl80211: Ignoring survey data for freq %d MHz",
+ surveyed_freq);
+ return NL_SKIP;
+ }
+
+ add_survey(sinfo, ifidx, &survey_results->survey_list);
+
+ return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int err = -ENOBUFS;
+ union wpa_event_data data;
+ struct survey_results *survey_results;
+
+ os_memset(&data, 0, sizeof(data));
+ survey_results = &data.survey_results;
+
+ dl_list_init(&survey_results->survey_list);
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto nla_put_failure;
+
+ nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ if (freq)
+ data.survey_results.freq_filter = freq;
+
+ do {
+ wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
+ err = send_and_recv_msgs(drv, msg, survey_handler,
+ survey_results);
+ } while (err > 0);
+
+ if (err) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
+ goto out_clean;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
+
+out_clean:
+ clean_survey_results(survey_results);
+nla_put_failure:
+ return err;
+}
+
+
static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
const u8 *replay_ctr)
{
@@ -10625,6 +10831,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
#endif /* CONFIG_TDLS */
.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
.get_mac_addr = wpa_driver_nl80211_get_macaddr,
+ .get_survey = wpa_driver_nl80211_get_survey,
#ifdef ANDROID_P2P
.set_noa = wpa_driver_set_p2p_noa,
.get_noa = wpa_driver_get_p2p_noa,
diff --git a/src/drivers/driver_wired.c b/src/drivers/driver_wired.c
index e0f0f228..21f5e424 100644
--- a/src/drivers/driver_wired.c
+++ b/src/drivers/driver_wired.c
@@ -17,6 +17,7 @@
#endif /* __linux__ */
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
#include <net/if_dl.h>
+#include <net/if_media.h>
#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
#ifdef __sun__
#include <sys/sockio.h>
@@ -454,6 +455,34 @@ static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
}
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+static int wpa_driver_wired_get_ifstatus(const char *ifname, int *status)
+{
+ struct ifmediareq ifmr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ os_memset(&ifmr, 0, sizeof(ifmr));
+ os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
+ perror("ioctl[SIOCGIFMEDIA]");
+ close(s);
+ return -1;
+ }
+ close(s);
+ *status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) ==
+ (IFM_ACTIVE | IFM_AVALID);
+
+ return 0;
+}
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
+
+
static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
{
struct ifreq ifr;
@@ -562,6 +591,16 @@ static void * wpa_driver_wired_init(void *ctx, const char *ifname)
__func__);
drv->iff_allmulti = 1;
}
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+ {
+ int status;
+ wpa_printf(MSG_DEBUG, "%s: waiting for link to become active",
+ __func__);
+ while (wpa_driver_wired_get_ifstatus(ifname, &status) == 0 &&
+ status == 0)
+ sleep(1);
+ }
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
return drv;
}
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 0a414eeb..b9a754cc 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -180,6 +180,12 @@ static const char * p2p_state_txt(int state)
}
+const char * p2p_get_state_txt(struct p2p_data *p2p)
+{
+ return p2p_state_txt(p2p->state);
+}
+
+
u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
{
struct p2p_device *dev = NULL;
@@ -1195,6 +1201,8 @@ static int p2p_prepare_channel_pref(struct p2p_data *p2p,
u8 op_class, op_channel;
unsigned int freq = force_freq ? force_freq : pref_freq;
+ p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u",
+ force_freq, pref_freq);
if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) {
p2p_dbg(p2p, "Unsupported frequency %u MHz", freq);
return -1;
@@ -1227,6 +1235,8 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
{
u8 op_class, op_channel;
+ p2p_dbg(p2p, "Prepare channel best");
+
if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
p2p_supported_freq(p2p, p2p->best_freq_overall) &&
p2p_freq_to_channel(p2p->best_freq_overall, &op_class, &op_channel)
@@ -1248,7 +1258,15 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
p2p_dbg(p2p, "Select best 2.4 GHz channel as operating channel preference");
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
+ } else if (p2p->cfg->num_pref_chan > 0 &&
+ p2p_channels_includes(&p2p->cfg->channels,
+ p2p->cfg->pref_chan[0].op_class,
+ p2p->cfg->pref_chan[0].chan)) {
+ p2p_dbg(p2p, "Select first pref_chan entry as operating channel preference");
+ p2p->op_reg_class = p2p->cfg->pref_chan[0].op_class;
+ p2p->op_channel = p2p->cfg->pref_chan[0].chan;
} else {
+ p2p_dbg(p2p, "Select pre-configured channel as operating channel preference");
p2p->op_reg_class = p2p->cfg->op_reg_class;
p2p->op_channel = p2p->cfg->op_channel;
}
@@ -1274,6 +1292,8 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
unsigned int force_freq, unsigned int pref_freq)
{
+ p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u",
+ force_freq, pref_freq);
if (force_freq || pref_freq) {
if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq) < 0)
return -1;
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 0fdad86a..b206d232 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -1836,4 +1836,15 @@ struct wpabuf * wifi_display_encaps(struct wpabuf *subelems);
int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int,
int max_disc_tu);
+/**
+ * p2p_get_state_txt - Get current P2P state for debug purposes
+ * @p2p: P2P module context from p2p_init()
+ * Returns: Name of the current P2P module state
+ *
+ * It should be noted that the P2P module state names are internal information
+ * and subject to change at any point, i.e., this information should be used
+ * mainly for debugging purposes.
+ */
+const char * p2p_get_state_txt(struct p2p_data *p2p);
+
#endif /* P2P_H */
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 4fba5501..8740ed5b 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -1094,6 +1094,14 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
p2p_parse_free(&msg);
return;
#endif /* CONFIG_P2P_STRICT */
+ } else if (dev->go_state == REMOTE_GO) {
+ int oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
+ msg.operating_channel[4]);
+ if (oper_freq != dev->oper_freq) {
+ p2p_dbg(p2p, "Updated peer (GO) operating channel preference from %d MHz to %d MHz",
+ dev->oper_freq, oper_freq);
+ dev->oper_freq = oper_freq;
+ }
}
#ifdef ANDROID_P2P
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 0da26827..deb7aa9f 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -109,6 +109,9 @@ int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel)
{
/* TODO: more operating classes */
if (freq >= 2412 && freq <= 2472) {
+ if ((freq - 2407) % 5)
+ return -1;
+
*op_class = 81; /* 2.407 GHz, channels 1..13 */
*channel = (freq - 2407) / 5;
return 0;
@@ -121,12 +124,18 @@ int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel)
}
if (freq >= 5180 && freq <= 5240) {
+ if ((freq - 5000) % 5)
+ return -1;
+
*op_class = 115; /* 5 GHz, channels 36..48 */
*channel = (freq - 5000) / 5;
return 0;
}
if (freq >= 5745 && freq <= 5805) {
+ if ((freq - 5000) % 5)
+ return -1;
+
*op_class = 124; /* 5 GHz, channels 149..161 */
*channel = (freq - 5000) / 5;
return 0;
diff --git a/src/wps/wps.c b/src/wps/wps.c
index ff4b20d6..22d7eeaa 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -497,7 +497,7 @@ struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,
wps_build_config_methods(ie, dev->config_methods) ||
wps_build_uuid_e(ie, uuid) ||
wps_build_primary_dev_type(dev, ie) ||
- wps_build_rf_bands(dev, ie) ||
+ wps_build_rf_bands(dev, ie, 0) ||
wps_build_assoc_state(NULL, ie) ||
wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
wps_build_dev_password_id(ie, pw_id) ||
@@ -640,3 +640,20 @@ int wps_attr_text(struct wpabuf *data, char *buf, char *end)
return pos - buf;
}
+
+
+const char * wps_ei_str(enum wps_error_indication ei)
+{
+ switch (ei) {
+ case WPS_EI_NO_ERROR:
+ return "No Error";
+ case WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED:
+ return "TKIP Only Prohibited";
+ case WPS_EI_SECURITY_WEP_PROHIBITED:
+ return "WEP Prohibited";
+ case WPS_EI_AUTH_FAILURE:
+ return "Authentication Failure";
+ default:
+ return "Unknown";
+ }
+}
diff --git a/src/wps/wps.h b/src/wps/wps.h
index cb03dbdc..dc82c446 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -420,6 +420,16 @@ enum wps_event {
WPS_EV_PBC_TIMEOUT,
/**
+ * WPS_EV_PBC_ACTIVE - PBC mode was activated
+ */
+ WPS_EV_PBC_ACTIVE,
+
+ /**
+ * WPS_EV_PBC_DISABLE - PBC mode was disabled
+ */
+ WPS_EV_PBC_DISABLE,
+
+ /**
* WPS_EV_ER_AP_ADD - ER: AP added
*/
WPS_EV_ER_AP_ADD,
@@ -487,11 +497,17 @@ union wps_event_data {
int msg;
u16 config_error;
u16 error_indication;
+ u8 peer_macaddr[ETH_ALEN];
} fail;
+ struct wps_event_success {
+ u8 peer_macaddr[ETH_ALEN];
+ } success;
+
struct wps_event_pwd_auth_fail {
int enrollee;
int part;
+ u8 peer_macaddr[ETH_ALEN];
} pwd_auth_fail;
struct wps_event_er_ap {
@@ -730,6 +746,13 @@ struct wps_context {
union wps_event_data *data);
/**
+ * rf_band_cb - Fetch currently used RF band
+ * @ctx: Higher layer context data (cb_ctx)
+ * Return: Current used RF band or 0 if not known
+ */
+ int (*rf_band_cb)(void *ctx);
+
+ /**
* cb_ctx: Higher layer context data for callbacks
*/
void *cb_ctx;
@@ -786,6 +809,7 @@ void wps_free_pending_msgs(struct upnp_pending_message *msgs);
struct wpabuf * wps_get_oob_cred(struct wps_context *wps);
int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr);
int wps_attr_text(struct wpabuf *data, char *buf, char *end);
+const char * wps_ei_str(enum wps_error_indication ei);
struct wps_er * wps_er_init(struct wps_context *wps, const char *ifname,
const char *filter);
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 4e4da5ec..4b431adc 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -266,7 +266,7 @@ int wps_pin_str_valid(const char *pin)
void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
- u16 config_error, u16 error_indication)
+ u16 config_error, u16 error_indication, const u8 *mac_addr)
{
union wps_event_data data;
@@ -277,20 +277,26 @@ void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
data.fail.msg = msg;
data.fail.config_error = config_error;
data.fail.error_indication = error_indication;
+ os_memcpy(data.fail.peer_macaddr, mac_addr, ETH_ALEN);
wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data);
}
-void wps_success_event(struct wps_context *wps)
+void wps_success_event(struct wps_context *wps, const u8 *mac_addr)
{
+ union wps_event_data data;
+
if (wps->event_cb == NULL)
return;
- wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL);
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.success.peer_macaddr, mac_addr, ETH_ALEN);
+ wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, &data);
}
-void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)
+void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part,
+ const u8 *mac_addr)
{
union wps_event_data data;
@@ -300,6 +306,7 @@ void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)
os_memset(&data, 0, sizeof(data));
data.pwd_auth_fail.enrollee = enrollee;
data.pwd_auth_fail.part = part;
+ os_memcpy(data.pwd_auth_fail.peer_macaddr, mac_addr, ETH_ALEN);
wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data);
}
@@ -322,6 +329,24 @@ void wps_pbc_timeout_event(struct wps_context *wps)
}
+void wps_pbc_active_event(struct wps_context *wps)
+{
+ if (wps->event_cb == NULL)
+ return;
+
+ wps->event_cb(wps->cb_ctx, WPS_EV_PBC_ACTIVE, NULL);
+}
+
+
+void wps_pbc_disable_event(struct wps_context *wps)
+{
+ if (wps->event_cb == NULL)
+ return;
+
+ wps->event_cb(wps->cb_ctx, WPS_EV_PBC_DISABLE, NULL);
+}
+
+
#ifdef CONFIG_WPS_OOB
struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h
index 2f42603a..3421ac5f 100644
--- a/src/wps/wps_defs.h
+++ b/src/wps/wps_defs.h
@@ -223,6 +223,7 @@ enum wps_error_indication {
WPS_EI_NO_ERROR,
WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED,
WPS_EI_SECURITY_WEP_PROHIBITED,
+ WPS_EI_AUTH_FAILURE,
NUM_WPS_EI_VALUES
};
diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c
index 7a7c0999..1b12b5a1 100644
--- a/src/wps/wps_dev_attr.c
+++ b/src/wps/wps_dev_attr.c
@@ -217,12 +217,13 @@ int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg)
}
-int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg)
+int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg,
+ u8 rf_band)
{
wpa_printf(MSG_DEBUG, "WPS: * RF Bands (%x)", dev->rf_bands);
wpabuf_put_be16(msg, ATTR_RF_BANDS);
wpabuf_put_be16(msg, 1);
- wpabuf_put_u8(msg, dev->rf_bands);
+ wpabuf_put_u8(msg, rf_band ? rf_band : dev->rf_bands);
return 0;
}
diff --git a/src/wps/wps_dev_attr.h b/src/wps/wps_dev_attr.h
index 200c9c45..0158cdc3 100644
--- a/src/wps/wps_dev_attr.h
+++ b/src/wps/wps_dev_attr.h
@@ -18,7 +18,8 @@ int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg);
-int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg,
+ u8 rf_band);
int wps_build_primary_dev_type(struct wps_device_data *dev,
struct wpabuf *msg);
int wps_build_secondary_dev_type(struct wps_device_data *dev,
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 27c554f3..d02ba308 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -148,7 +148,8 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps)
wps_build_config_methods(msg, config_methods) ||
wps_build_wps_state(wps, msg) ||
wps_build_device_attrs(&wps->wps->dev, msg) ||
- wps_build_rf_bands(&wps->wps->dev, msg) ||
+ wps_build_rf_bands(&wps->wps->dev, msg,
+ wps->wps->rf_band_cb(wps->wps->cb_ctx)) ||
wps_build_assoc_state(wps, msg) ||
wps_build_dev_password_id(msg, wps->dev_pw_id) ||
wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
@@ -392,7 +393,7 @@ static struct wpabuf * wps_build_wsc_done(struct wps_data *wps)
if (wps->wps->ap)
wps->state = RECV_ACK;
else {
- wps_success_event(wps->wps);
+ wps_success_event(wps->wps, wps->peer_dev.mac_addr);
wps->state = WPS_FINISHED;
}
return msg;
@@ -582,7 +583,7 @@ static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1)
wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does "
"not match with the pre-committed value");
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
- wps_pwd_auth_fail_event(wps->wps, 1, 1);
+ wps_pwd_auth_fail_event(wps->wps, 1, 1, wps->peer_dev.mac_addr);
return -1;
}
@@ -622,7 +623,7 @@ static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does "
"not match with the pre-committed value");
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
- wps_pwd_auth_fail_event(wps->wps, 1, 2);
+ wps_pwd_auth_fail_event(wps->wps, 1, 2, wps->peer_dev.mac_addr);
return -1;
}
@@ -1204,7 +1205,8 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
ret = wps_process_m4(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M4, wps->config_error,
- wps->error_indication);
+ wps->error_indication,
+ wps->peer_dev.mac_addr);
break;
case WPS_M6:
if (wps_validate_m6(msg) < 0)
@@ -1212,7 +1214,8 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
ret = wps_process_m6(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M6, wps->config_error,
- wps->error_indication);
+ wps->error_indication,
+ wps->peer_dev.mac_addr);
break;
case WPS_M8:
if (wps_validate_m8(msg) < 0)
@@ -1220,7 +1223,8 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
ret = wps_process_m8(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M8, wps->config_error,
- wps->error_indication);
+ wps->error_indication,
+ wps->peer_dev.mac_addr);
break;
default:
wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
@@ -1283,7 +1287,7 @@ static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
if (wps->state == RECV_ACK && wps->wps->ap) {
wpa_printf(MSG_DEBUG, "WPS: External Registrar registration "
"completed successfully");
- wps_success_event(wps->wps);
+ wps_success_event(wps->wps, wps->peer_dev.mac_addr);
wps->state = WPS_FINISHED;
return WPS_DONE;
}
@@ -1348,15 +1352,15 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
switch (wps->state) {
case RECV_M4:
wps_fail_event(wps->wps, WPS_M3, config_error,
- wps->error_indication);
+ wps->error_indication, wps->peer_dev.mac_addr);
break;
case RECV_M6:
wps_fail_event(wps->wps, WPS_M5, config_error,
- wps->error_indication);
+ wps->error_indication, wps->peer_dev.mac_addr);
break;
case RECV_M8:
wps_fail_event(wps->wps, WPS_M7, config_error,
- wps->error_indication);
+ wps->error_indication, wps->peer_dev.mac_addr);
break;
default:
break;
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index 413379ba..dac12508 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -134,11 +134,14 @@ void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
size_t encr_len);
void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
- u16 config_error, u16 error_indication);
-void wps_success_event(struct wps_context *wps);
-void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part);
+ u16 config_error, u16 error_indication, const u8 *mac_addr);
+void wps_success_event(struct wps_context *wps, const u8 *mac_addr);
+void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part,
+ const u8 *mac_addr);
void wps_pbc_overlap_event(struct wps_context *wps);
void wps_pbc_timeout_event(struct wps_context *wps);
+void wps_pbc_active_event(struct wps_context *wps);
+void wps_pbc_disable_event(struct wps_context *wps);
struct wpabuf * wps_build_wsc_ack(struct wps_data *wps);
struct wpabuf * wps_build_wsc_nack(struct wps_data *wps);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index d182f14f..0befca2e 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -1006,6 +1006,7 @@ int wps_registrar_button_pushed(struct wps_registrar *reg,
(u8 *) "\xff\xff\xff\xff\xff\xff");
wps_registrar_selected_registrar_changed(reg, 0);
+ wps_pbc_active_event(reg->wps);
eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wps_registrar_pbc_timeout,
@@ -1019,6 +1020,7 @@ static void wps_registrar_pbc_completed(struct wps_registrar *reg)
wpa_printf(MSG_DEBUG, "WPS: PBC completed - stopping PBC mode");
eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
wps_registrar_stop_pbc(reg);
+ wps_pbc_disable_event(reg->wps);
}
@@ -1268,7 +1270,7 @@ static int wps_set_ie(struct wps_registrar *reg)
wps_build_sel_reg_dev_password_id(reg, beacon) ||
wps_build_sel_reg_config_methods(reg, beacon) ||
wps_build_sel_pbc_reg_uuid_e(reg, beacon) ||
- (reg->dualband && wps_build_rf_bands(&reg->wps->dev, beacon)) ||
+ (reg->dualband && wps_build_rf_bands(&reg->wps->dev, beacon, 0)) ||
wps_build_wfa_ext(beacon, 0, auth_macs, count) ||
wps_build_vendor_ext(&reg->wps->dev, beacon)) {
wpabuf_free(beacon);
@@ -1298,7 +1300,7 @@ static int wps_set_ie(struct wps_registrar *reg)
wps_build_uuid_e(probe, reg->wps->uuid) ||
wps_build_device_attrs(&reg->wps->dev, probe) ||
wps_build_probe_config_methods(reg, probe) ||
- (reg->dualband && wps_build_rf_bands(&reg->wps->dev, probe)) ||
+ (reg->dualband && wps_build_rf_bands(&reg->wps->dev, probe, 0)) ||
wps_build_wfa_ext(probe, 0, auth_macs, count) ||
wps_build_vendor_ext(&reg->wps->dev, probe)) {
wpabuf_free(beacon);
@@ -1793,7 +1795,8 @@ static struct wpabuf * wps_build_m2(struct wps_data *wps)
wps_build_conn_type_flags(wps, msg) ||
wps_build_config_methods_r(wps->wps->registrar, msg) ||
wps_build_device_attrs(&wps->wps->dev, msg) ||
- wps_build_rf_bands(&wps->wps->dev, msg) ||
+ wps_build_rf_bands(&wps->wps->dev, msg,
+ wps->wps->rf_band_cb(wps->wps->cb_ctx)) ||
wps_build_assoc_state(wps, msg) ||
wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
wps_build_dev_password_id(msg, wps->dev_pw_id) ||
@@ -1834,7 +1837,8 @@ static struct wpabuf * wps_build_m2d(struct wps_data *wps)
wps_build_conn_type_flags(wps, msg) ||
wps_build_config_methods_r(wps->wps->registrar, msg) ||
wps_build_device_attrs(&wps->wps->dev, msg) ||
- wps_build_rf_bands(&wps->wps->dev, msg) ||
+ wps_build_rf_bands(&wps->wps->dev, msg,
+ wps->wps->rf_band_cb(wps->wps->cb_ctx)) ||
wps_build_assoc_state(wps, msg) ||
wps_build_config_error(msg, err) ||
wps_build_os_version(&wps->wps->dev, msg) ||
@@ -2172,7 +2176,7 @@ static int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1)
wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does "
"not match with the pre-committed value");
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
- wps_pwd_auth_fail_event(wps->wps, 0, 1);
+ wps_pwd_auth_fail_event(wps->wps, 0, 1, wps->mac_addr_e);
return -1;
}
@@ -2213,7 +2217,7 @@ static int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2)
"not match with the pre-committed value");
wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e);
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
- wps_pwd_auth_fail_event(wps->wps, 0, 2);
+ wps_pwd_auth_fail_event(wps->wps, 0, 2, wps->mac_addr_e);
return -1;
}
@@ -2565,7 +2569,7 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
wps_pbc_overlap_event(wps->wps);
wps_fail_event(wps->wps, WPS_M1,
WPS_CFG_MULTIPLE_PBC_DETECTED,
- WPS_EI_NO_ERROR);
+ WPS_EI_NO_ERROR, wps->mac_addr_e);
wps->wps->registrar->force_pbc_overlap = 1;
return WPS_CONTINUE;
}
@@ -2895,7 +2899,7 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
ret = wps_process_m3(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M3, wps->config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
break;
case WPS_M5:
if (wps_validate_m5(msg) < 0)
@@ -2903,7 +2907,7 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
ret = wps_process_m5(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M5, wps->config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
break;
case WPS_M7:
if (wps_validate_m7(msg) < 0)
@@ -2911,7 +2915,7 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
ret = wps_process_m7(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M7, wps->config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
break;
default:
wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
@@ -3057,19 +3061,19 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
switch (old_state) {
case RECV_M3:
wps_fail_event(wps->wps, WPS_M2, config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
break;
case RECV_M5:
wps_fail_event(wps->wps, WPS_M4, config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
break;
case RECV_M7:
wps_fail_event(wps->wps, WPS_M6, config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
break;
case RECV_DONE:
wps_fail_event(wps->wps, WPS_M8, config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
break;
default:
break;
@@ -3190,7 +3194,7 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
/* TODO: maintain AuthorizedMACs somewhere separately for each ER and
* merge them into APs own list.. */
- wps_success_event(wps->wps);
+ wps_success_event(wps->wps, wps->mac_addr_e);
return WPS_DONE;
}
@@ -3259,7 +3263,7 @@ enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
wps->state = SEND_WSC_NACK;
wps_fail_event(wps->wps, WPS_WSC_DONE,
wps->config_error,
- wps->error_indication);
+ wps->error_indication, wps->mac_addr_e);
}
return ret;
default:
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index c48a2865..2950d2d1 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -14,6 +14,7 @@
#include "utils/uuid.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "eapol_supp/eapol_supp_sm.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
#include "ap/ap_drv_ops.h"
@@ -51,18 +52,12 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
- if (ssid->frequency == 0) {
- /* default channel 11 */
- conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
- conf->channel = 11;
- } else {
- conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
- &conf->channel);
- if (conf->hw_mode == NUM_HOSTAPD_MODES) {
- wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: "
- "%d MHz", ssid->frequency);
- return -1;
- }
+ conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
+ &conf->channel);
+ if (conf->hw_mode == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
+ ssid->frequency);
+ return -1;
}
/* TODO: enable HT40 if driver supports it;
@@ -461,6 +456,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
params.mode = IEEE80211_MODE_AP;
break;
}
+ if (ssid->frequency == 0)
+ ssid->frequency = 2462; /* default channel 11 */
params.freq = ssid->frequency;
params.wpa_proto = ssid->proto;
@@ -586,6 +583,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
hapd_iface->bss[0]->drv_priv = wpa_s->drv_priv;
wpa_s->current_ssid = ssid;
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
wpa_s->assoc_freq = ssid->frequency;
@@ -609,6 +607,7 @@ void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s)
return;
wpa_s->current_ssid = NULL;
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_s->assoc_freq = 0;
#ifdef CONFIG_P2P
if (wpa_s->ap_iface->bss)
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index fb3eacc5..55f6a060 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -5939,7 +5939,6 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
#ifdef ANDROID_P2P
"LIST_NETWORKS",
"SAVE_CONFIG",
- "STATUS",
#endif
"P2P_FIND",
"P2P_STOP_FIND",
@@ -6038,6 +6037,102 @@ static char * wpas_global_ctrl_iface_redir(struct wpa_global *global,
}
+static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd)
+{
+ char *value;
+
+ value = os_strchr(cmd, ' ');
+ if (value == NULL)
+ return -1;
+ *value++ = '\0';
+
+ wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value);
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (os_strcasecmp(cmd, "wifi_display") == 0) {
+ wifi_display_enable(global, !!atoi(value));
+ return 0;
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ return -1;
+}
+
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+static int wpas_global_ctrl_iface_save_config(struct wpa_global *global)
+{
+ int ret = 0;
+ struct wpa_supplicant *wpa_s;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (!wpa_s->conf->update_config) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)");
+ continue;
+ }
+
+ if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration");
+ ret = 1;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated");
+ }
+ }
+
+ return ret;
+}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+
+static int wpas_global_ctrl_iface_status(struct wpa_global *global,
+ char *buf, size_t buflen)
+{
+ char *pos, *end;
+ int ret;
+ struct wpa_supplicant *wpa_s;
+
+ pos = buf;
+ end = buf + buflen;
+
+#ifdef CONFIG_P2P
+ if (global->p2p && !global->p2p_disabled) {
+ ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
+ "\n"
+ "p2p_state=%s\n",
+ MAC2STR(global->p2p_dev_addr),
+ p2p_get_state_txt(global->p2p));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ } else if (global->p2p) {
+ ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WIFI_DISPLAY
+ ret = os_snprintf(pos, end - pos, "wifi_display=%d\n",
+ !!global->wifi_display);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ ret = os_snprintf(pos, end - pos, "ifname=%s\n"
+ "address=" MACSTR "\n",
+ wpa_s->ifname, MAC2STR(wpa_s->own_addr));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
char *buf, size_t *resp_len)
{
@@ -6095,6 +6190,17 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
wpas_notify_suspend(global);
} else if (os_strcmp(buf, "RESUME") == 0) {
wpas_notify_resume(global);
+ } else if (os_strncmp(buf, "SET ", 4) == 0) {
+ if (wpas_global_ctrl_iface_set(global, buf + 4))
+ reply_len = -1;
+#ifndef CONFIG_NO_CONFIG_WRITE
+ } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
+ if (wpas_global_ctrl_iface_save_config(global))
+ reply_len = -1;
+#endif /* CONFIG_NO_CONFIG_WRITE */
+ } else if (os_strcmp(buf, "STATUS") == 0) {
+ reply_len = wpas_global_ctrl_iface_status(global, reply,
+ reply_size);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index f3b660d0..8c09ba13 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -80,14 +80,14 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
while (dst) {
if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
from->sin_port == dst->addr.sin_port) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
+ "%s:%d", inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port));
if (prev == NULL)
priv->ctrl_dst = dst->next;
else
prev->next = dst->next;
os_free(dst);
- wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
- "%s:%d", inet_ntoa(from->sin_addr),
- ntohs(from->sin_port));
return 0;
}
prev = dst;
@@ -331,13 +331,13 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
eloop_unregister_read_sock(priv->sock);
if (priv->ctrl_dst) {
/*
- * Wait a second before closing the control socket if
+ * Wait before closing the control socket if
* there are any attached monitors in order to allow
* them to receive any pending messages.
*/
wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
"monitors to receive messages");
- os_sleep(1, 0);
+ os_sleep(0, 100000);
}
close(priv->sock);
priv->sock = -1;
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index fc0d649e..e35d2c39 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -94,12 +94,12 @@ static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst,
os_memcmp(from->sun_path, dst->addr.sun_path,
fromlen - offsetof(struct sockaddr_un, sun_path))
== 0) {
- dl_list_del(&dst->list);
- os_free(dst);
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
(u8 *) from->sun_path,
fromlen -
offsetof(struct sockaddr_un, sun_path));
+ dl_list_del(&dst->list);
+ os_free(dst);
return 0;
}
}
@@ -150,7 +150,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
return;
}
buf[res] = '\0';
@@ -327,7 +328,8 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "Using existing control "
"interface directory.");
} else {
- perror("mkdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "mkdir[ctrl_interface=%s]: %s",
+ dir, strerror(errno));
goto fail;
}
}
@@ -371,7 +373,8 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
}
if (gid_set && chown(dir, -1, gid) < 0) {
- perror("chown[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+ dir, (int) gid, strerror(errno));
goto fail;
}
@@ -391,7 +394,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
if (priv->sock < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
goto fail;
}
@@ -413,15 +416,15 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
" allow connections - assuming it was left"
"over from forced program termination");
if (unlink(fname) < 0) {
- perror("unlink[ctrl_iface]");
- wpa_printf(MSG_ERROR, "Could not unlink "
- "existing ctrl_iface socket '%s'",
- fname);
+ wpa_printf(MSG_ERROR,
+ "Could not unlink existing ctrl_iface socket '%s': %s",
+ fname, strerror(errno));
goto fail;
}
if (bind(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("supp-ctrl-iface-init: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "supp-ctrl-iface-init: bind(PF_UNIX): %s",
+ strerror(errno));
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -438,12 +441,14 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
}
if (gid_set && chown(fname, -1, gid) < 0) {
- perror("chown[ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+ fname, (int) gid, strerror(errno));
goto fail;
}
if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
- perror("chmod[ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR, "chmod[ctrl_interface=%s]: %s",
+ fname, strerror(errno));
goto fail;
}
os_free(fname);
@@ -460,7 +465,8 @@ havesock:
if (flags >= 0) {
flags |= O_NONBLOCK;
if (fcntl(priv->sock, F_SETFL, flags) < 0) {
- perror("fcntl(ctrl, O_NONBLOCK)");
+ wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
+ strerror(errno));
/* Not fatal, continue on.*/
}
}
@@ -495,13 +501,13 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
eloop_unregister_read_sock(priv->sock);
if (!dl_list_empty(&priv->ctrl_dst)) {
/*
- * Wait a second before closing the control socket if
+ * Wait before closing the control socket if
* there are any attached monitors in order to allow
* them to receive any pending messages.
*/
wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
"monitors to receive messages");
- os_sleep(1, 0);
+ os_sleep(0, 100000);
}
close(priv->sock);
priv->sock = -1;
@@ -530,7 +536,9 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
"directory not empty - leaving it "
"behind");
} else {
- perror("rmdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR,
+ "rmdir[ctrl_interface=%s]: %s",
+ dir, strerror(errno));
}
}
os_free(buf);
@@ -638,7 +646,8 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
continue;
}
buf[res] = '\0';
@@ -681,7 +690,8 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
return;
}
buf[res] = '\0';
@@ -722,6 +732,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
struct ctrl_iface_global_priv *priv;
struct sockaddr_un addr;
const char *ctrl = global->params.ctrl_interface;
+ int flags;
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
@@ -766,7 +777,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
if (priv->sock < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
goto fail;
}
@@ -783,7 +794,8 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) <
0) {
wpa_printf(MSG_ERROR, "supp-global-ctrl-iface-init: "
- "bind(PF_UNIX) failed: %s", strerror(errno));
+ "bind(PF_UNIX;%s) failed: %s",
+ ctrl, strerror(errno));
goto fail;
}
wpa_printf(MSG_DEBUG, "Using Abstract control socket '%s'",
@@ -793,23 +805,23 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
os_strlcpy(addr.sun_path, ctrl, sizeof(addr.sun_path));
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("supp-global-ctrl-iface-init (will try fixup): "
- "bind(PF_UNIX)");
+ wpa_printf(MSG_INFO, "supp-global-ctrl-iface-init(%s) (will try fixup): bind(PF_UNIX): %s",
+ ctrl, strerror(errno));
if (connect(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
" allow connections - assuming it was left"
"over from forced program termination");
if (unlink(ctrl) < 0) {
- perror("unlink[ctrl_iface]");
- wpa_printf(MSG_ERROR, "Could not unlink "
- "existing ctrl_iface socket '%s'",
- ctrl);
+ wpa_printf(MSG_ERROR,
+ "Could not unlink existing ctrl_iface socket '%s': %s",
+ ctrl, strerror(errno));
goto fail;
}
if (bind(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("supp-glb-iface-init: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "supp-glb-iface-init: bind(PF_UNIX;%s): %s",
+ ctrl, strerror(errno));
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -851,12 +863,16 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
(int) gid);
}
if (chown(ctrl, -1, gid) < 0) {
- perror("chown[global_ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR,
+ "chown[global_ctrl_interface=%s,gid=%d]: %s",
+ ctrl, (int) gid, strerror(errno));
goto fail;
}
if (chmod(ctrl, S_IRWXU | S_IRWXG) < 0) {
- perror("chmod[global_ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR,
+ "chmod[global_ctrl_interface=%s]: %s",
+ ctrl, strerror(errno));
goto fail;
}
} else {
@@ -864,6 +880,21 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
}
havesock:
+
+ /*
+ * Make socket non-blocking so that we don't hang forever if
+ * target dies unexpectedly.
+ */
+ flags = fcntl(priv->sock, F_GETFL);
+ if (flags >= 0) {
+ flags |= O_NONBLOCK;
+ if (fcntl(priv->sock, F_SETFL, flags) < 0) {
+ wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
+ strerror(errno));
+ /* Not fatal, continue on.*/
+ }
+ }
+
eloop_register_read_sock(priv->sock,
wpa_supplicant_global_ctrl_iface_receive,
global, priv);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 7c0d2e8f..d77e96b7 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -190,6 +190,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
wpa_s->ap_ies_from_associnfo = 0;
wpa_s->current_ssid = NULL;
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_s->key_mgmt = 0;
}
@@ -337,10 +338,24 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
#ifndef CONFIG_NO_SCAN_PROCESSING
+
+static int has_wep_key(struct wpa_ssid *ssid)
+{
+ int i;
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i])
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
struct wpa_ssid *ssid)
{
- int i, privacy = 0;
+ int privacy = 0;
if (ssid->mixed_cell)
return 1;
@@ -350,12 +365,9 @@ static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
return 1;
#endif /* CONFIG_WPS */
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (ssid->wep_key_len[i]) {
- privacy = 1;
- break;
- }
- }
+ if (has_wep_key(ssid))
+ privacy = 1;
+
#ifdef IEEE8021X_EAPOL
if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
@@ -821,6 +833,12 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
continue;
}
+ if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
+ has_wep_key(ssid)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - ignore WPA/WPA2 AP for WEP network block");
+ continue;
+ }
+
if (!wpa_supplicant_match_privacy(bss, ssid)) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy "
"mismatch");
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 62d68b8b..b694bdec 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - IBSS RSN
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "common/wpa_ctrl.h"
#include "l2_packet/l2_packet.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/wpa_ie.h"
@@ -114,6 +115,22 @@ static int supp_get_beacon_ie(void *ctx)
}
+static void ibss_check_rsn_completed(struct ibss_rsn_peer *peer)
+{
+ struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s;
+
+ if ((peer->authentication_status &
+ (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH)) !=
+ (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH))
+ return;
+ if (peer->authentication_status & IBSS_RSN_REPORTED_PTK)
+ return;
+ peer->authentication_status |= IBSS_RSN_REPORTED_PTK;
+ wpa_msg(wpa_s, MSG_INFO, IBSS_RSN_COMPLETED MACSTR,
+ MAC2STR(peer->addr));
+}
+
+
static int supp_set_key(void *ctx, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
@@ -128,6 +145,8 @@ static int supp_set_key(void *ctx, enum wpa_alg alg,
wpa_hexdump_key(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
if (key_idx == 0) {
+ peer->authentication_status |= IBSS_RSN_SET_PTK_SUPP;
+ ibss_check_rsn_completed(peer);
/*
* In IBSS RSN, the pairwise key from the 4-way handshake
* initiated by the peer with highest MAC address is used.
@@ -281,6 +300,15 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
if (idx == 0) {
+ if (addr) {
+ struct ibss_rsn_peer *peer;
+ peer = ibss_rsn_get_peer(ibss_rsn, addr);
+ if (peer) {
+ peer->authentication_status |=
+ IBSS_RSN_SET_PTK_AUTH;
+ ibss_check_rsn_completed(peer);
+ }
+ }
/*
* In IBSS RSN, the pairwise key from the 4-way handshake
* initiated by the peer with highest MAC address is used.
diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h
index 5a8eda4b..6b89f7a9 100644
--- a/wpa_supplicant/ibss_rsn.h
+++ b/wpa_supplicant/ibss_rsn.h
@@ -19,6 +19,12 @@ struct ibss_rsn;
#define IBSS_RSN_AUTH_BY_US 0x02
/* we sent an EAPOL message */
#define IBSS_RSN_AUTH_EAPOL_BY_US 0x04
+/* PTK derived as supplicant */
+#define IBSS_RSN_SET_PTK_SUPP 0x08
+/* PTK derived as authenticator */
+#define IBSS_RSN_SET_PTK_AUTH 0x10
+/* PTK completion reported */
+#define IBSS_RSN_REPORTED_PTK 0x20
struct ibss_rsn_peer {
struct ibss_rsn_peer *next;
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index e0395949..0827f354 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1058,6 +1058,7 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
d->pbc_in_m1 = s->pbc_in_m1;
d->ignore_old_scan_res = s->ignore_old_scan_res;
d->beacon_int = s->beacon_int;
+ d->disassoc_low_ack = s->disassoc_low_ack;
}
@@ -1237,7 +1238,13 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
if (wpa_s->p2p_go_ht40)
res->ht40 = 1;
- wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS "role=%s "
+ "freq=%d ht40=%d peer_dev=" MACSTR " peer_iface=" MACSTR
+ " wps_method=%s",
+ res->role_go ? "GO" : "client", res->freq, res->ht40,
+ MAC2STR(res->peer_device_addr),
+ MAC2STR(res->peer_interface_addr),
+ p2p_wps_method_text(res->wps_method));
wpas_notify_p2p_go_neg_completed(wpa_s, res);
if (res->role_go && wpa_s->p2p_persistent_id >= 0) {
@@ -3894,6 +3901,9 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
num = get_shared_radio_freqs(wpa_s, freqs,
wpa_s->num_multichan_concurrent);
+ wpa_printf(MSG_DEBUG,
+ "P2P: Setup freqs: freq=%d num_MCC=%d shared_freqs=%u",
+ freq, wpa_s->num_multichan_concurrent, num);
if (freq > 0) {
if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
@@ -4186,7 +4196,11 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
while (wpa_s) {
prev = wpa_s;
wpa_s = wpa_s->next;
- wpas_p2p_disconnect(prev);
+ if (prev->p2p_group_interface !=
+ NOT_P2P_GROUP_INTERFACE ||
+ (prev->current_ssid &&
+ prev->current_ssid->p2p_group))
+ wpas_p2p_disconnect(prev);
}
return 0;
}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 9b6cd466..a0f51d0c 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -266,17 +266,13 @@ wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
int interval)
{
int ret;
-#ifndef ANDROID_P2P
+
wpa_supplicant_notify_scanning(wpa_s, 1);
-#endif
ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000);
if (ret)
wpa_supplicant_notify_scanning(wpa_s, 0);
else {
wpa_s->sched_scanning = 1;
-#ifdef ANDROID_P2P
- wpa_supplicant_notify_scanning(wpa_s, 1);
-#endif
}
return ret;
@@ -1048,11 +1044,9 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
sizeof(struct wpa_driver_scan_filter));
prev_state = wpa_s->wpa_state;
-#ifndef ANDROID_P2P
if (wpa_s->wpa_state == WPA_DISCONNECTED ||
wpa_s->wpa_state == WPA_INACTIVE)
wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
-#endif
if (wpa_s->autoscan_params != NULL) {
scan_params = wpa_s->autoscan_params;
@@ -1264,12 +1258,7 @@ void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
int scanning)
{
if (wpa_s->scanning != scanning) {
-#ifdef ANDROID_P2P
- if(!wpa_s->sched_scanning)
- wpa_s->scanning = scanning;
-#else
wpa_s->scanning = scanning;
-#endif
wpas_notify_scanning(wpa_s);
}
}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 35ecfea3..caab28b3 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1933,8 +1933,10 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
return;
}
- if (ssid)
+ if (ssid) {
wpa_s->current_ssid = ssid;
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ }
wpa_s->connect_without_scan = NULL;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 8e0207cb..b855dbd0 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -567,11 +567,13 @@ static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
}
-static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = {
- "No Error", /* WPS_EI_NO_ERROR */
- "TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */
- "WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */
-};
+static void wpas_wps_clear_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ wpa_printf(MSG_DEBUG, "WPS: Clear WPS network from timeout");
+ wpas_clear_wps(wpa_s);
+}
+
static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail)
@@ -581,13 +583,13 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO,
WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
fail->msg, fail->config_error, fail->error_indication,
- wps_event_fail_reason[fail->error_indication]);
+ wps_ei_str(fail->error_indication));
if (wpa_s->parent && wpa_s->parent != wpa_s)
wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
"msg=%d config_error=%d reason=%d (%s)",
fail->msg, fail->config_error,
fail->error_indication,
- wps_event_fail_reason[fail->error_indication]);
+ wps_ei_str(fail->error_indication));
} else {
wpa_msg(wpa_s, MSG_INFO,
WPS_EVENT_FAIL "msg=%d config_error=%d",
@@ -597,7 +599,14 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
"msg=%d config_error=%d",
fail->msg, fail->config_error);
}
- wpas_clear_wps(wpa_s);
+
+ /*
+ * Need to allow WPS processing to complete, e.g., by sending WSC_NACK.
+ */
+ wpa_printf(MSG_DEBUG, "WPS: Register timeout to clear WPS network");
+ eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
+ eloop_register_timeout(0, 100000, wpas_wps_clear_timeout, wpa_s, NULL);
+
wpas_notify_wps_event_fail(wpa_s, fail);
#ifdef CONFIG_P2P
wpas_p2p_wps_failed(wpa_s, fail);
@@ -813,6 +822,12 @@ static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
break;
case WPS_EV_PBC_TIMEOUT:
break;
+ case WPS_EV_PBC_ACTIVE:
+ wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ACTIVE);
+ break;
+ case WPS_EV_PBC_DISABLE:
+ wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_DISABLE);
+ break;
case WPS_EV_ER_AP_ADD:
wpa_supplicant_wps_event_er_ap_add(wpa_s, &data->ap);
break;
@@ -841,6 +856,17 @@ static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
}
+static int wpa_supplicant_wps_rf_band(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (!wpa_s->current_ssid || !wpa_s->assoc_freq)
+ return 0;
+
+ return (wpa_s->assoc_freq > 2484) ? WPS_RF_50GHZ : WPS_RF_24GHZ;
+}
+
+
enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid)
{
if (eap_is_wps_pbc_enrollee(&ssid->eap) ||
@@ -1312,6 +1338,7 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
wps->cred_cb = wpa_supplicant_wps_cred;
wps->event_cb = wpa_supplicant_wps_event;
+ wps->rf_band_cb = wpa_supplicant_wps_rf_band;
wps->cb_ctx = wpa_s;
wps->dev.device_name = wpa_s->conf->device_name;
@@ -1385,6 +1412,7 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
{
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
wpas_wps_clear_ap_info(wpa_s);