diff options
| author | Dmitry Shmidt <dimitrysh@google.com> | 2015-03-05 14:16:04 -0800 |
|---|---|---|
| committer | Dmitry Shmidt <dimitrysh@google.com> | 2015-03-10 11:04:48 -0700 |
| commit | 203eadb9eda41a1dde4a583edb4684319e3f399e (patch) | |
| tree | 3b91f63844f16aeca8e1e122ef4c6d49f8164b17 /src | |
| parent | 34c1202b3e71c63661a850aad81f663e40e48ca1 (diff) | |
| download | android_external_wpa_supplicant_8-203eadb9eda41a1dde4a583edb4684319e3f399e.tar.gz android_external_wpa_supplicant_8-203eadb9eda41a1dde4a583edb4684319e3f399e.tar.bz2 android_external_wpa_supplicant_8-203eadb9eda41a1dde4a583edb4684319e3f399e.zip | |
Cumulative patch from commit 6e9023ea499ea9a89b0e858c85e32b455d57264c
6e9023e DFS: Allow wpa_supplicant AP mode to use non-offloaded DFS
02e42ab nl80211: Add vendor event parsing for DFS offload events
bd0f68c DFS: wpa_supplicant event processing
d7f1aa8 DFS offload: P2P changes for autonomous GO
1e2aaff DFS offload: Indicate AP-CSA-FINISHED for DFS offloaded case
c13578c DFS offload: Add main DFS handler for offloaded case
5de81d7 DFS offload: Skip user space processing for CAC operations
192ad3d Interworking: Clear SCANNING state if no match found
95d7b86 P2P: Consider 5 GHz channels also for auto GO
a51c40a P2P: Fix regression in start-GO/AP through a "fake" scan
dd5c155 eap_proxy: Callback to notify any updates from eap_proxy
9a05d98 atheros: Add a new flag for OSEN support
9feadba Remove unnecessary NULL check to make function more consistent
1772d34 P2P: Fix interface deinit for failed group interface initialization
3f9ebc4 P2P: Allow AP/GO interface to be started while P2P-in-progress
b4a9292 RADIUS client: Fix server failover on return-to-primary on error case
9836cb5 Add option to force a specific RADIUS client address to be used
1a7ed38 RADIUS client: Fix a copy-paste error in accounting server failover
de7c06e P2P: Continue find in GO-Neg-Resp-fail status corner cases
c280590 Do not add blacklist entries based on normal disconnect request cases
bdf0518 P2P: Direct P2P_CONNECT command to proper interface
44b9ea5 P2P: Do not allow scan or normal association on cfg80211 P2P Device
9542f21 Clean up p2p_find command parsing and execution
fa9f381 P2P: Allow a specific channel to be specified in P2P_FIND
eb78a8d P2P: Restore P2P_SCAN_SPECIFIC
d988ff7 hostapd: Disable VHT caps for STAs when no valid VHT MCS found
70fd828 RADIUS client: Fix previous failover change
c3dabf5 Fix merge issue with IBSS VHT support
8b2b718 Fix minor issue in HT40 max rate determination
347c55e RADIUS client: Re-try connection if socket is closed on retransmit
94b39e5 RADIUS client: Fix server connection recovery after initial failure
bbee36e Allow RADIUS server address to be replaced
efb4008 TLS: Remove placeholders for SIGN_ALG_DSA support
Change-Id: I8e5d0dfd5fddb6de2f8d8211b708c3bb6674098b
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/ap/dfs.c | 85 | ||||
| -rw-r--r-- | src/ap/dfs.h | 4 | ||||
| -rw-r--r-- | src/ap/drv_callbacks.c | 26 | ||||
| -rw-r--r-- | src/ap/hostapd.c | 31 | ||||
| -rw-r--r-- | src/ap/ieee802_11_vht.c | 44 | ||||
| -rw-r--r-- | src/common/ieee802_11_common.c | 7 | ||||
| -rw-r--r-- | src/common/ieee802_11_common.h | 1 | ||||
| -rw-r--r-- | src/drivers/driver_atheros.c | 2 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211.c | 3 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211_event.c | 93 | ||||
| -rw-r--r-- | src/eap_peer/eap.h | 8 | ||||
| -rw-r--r-- | src/eapol_supp/eapol_supp_sm.c | 14 | ||||
| -rw-r--r-- | src/eapol_supp/eapol_supp_sm.h | 8 | ||||
| -rw-r--r-- | src/p2p/p2p.c | 23 | ||||
| -rw-r--r-- | src/p2p/p2p.h | 10 | ||||
| -rw-r--r-- | src/radius/radius_client.c | 157 | ||||
| -rw-r--r-- | src/tls/tlsv1_client_write.c | 30 | ||||
| -rw-r--r-- | src/tls/tlsv1_common.c | 23 | ||||
| -rw-r--r-- | src/tls/tlsv1_server_read.c | 30 | ||||
| -rw-r--r-- | src/utils/utils_module_tests.c | 159 |
20 files changed, 638 insertions, 120 deletions
diff --git a/src/ap/dfs.c b/src/ap/dfs.c index fc8d7adf..da6fd464 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -1,7 +1,7 @@ /* * DFS - Dynamic Frequency Selection * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> - * Copyright (c) 2013, Qualcomm Atheros, Inc. + * Copyright (c) 2013-2015, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -748,11 +748,19 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, if (success) { /* Complete iface/ap configuration */ - set_dfs_state(iface, freq, ht_enabled, chan_offset, - chan_width, cf1, cf2, - HOSTAPD_CHAN_DFS_AVAILABLE); - iface->cac_started = 0; - hostapd_setup_interface_complete(iface, 0); + if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) { + /* Complete AP configuration for the first bring up. */ + if (iface->state != HAPD_IFACE_ENABLED) + hostapd_setup_interface_complete(iface, 0); + else + iface->cac_started = 0; + } else { + set_dfs_state(iface, freq, ht_enabled, chan_offset, + chan_width, cf1, cf2, + HOSTAPD_CHAN_DFS_AVAILABLE); + iface->cac_started = 0; + hostapd_setup_interface_complete(iface, 0); + } } return 0; @@ -934,13 +942,17 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, { int res; - if (!iface->conf->ieee80211h) - return 0; - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", freq, ht_enabled, chan_offset, chan_width, cf1, cf2); + /* Proceed only if DFS is not offloaded to the driver */ + if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) + return 0; + + if (!iface->conf->ieee80211h) + return 0; + /* mark radar frequency as invalid */ set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE); @@ -964,6 +976,11 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", freq, ht_enabled, chan_offset, chan_width, cf1, cf2); + + /* Proceed only if DFS is not offloaded to the driver */ + if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) + return 0; + /* TODO add correct implementation here */ set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); @@ -995,3 +1012,53 @@ int hostapd_is_dfs_required(struct hostapd_iface *iface) res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1); return res; } + + +int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq, + int ht_enabled, int chan_offset, int chan_width, + int cf1, int cf2) +{ + wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START + "freq=%d chan=%d chan_offset=%d width=%d seg0=%d " + "seg1=%d cac_time=%ds", + freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60); + iface->cac_started = 1; + return 0; +} + + +/* + * Main DFS handler for offloaded case. + * 2 - continue channel/AP setup for non-DFS channel + * 1 - continue channel/AP setup for DFS channel + * 0 - channel/AP setup will be continued after CAC + * -1 - hit critical error + */ +int hostapd_handle_dfs_offload(struct hostapd_iface *iface) +{ + wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d", + __func__, iface->cac_started); + + /* + * If DFS has already been started, then we are being called from a + * callback to continue AP/channel setup. Reset the CAC start flag and + * return. + */ + if (iface->cac_started) { + wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d", + __func__, iface->cac_started); + iface->cac_started = 0; + return 1; + } + + if (ieee80211_is_dfs(iface->freq)) { + wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS", + __func__, iface->freq); + return 0; + } + + wpa_printf(MSG_DEBUG, + "%s: freq %d MHz does not require DFS. Continue channel/AP setup", + __func__, iface->freq); + return 2; +} diff --git a/src/ap/dfs.h b/src/ap/dfs.h index a619c55c..be8c0e60 100644 --- a/src/ap/dfs.h +++ b/src/ap/dfs.h @@ -22,5 +22,9 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, int ht_enabled, int chan_offset, int chan_width, int cf1, int cf2); int hostapd_is_dfs_required(struct hostapd_iface *iface); +int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq, + int ht_enabled, int chan_offset, int chan_width, + int cf1, int cf2); +int hostapd_handle_dfs_offload(struct hostapd_iface *iface); #endif /* DFS_H */ diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index c39989c3..a0adc67d 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -439,7 +439,7 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, int offset, int width, int cf1, int cf2) { #ifdef NEED_AP_MLME - int channel, chwidth, seg0_idx = 0, seg1_idx = 0; + int channel, chwidth, seg0_idx = 0, seg1_idx = 0, is_dfs; hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, @@ -497,13 +497,18 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx; hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx; + is_dfs = ieee80211_is_dfs(freq); + if (hapd->csa_in_progress && freq == hapd->cs_freq_params.freq) { hostapd_cleanup_cs_params(hapd); ieee802_11_set_beacon(hapd); - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED "freq=%d", - freq); + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED + "freq=%d dfs=%d", freq, is_dfs); + } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) { + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED + "freq=%d dfs=%d", freq, is_dfs); } #endif /* NEED_AP_MLME */ } @@ -1032,6 +1037,16 @@ static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd, radar->cf1, radar->cf2); } + +static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd, + struct dfs_event *radar) +{ + wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq); + hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled, + radar->chan_offset, radar->chan_width, + radar->cf1, radar->cf2); +} + #endif /* NEED_AP_MLME */ @@ -1207,6 +1222,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, hostapd_channel_list_updated( hapd->iface, data->channel_list_changed.initiator); break; + case EVENT_DFS_CAC_STARTED: + if (!data) + break; + hostapd_event_dfs_cac_started(hapd, &data->dfs_event); + break; #endif /* NEED_AP_MLME */ case EVENT_INTERFACE_ENABLED: wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED); diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index e641b129..f6019ac2 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1377,6 +1377,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) size_t j; u8 *prev_addr; int delay_apply_cfg = 0; + int res_dfs_offload = 0; if (err) goto fail; @@ -1403,6 +1404,23 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) goto fail; return res; } + } else { + /* If DFS is offloaded to the driver */ + res_dfs_offload = hostapd_handle_dfs_offload(iface); + if (res_dfs_offload <= 0) { + if (res_dfs_offload < 0) + goto fail; + } else { + wpa_printf(MSG_DEBUG, + "Proceed with AP/channel setup"); + /* + * If this is a DFS channel, move to completing + * AP setup. + */ + if (res_dfs_offload == 1) + goto dfs_offload; + /* Otherwise fall through. */ + } } #endif /* NEED_AP_MLME */ @@ -1497,6 +1515,19 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) goto fail; } + if ((iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) && + !res_dfs_offload) { + /* + * If freq is DFS, and DFS is offloaded to the driver, then wait + * for CAC to complete. + */ + wpa_printf(MSG_DEBUG, "%s: Wait for CAC to complete", __func__); + return res_dfs_offload; + } + +#ifdef NEED_AP_MLME +dfs_offload: +#endif /* NEED_AP_MLME */ hostapd_set_state(iface, HAPD_IFACE_ENABLED); wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED); if (hapd->setup_complete_cb) diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c index 159693f6..171538ad 100644 --- a/src/ap/ieee802_11_vht.c +++ b/src/ap/ieee802_11_vht.c @@ -90,13 +90,55 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid) } +static int check_valid_vht_mcs(struct hostapd_hw_modes *mode, + const u8 *sta_vht_capab) +{ + const struct ieee80211_vht_capabilities *vht_cap; + struct ieee80211_vht_capabilities ap_vht_cap; + u16 sta_rx_mcs_set, ap_tx_mcs_set; + int i; + + if (!mode) + return 1; + + /* + * Disable VHT caps for STAs for which there is not even a single + * allowed MCS in any supported number of streams, i.e., STA is + * advertising 3 (not supported) as VHT MCS rates for all supported + * stream cases. + */ + os_memcpy(&ap_vht_cap.vht_supported_mcs_set, mode->vht_mcs_set, + sizeof(ap_vht_cap.vht_supported_mcs_set)); + vht_cap = (const struct ieee80211_vht_capabilities *) sta_vht_capab; + + /* AP Tx MCS map vs. STA Rx MCS map */ + sta_rx_mcs_set = le_to_host16(vht_cap->vht_supported_mcs_set.rx_map); + ap_tx_mcs_set = le_to_host16(ap_vht_cap.vht_supported_mcs_set.tx_map); + + for (i = 0; i < VHT_RX_NSS_MAX_STREAMS; i++) { + if ((ap_tx_mcs_set & (0x3 << (i * 2))) == 3) + continue; + + if ((sta_rx_mcs_set & (0x3 << (i * 2))) == 3) + continue; + + return 1; + } + + wpa_printf(MSG_DEBUG, + "No matching VHT MCS found between AP TX and STA RX"); + return 0; +} + + u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta, const u8 *vht_capab, size_t vht_capab_len) { /* Disable VHT caps for STAs associated to no-VHT BSSes. */ if (!vht_capab || vht_capab_len < sizeof(struct ieee80211_vht_capabilities) || - hapd->conf->disable_11ac) { + hapd->conf->disable_11ac || + !check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) { sta->flags &= ~WLAN_STA_VHT; os_free(sta->vht_capabilities); sta->vht_capabilities = NULL; diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index ed8d4661..aca0b732 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -826,6 +826,13 @@ int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan) } +int ieee80211_is_dfs(int freq) +{ + /* TODO: this could be more accurate to better cover all domains */ + return (freq >= 5260 && freq <= 5320) || (freq >= 5500 && freq <= 5700); +} + + static int is_11b(u8 rate) { return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16; diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index 05fe32b4..7f0b296d 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -108,6 +108,7 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[], const char *name, const char *val); enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel); int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan); +int ieee80211_is_dfs(int freq); int supp_rates_11b_only(struct ieee802_11_elems *elems); diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c index 350d5059..f4644216 100644 --- a/src/drivers/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -1810,7 +1810,7 @@ static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params) wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies", params->assocresp_ies); -#if defined(CONFIG_HS20) && defined(IEEE80211_PARAM_OSEN) +#if defined(CONFIG_HS20) && (defined(IEEE80211_PARAM_OSEN) || defined(CONFIG_ATHEROS_OSEN)) if (params->osen) { struct wpa_bss_params bss_params; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 2dce242a..2a2ef6f1 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -4301,7 +4301,8 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv, return -1; } - if (nl80211_set_channel(drv->first_bss, ¶ms->freq, 0)) { + if (params->freq.freq && + nl80211_set_channel(drv->first_bss, ¶ms->freq, 0)) { if (old_mode != nlmode) wpa_driver_nl80211_set_mode(drv->first_bss, old_mode); nl80211_remove_monitor_interface(drv); diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 6a7b509e..b59d1390 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -1531,6 +1531,92 @@ static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv, } +static void qca_nl80211_dfs_offload_radar_event( + struct wpa_driver_nl80211_data *drv, u32 subcmd, u8 *msg, int length) +{ + union wpa_event_data data; + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + + wpa_printf(MSG_DEBUG, + "nl80211: DFS offload radar vendor event received"); + + if (nla_parse(tb, NL80211_ATTR_MAX, + (struct nlattr *) msg, length, NULL)) + return; + + if (!tb[NL80211_ATTR_WIPHY_FREQ]) { + wpa_printf(MSG_INFO, + "nl80211: Error parsing WIPHY_FREQ in FS offload radar vendor event"); + return; + } + + os_memset(&data, 0, sizeof(data)); + data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); + + wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz", + data.dfs_event.freq); + + /* Check HT params */ + if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { + data.dfs_event.ht_enabled = 1; + data.dfs_event.chan_offset = 0; + + switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) { + case NL80211_CHAN_NO_HT: + data.dfs_event.ht_enabled = 0; + break; + case NL80211_CHAN_HT20: + break; + case NL80211_CHAN_HT40PLUS: + data.dfs_event.chan_offset = 1; + break; + case NL80211_CHAN_HT40MINUS: + data.dfs_event.chan_offset = -1; + break; + } + } + + /* Get VHT params */ + if (tb[NL80211_ATTR_CHANNEL_WIDTH]) + data.dfs_event.chan_width = + convert2width(nla_get_u32( + tb[NL80211_ATTR_CHANNEL_WIDTH])); + if (tb[NL80211_ATTR_CENTER_FREQ1]) + data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]); + if (tb[NL80211_ATTR_CENTER_FREQ2]) + data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]); + + wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, " + "offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz", + data.dfs_event.freq, data.dfs_event.ht_enabled, + data.dfs_event.chan_offset, data.dfs_event.chan_width, + data.dfs_event.cf1, data.dfs_event.cf2); + + switch (subcmd) { + case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: + wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data); + break; + case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED: + wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_STARTED, &data); + break; + case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED: + wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data); + break; + case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED: + wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data); + break; + case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED: + wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data); + break; + default: + wpa_printf(MSG_DEBUG, + "nl80211: Unknown DFS offload radar event %d received", + subcmd); + break; + } +} + + static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, u32 subcmd, u8 *data, size_t len) { @@ -1547,6 +1633,13 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, case QCA_NL80211_VENDOR_SUBCMD_DO_ACS: qca_nl80211_acs_select_ch(drv, data, len); break; + case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED: + case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED: + case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED: + case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED: + case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: + qca_nl80211_dfs_offload_radar_event(drv, subcmd, data, len); + break; default: wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported QCA vendor event %u", diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h index 8c4a42f6..702463b9 100644 --- a/src/eap_peer/eap.h +++ b/src/eap_peer/eap.h @@ -246,6 +246,14 @@ struct eapol_callbacks { void (*notify_status)(void *ctx, const char *status, const char *parameter); +#ifdef CONFIG_EAP_PROXY + /** + * eap_proxy_cb - Callback signifying any updates from eap_proxy + * @ctx: eapol_ctx from eap_peer_sm_init() call + */ + void (*eap_proxy_cb)(void *ctx); +#endif /* CONFIG_EAP_PROXY */ + /** * set_anon_id - Set or add anonymous identity * @ctx: eapol_ctx from eap_peer_sm_init() call diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c index f6150512..9cc234a8 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -1977,6 +1977,17 @@ static void eapol_sm_notify_status(void *ctx, const char *status, } +#ifdef CONFIG_EAP_PROXY +static void eapol_sm_eap_proxy_cb(void *ctx) +{ + struct eapol_sm *sm = ctx; + + if (sm->ctx->eap_proxy_cb) + sm->ctx->eap_proxy_cb(sm->ctx->ctx); +} +#endif /* CONFIG_EAP_PROXY */ + + static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len) { struct eapol_sm *sm = ctx; @@ -2000,6 +2011,9 @@ static struct eapol_callbacks eapol_cb = eapol_sm_eap_param_needed, eapol_sm_notify_cert, eapol_sm_notify_status, +#ifdef CONFIG_EAP_PROXY + eapol_sm_eap_proxy_cb, +#endif /* CONFIG_EAP_PROXY */ eapol_sm_set_anon_id }; diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h index 03341a30..1309ff75 100644 --- a/src/eapol_supp/eapol_supp_sm.h +++ b/src/eapol_supp/eapol_supp_sm.h @@ -271,6 +271,14 @@ struct eapol_ctx { void (*status_cb)(void *ctx, const char *status, const char *parameter); +#ifdef CONFIG_EAP_PROXY + /** + * eap_proxy_cb - Callback signifying any updates from eap_proxy + * @ctx: eapol_ctx from eap_peer_sm_init() call + */ + void (*eap_proxy_cb)(void *ctx); +#endif /* CONFIG_EAP_PROXY */ + /** * set_anon_id - Set or add anonymous identity * @ctx: eapol_ctx from eap_peer_sm_init() call diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index d62874ec..6adb3dc2 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1147,7 +1147,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, enum p2p_discovery_type type, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id, unsigned int search_delay, - u8 seek_count, const char **seek) + u8 seek_count, const char **seek, int freq) { int res; @@ -1230,6 +1230,19 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, p2p, NULL); switch (type) { case P2P_FIND_START_WITH_FULL: + if (freq > 0) { + /* + * Start with the specified channel and then move to + * social channels only scans. + */ + res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, + P2P_SCAN_SPECIFIC, freq, + p2p->num_req_dev_types, + p2p->req_dev_types, dev_id, + DEV_PW_DEFAULT); + break; + } + /* fall through */ case P2P_FIND_PROGRESSIVE: res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0, p2p->num_req_dev_types, @@ -3508,13 +3521,19 @@ static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success, p2p_dbg(p2p, "GO Negotiation Response (failure) TX callback: success=%d", success); if (p2p->go_neg_peer && p2p->go_neg_peer->status != P2P_SC_SUCCESS) { p2p_go_neg_failed(p2p, p2p->go_neg_peer->status); - } else if (success) { + return; + } + + if (success) { struct p2p_device *dev; dev = p2p_get_device(p2p, addr); if (dev && dev->status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE; } + + if (p2p->state == P2P_SEARCH || p2p->state == P2P_SD_DURING_FIND) + p2p_continue_find(p2p); } diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index b1c89d71..2402db6a 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -245,6 +245,7 @@ struct p2p_data; enum p2p_scan_type { P2P_SCAN_SOCIAL, P2P_SCAN_FULL, + P2P_SCAN_SPECIFIC, P2P_SCAN_SOCIAL_PLUS_ONE }; @@ -545,7 +546,8 @@ struct p2p_config { * operation to be completed. Type type argument specifies which type * of scan is to be done. @P2P_SCAN_SOCIAL indicates that only the * social channels (1, 6, 11) should be scanned. @P2P_SCAN_FULL - * indicates that all channels are to be scanned. + * indicates that all channels are to be scanned. @P2P_SCAN_SPECIFIC + * request a scan of a single channel specified by freq. * @P2P_SCAN_SOCIAL_PLUS_ONE request scan of all the social channels * plus one extra channel specified by freq. * @@ -1129,13 +1131,17 @@ enum p2p_discovery_type { * @search_delay: Extra delay in milliseconds between search iterations * @seek_count: Number of ASP Service Strings in the seek_string array * @seek_string: ASP Service Strings to query for in Probe Requests + * @freq: Requested first scan frequency (in MHz) to modify type == + * P2P_FIND_START_WITH_FULL behavior. 0 = Use normal full scan. + * If p2p_find is already in progress, this parameter is ignored and full + * scan will be executed. * Returns: 0 on success, -1 on failure */ int p2p_find(struct p2p_data *p2p, unsigned int timeout, enum p2p_discovery_type type, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id, unsigned int search_delay, - u8 seek_count, const char **seek_string); + u8 seek_count, const char **seek_string, int freq); /** * p2p_notify_scan_trigger_status - Indicate scan trigger status diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c index 34f56853..693f61ea 100644 --- a/src/radius/radius_client.c +++ b/src/radius/radius_client.c @@ -1,6 +1,6 @@ /* * RADIUS client - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -236,6 +236,8 @@ radius_change_server(struct radius_client_data *radius, int sock, int sock6, int auth); static int radius_client_init_acct(struct radius_client_data *radius); static int radius_client_init_auth(struct radius_client_data *radius); +static void radius_client_auth_failover(struct radius_client_data *radius); +static void radius_client_acct_failover(struct radius_client_data *radius); static void radius_client_msg_free(struct radius_msg_list *req) @@ -304,7 +306,7 @@ static int radius_client_handle_send_error(struct radius_client_data *radius, { #ifndef CONFIG_NATIVE_WINDOWS int _errno = errno; - wpa_printf(MSG_INFO, "send[RADIUS]: %s", strerror(errno)); + wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno)); if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL || _errno == EBADF || _errno == ENETUNREACH) { hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, @@ -333,9 +335,18 @@ static int radius_client_retransmit(struct radius_client_data *radius, struct hostapd_radius_servers *conf = radius->conf; int s; struct wpabuf *buf; + size_t prev_num_msgs; if (entry->msg_type == RADIUS_ACCT || entry->msg_type == RADIUS_ACCT_INTERIM) { + if (radius->acct_sock < 0) + radius_client_init_acct(radius); + if (radius->acct_sock < 0 && conf->num_acct_servers > 1) { + prev_num_msgs = radius->num_msgs; + radius_client_acct_failover(radius); + if (prev_num_msgs != radius->num_msgs) + return 0; + } s = radius->acct_sock; if (entry->attempts == 0) conf->acct_server->requests++; @@ -344,6 +355,14 @@ static int radius_client_retransmit(struct radius_client_data *radius, conf->acct_server->retransmissions++; } } else { + if (radius->auth_sock < 0) + radius_client_init_auth(radius); + if (radius->auth_sock < 0 && conf->num_auth_servers > 1) { + prev_num_msgs = radius->num_msgs; + radius_client_auth_failover(radius); + if (prev_num_msgs != radius->num_msgs) + return 0; + } s = radius->auth_sock; if (entry->attempts == 0) conf->auth_server->requests++; @@ -352,6 +371,11 @@ static int radius_client_retransmit(struct radius_client_data *radius, conf->auth_server->retransmissions++; } } + if (s < 0) { + wpa_printf(MSG_INFO, + "RADIUS: No valid socket for retransmission"); + return 1; + } /* retransmit; remove entry if too many attempts */ entry->attempts++; @@ -388,7 +412,6 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) os_time_t first; struct radius_msg_list *entry, *prev, *tmp; int auth_failover = 0, acct_failover = 0; - char abuf[50]; size_t prev_num_msgs; int s; @@ -453,54 +476,70 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) (long int) (first - now.sec)); } - if (auth_failover && conf->num_auth_servers > 1) { - struct hostapd_radius_server *next, *old; - old = conf->auth_server; - hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_NOTICE, - "No response from Authentication server " - "%s:%d - failover", - hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)), - old->port); - - for (entry = radius->msgs; entry; entry = entry->next) { - if (entry->msg_type == RADIUS_AUTH) - old->timeouts++; - } + if (auth_failover && conf->num_auth_servers > 1) + radius_client_auth_failover(radius); + + if (acct_failover && conf->num_acct_servers > 1) + radius_client_acct_failover(radius); +} + + +static void radius_client_auth_failover(struct radius_client_data *radius) +{ + struct hostapd_radius_servers *conf = radius->conf; + struct hostapd_radius_server *next, *old; + struct radius_msg_list *entry; + char abuf[50]; + + old = conf->auth_server; + hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, + HOSTAPD_LEVEL_NOTICE, + "No response from Authentication server %s:%d - failover", + hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)), + old->port); - next = old + 1; - if (next > &(conf->auth_servers[conf->num_auth_servers - 1])) - next = conf->auth_servers; - conf->auth_server = next; - radius_change_server(radius, next, old, - radius->auth_serv_sock, - radius->auth_serv_sock6, 1); + for (entry = radius->msgs; entry; entry = entry->next) { + if (entry->msg_type == RADIUS_AUTH) + old->timeouts++; } - if (acct_failover && conf->num_acct_servers > 1) { - struct hostapd_radius_server *next, *old; - old = conf->acct_server; - hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, - HOSTAPD_LEVEL_NOTICE, - "No response from Accounting server " - "%s:%d - failover", - hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)), - old->port); + next = old + 1; + if (next > &(conf->auth_servers[conf->num_auth_servers - 1])) + next = conf->auth_servers; + conf->auth_server = next; + radius_change_server(radius, next, old, + radius->auth_serv_sock, + radius->auth_serv_sock6, 1); +} - for (entry = radius->msgs; entry; entry = entry->next) { - if (entry->msg_type == RADIUS_ACCT || - entry->msg_type == RADIUS_ACCT_INTERIM) - old->timeouts++; - } - next = old + 1; - if (next > &conf->acct_servers[conf->num_acct_servers - 1]) - next = conf->acct_servers; - conf->acct_server = next; - radius_change_server(radius, next, old, - radius->acct_serv_sock, - radius->acct_serv_sock6, 0); +static void radius_client_acct_failover(struct radius_client_data *radius) +{ + struct hostapd_radius_servers *conf = radius->conf; + struct hostapd_radius_server *next, *old; + struct radius_msg_list *entry; + char abuf[50]; + + old = conf->acct_server; + hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, + HOSTAPD_LEVEL_NOTICE, + "No response from Accounting server %s:%d - failover", + hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)), + old->port); + + for (entry = radius->msgs; entry; entry = entry->next) { + if (entry->msg_type == RADIUS_ACCT || + entry->msg_type == RADIUS_ACCT_INTERIM) + old->timeouts++; } + + next = old + 1; + if (next > &conf->acct_servers[conf->num_acct_servers - 1]) + next = conf->acct_servers; + conf->acct_server = next; + radius_change_server(radius, next, old, + radius->acct_serv_sock, + radius->acct_serv_sock6, 0); } @@ -658,6 +697,9 @@ int radius_client_send(struct radius_client_data *radius, } if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) { + if (conf->acct_server && radius->acct_sock < 0) + radius_client_init_acct(radius); + if (conf->acct_server == NULL || radius->acct_sock < 0 || conf->acct_server->shared_secret == NULL) { hostapd_logger(radius->ctx, NULL, @@ -673,6 +715,9 @@ int radius_client_send(struct radius_client_data *radius, s = radius->acct_sock; conf->acct_server->requests++; } else { + if (conf->auth_server && radius->auth_sock < 0) + radius_client_init_auth(radius); + if (conf->auth_server == NULL || radius->auth_sock < 0 || conf->auth_server->shared_secret == NULL) { hostapd_logger(radius->ctx, NULL, @@ -1131,18 +1176,28 @@ static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx) conf->auth_server != conf->auth_servers) { oserv = conf->auth_server; conf->auth_server = conf->auth_servers; - radius_change_server(radius, conf->auth_server, oserv, - radius->auth_serv_sock, - radius->auth_serv_sock6, 1); + if (radius_change_server(radius, conf->auth_server, oserv, + radius->auth_serv_sock, + radius->auth_serv_sock6, 1) < 0) { + conf->auth_server = oserv; + radius_change_server(radius, oserv, conf->auth_server, + radius->auth_serv_sock, + radius->auth_serv_sock6, 1); + } } if (radius->acct_sock >= 0 && conf->acct_servers && conf->acct_server != conf->acct_servers) { oserv = conf->acct_server; conf->acct_server = conf->acct_servers; - radius_change_server(radius, conf->acct_server, oserv, - radius->acct_serv_sock, - radius->acct_serv_sock6, 0); + if (radius_change_server(radius, conf->acct_server, oserv, + radius->acct_serv_sock, + radius->acct_serv_sock6, 0) < 0) { + conf->acct_server = oserv; + radius_change_server(radius, oserv, conf->acct_server, + radius->acct_serv_sock, + radius->acct_serv_sock6, 0); + } } if (conf->retry_primary_interval) diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c index 839eb90a..d192f44f 100644 --- a/src/tls/tlsv1_client_write.c +++ b/src/tls/tlsv1_client_write.c @@ -432,7 +432,6 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn, u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start; size_t rlen, hlen, clen; u8 hash[100], *hpos; - enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; pos = *msgpos; @@ -505,21 +504,17 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn, } else { #endif /* CONFIG_TLSV12 */ - if (alg == SIGN_ALG_RSA) { - hlen = MD5_MAC_LEN; - if (conn->verify.md5_cert == NULL || - crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) - { - tls_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - conn->verify.md5_cert = NULL; - crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL); - conn->verify.sha1_cert = NULL; - return -1; - } - hpos += MD5_MAC_LEN; - } else - crypto_hash_finish(conn->verify.md5_cert, NULL, NULL); + hlen = MD5_MAC_LEN; + if (conn->verify.md5_cert == NULL || + crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) { + tls_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + conn->verify.md5_cert = NULL; + crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL); + conn->verify.sha1_cert = NULL; + return -1; + } + hpos += MD5_MAC_LEN; conn->verify.md5_cert = NULL; hlen = SHA1_MAC_LEN; @@ -532,8 +527,7 @@ static int tls_write_client_certificate_verify(struct tlsv1_client *conn, } conn->verify.sha1_cert = NULL; - if (alg == SIGN_ALG_RSA) - hlen += MD5_MAC_LEN; + hlen += MD5_MAC_LEN; #ifdef CONFIG_TLSV12 } diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c index ced28cff..dabc12a1 100644 --- a/src/tls/tlsv1_common.c +++ b/src/tls/tlsv1_common.c @@ -366,23 +366,20 @@ int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random, { u8 *hpos; size_t hlen; - enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; struct crypto_hash *ctx; hpos = hash; - if (alg == SIGN_ALG_RSA) { - ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0); - if (ctx == NULL) - return -1; - crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN); - crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN); - crypto_hash_update(ctx, server_params, server_params_len); - hlen = MD5_MAC_LEN; - if (crypto_hash_finish(ctx, hash, &hlen) < 0) - return -1; - hpos += hlen; - } + ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0); + if (ctx == NULL) + return -1; + crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN); + crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN); + crypto_hash_update(ctx, server_params, server_params_len); + hlen = MD5_MAC_LEN; + if (crypto_hash_finish(ctx, hash, &hlen) < 0) + return -1; + hpos += hlen; ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0); if (ctx == NULL) diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c index 310966c2..0f237baf 100644 --- a/src/tls/tlsv1_server_read.c +++ b/src/tls/tlsv1_server_read.c @@ -775,7 +775,6 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct, u8 type; size_t hlen; u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos; - enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; u8 alert; if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) { @@ -883,21 +882,17 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct, } else { #endif /* CONFIG_TLSV12 */ - if (alg == SIGN_ALG_RSA) { - hlen = MD5_MAC_LEN; - if (conn->verify.md5_cert == NULL || - crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) - { - tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, - TLS_ALERT_INTERNAL_ERROR); - conn->verify.md5_cert = NULL; - crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL); - conn->verify.sha1_cert = NULL; - return -1; - } - hpos += MD5_MAC_LEN; - } else - crypto_hash_finish(conn->verify.md5_cert, NULL, NULL); + hlen = MD5_MAC_LEN; + if (conn->verify.md5_cert == NULL || + crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) { + tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_INTERNAL_ERROR); + conn->verify.md5_cert = NULL; + crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL); + conn->verify.sha1_cert = NULL; + return -1; + } + hpos += MD5_MAC_LEN; conn->verify.md5_cert = NULL; hlen = SHA1_MAC_LEN; @@ -910,8 +905,7 @@ static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct, } conn->verify.sha1_cert = NULL; - if (alg == SIGN_ALG_RSA) - hlen += MD5_MAC_LEN; + hlen += MD5_MAC_LEN; #ifdef CONFIG_TLSV12 } diff --git a/src/utils/utils_module_tests.c b/src/utils/utils_module_tests.c index 9a9ec400..4b97dadd 100644 --- a/src/utils/utils_module_tests.c +++ b/src/utils/utils_module_tests.c @@ -1,6 +1,6 @@ /* * utils module tests - * Copyright (c) 2014, Jouni Malinen <j@w1.fi> + * Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -12,6 +12,7 @@ #include "utils/bitfield.h" #include "utils/ext_password.h" #include "utils/trace.h" +#include "utils/base64.h" struct printf_test_data { @@ -84,6 +85,15 @@ static int printf_encode_decode_tests(void) } } + if (printf_decode(bin, 3, "abcde") != 2) + errors++; + + if (printf_decode(bin, 3, "\\xa") != 1 || bin[0] != 10) + errors++; + + if (printf_decode(bin, 3, "\\a") != 1 || bin[0] != 'a') + errors++; + if (errors) { wpa_printf(MSG_ERROR, "%d printf test(s) failed", errors); return -1; @@ -167,6 +177,17 @@ static int bitfield_tests(void) bitfield_free(bf); + bf = bitfield_alloc(8); + if (bf == NULL) + return -1; + if (bitfield_get_first_zero(bf) != 0) + errors++; + for (i = 0; i < 8; i++) + bitfield_set(bf, i); + if (bitfield_get_first_zero(bf) != -1) + errors++; + bitfield_free(bf); + if (errors) { wpa_printf(MSG_ERROR, "%d bitfield test(s) failed", errors); return -1; @@ -249,6 +270,140 @@ static int trace_tests(void) } +static int base64_tests(void) +{ + int errors = 0; + unsigned char *res; + size_t res_len; + + wpa_printf(MSG_INFO, "base64 tests"); + + res = base64_encode((const unsigned char *) "", ~0, &res_len); + if (res) { + errors++; + os_free(res); + } + + res = base64_encode((const unsigned char *) "=", 1, &res_len); + if (!res || res_len != 5 || res[0] != 'P' || res[1] != 'Q' || + res[2] != '=' || res[3] != '=' || res[4] != '\n') + errors++; + os_free(res); + + res = base64_encode((const unsigned char *) "=", 1, NULL); + if (!res || res[0] != 'P' || res[1] != 'Q' || + res[2] != '=' || res[3] != '=' || res[4] != '\n') + errors++; + os_free(res); + + res = base64_decode((const unsigned char *) "", 0, &res_len); + if (res) { + errors++; + os_free(res); + } + + res = base64_decode((const unsigned char *) "a", 1, &res_len); + if (res) { + errors++; + os_free(res); + } + + res = base64_decode((const unsigned char *) "====", 4, &res_len); + if (res) { + errors++; + os_free(res); + } + + res = base64_decode((const unsigned char *) "PQ==", 4, &res_len); + if (!res || res_len != 1 || res[0] != '=') + errors++; + os_free(res); + + res = base64_decode((const unsigned char *) "P.Q-=!=*", 8, &res_len); + if (!res || res_len != 1 || res[0] != '=') + errors++; + os_free(res); + + if (errors) { + wpa_printf(MSG_ERROR, "%d base64 test(s) failed", errors); + return -1; + } + + return 0; +} + + +static int common_tests(void) +{ + char buf[3]; + u8 addr[ETH_ALEN] = { 1, 2, 3, 4, 5, 6 }; + u8 bin[3]; + int errors = 0; + struct wpa_freq_range_list ranges; + + wpa_printf(MSG_INFO, "common tests"); + + if (hwaddr_mask_txt(buf, 3, addr, addr) != -1) + errors++; + + if (wpa_scnprintf(buf, 0, "hello") != 0 || + wpa_scnprintf(buf, 3, "hello") != 2) + errors++; + + if (wpa_snprintf_hex(buf, 0, addr, ETH_ALEN) != 0 || + wpa_snprintf_hex(buf, 3, addr, ETH_ALEN) != 2) + errors++; + + if (merge_byte_arrays(bin, 3, addr, ETH_ALEN, NULL, 0) != 3 || + merge_byte_arrays(bin, 3, NULL, 0, addr, ETH_ALEN) != 3) + errors++; + + if (dup_binstr(NULL, 0) != NULL) + errors++; + + if (freq_range_list_includes(NULL, 0) != 0) + errors++; + + os_memset(&ranges, 0, sizeof(ranges)); + if (freq_range_list_parse(&ranges, "") != 0 || + freq_range_list_includes(&ranges, 0) != 0 || + freq_range_list_str(&ranges) != NULL) + errors++; + + if (utf8_unescape(NULL, 0, buf, sizeof(buf)) != 0 || + utf8_unescape("a", 1, NULL, 0) != 0 || + utf8_unescape("a\\", 2, buf, sizeof(buf)) != 0 || + utf8_unescape("abcde", 5, buf, sizeof(buf)) != 0 || + utf8_unescape("abc", 3, buf, 3) != 3) + errors++; + + if (utf8_unescape("a", 0, buf, sizeof(buf)) != 1 || buf[0] != 'a') + errors++; + + if (utf8_unescape("\\b", 2, buf, sizeof(buf)) != 1 || buf[0] != 'b') + errors++; + + if (utf8_escape(NULL, 0, buf, sizeof(buf)) != 0 || + utf8_escape("a", 1, NULL, 0) != 0 || + utf8_escape("abcde", 5, buf, sizeof(buf)) != 0 || + utf8_escape("a\\bcde", 6, buf, sizeof(buf)) != 0 || + utf8_escape("ab\\cde", 6, buf, sizeof(buf)) != 0 || + utf8_escape("abc\\de", 6, buf, sizeof(buf)) != 0 || + utf8_escape("abc", 3, buf, 3) != 3) + errors++; + + if (utf8_escape("a", 0, buf, sizeof(buf)) != 1 || buf[0] != 'a') + errors++; + + if (errors) { + wpa_printf(MSG_ERROR, "%d common test(s) failed", errors); + return -1; + } + + return 0; +} + + int utils_module_tests(void) { int ret = 0; @@ -259,6 +414,8 @@ int utils_module_tests(void) ext_password_tests() < 0 || trace_tests() < 0 || bitfield_tests() < 0 || + base64_tests() < 0 || + common_tests() < 0 || int_array_tests() < 0) ret = -1; |
