aboutsummaryrefslogtreecommitdiffstats
path: root/src/ap
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 /src/ap
parent0c18dcd2bd94644d9215995225c076d146d6ad82 (diff)
downloadandroid_external_wpa_supplicant_8-b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15.tar.gz
android_external_wpa_supplicant_8-b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15.tar.bz2
android_external_wpa_supplicant_8-b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15.zip
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>
Diffstat (limited to 'src/ap')
-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
6 files changed, 271 insertions, 79 deletions
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));