diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2013-08-26 12:09:05 -0700 |
---|---|---|
committer | Dmitry Shmidt <dimitrysh@google.com> | 2013-08-26 12:09:05 -0700 |
commit | b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15 (patch) | |
tree | 5c3debc3660836db47e9d01a3801a3587e74446b | |
parent | 0c18dcd2bd94644d9215995225c076d146d6ad82 (diff) | |
download | wpa_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>
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(®->wps->dev, beacon)) || + (reg->dualband && wps_build_rf_bands(®->wps->dev, beacon, 0)) || wps_build_wfa_ext(beacon, 0, auth_macs, count) || wps_build_vendor_ext(®->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(®->wps->dev, probe) || wps_build_probe_config_methods(reg, probe) || - (reg->dualband && wps_build_rf_bands(®->wps->dev, probe)) || + (reg->dualband && wps_build_rf_bands(®->wps->dev, probe, 0)) || wps_build_wfa_ext(probe, 0, auth_macs, count) || wps_build_vendor_ext(®->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); |