diff --git a/packages/extras-buildpkgs/hostapd-realtek/debian/patches/realtek.patch b/packages/extras-buildpkgs/hostapd-realtek/debian/patches/realtek.patch index 7ab81a060f..c4cc7ecda8 100644 --- a/packages/extras-buildpkgs/hostapd-realtek/debian/patches/realtek.patch +++ b/packages/extras-buildpkgs/hostapd-realtek/debian/patches/realtek.patch @@ -11,6 +11,7 @@ index 6c7406a..07dda78 100644 "User space daemon for IEEE 802.11 AP management,\n" "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" "Copyright (c) 2002-2015, Jouni Malinen " +diff --git a/hostapd/main.c.orig b/hostapd/main.c.orig new file mode 100644 index 0000000..6c7406a --- /dev/null @@ -835,8 +836,1267 @@ index 5fe8fd5..5f7c077 100644 + hapd->conf->wmm_enabled = 1; + #endif /* CONFIG_IEEE80211N */ - + tailpos = hostapd_eid_ext_capab(hapd, tailpos); +diff --git a/src/ap/beacon.c.orig b/src/ap/beacon.c.orig +new file mode 100644 +index 0000000..5fe8fd5 +--- /dev/null ++++ b/src/ap/beacon.c.orig +@@ -0,0 +1,1253 @@ ++/* ++ * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response ++ * Copyright (c) 2002-2004, Instant802 Networks, Inc. ++ * Copyright (c) 2005-2006, Devicescape Software, Inc. ++ * Copyright (c) 2008-2012, Jouni Malinen ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ */ ++ ++#include "utils/includes.h" ++ ++#ifndef CONFIG_NATIVE_WINDOWS ++ ++#include "utils/common.h" ++#include "common/ieee802_11_defs.h" ++#include "common/ieee802_11_common.h" ++#include "common/hw_features_common.h" ++#include "wps/wps_defs.h" ++#include "p2p/p2p.h" ++#include "hostapd.h" ++#include "ieee802_11.h" ++#include "wpa_auth.h" ++#include "wmm.h" ++#include "ap_config.h" ++#include "sta_info.h" ++#include "p2p_hostapd.h" ++#include "ap_drv_ops.h" ++#include "beacon.h" ++#include "hs20.h" ++#include "dfs.h" ++ ++ ++#ifdef NEED_AP_MLME ++ ++static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid, ++ size_t len) ++{ ++ if (!hapd->conf->radio_measurements || len < 2 + 4) ++ return eid; ++ ++ *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES; ++ *eid++ = 5; ++ *eid++ = (hapd->conf->radio_measurements & BIT(0)) ? ++ WLAN_RRM_CAPS_NEIGHBOR_REPORT : 0x00; ++ *eid++ = 0x00; ++ *eid++ = 0x00; ++ *eid++ = 0x00; ++ *eid++ = 0x00; ++ return eid; ++} ++ ++ ++static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len) ++{ ++ if (len < 2 + 5) ++ return eid; ++ ++#ifdef CONFIG_TESTING_OPTIONS ++ if (hapd->conf->bss_load_test_set) { ++ *eid++ = WLAN_EID_BSS_LOAD; ++ *eid++ = 5; ++ os_memcpy(eid, hapd->conf->bss_load_test, 5); ++ eid += 5; ++ return eid; ++ } ++#endif /* CONFIG_TESTING_OPTIONS */ ++ if (hapd->conf->bss_load_update_period) { ++ *eid++ = WLAN_EID_BSS_LOAD; ++ *eid++ = 5; ++ WPA_PUT_LE16(eid, hapd->num_sta); ++ eid += 2; ++ *eid++ = hapd->iface->channel_utilization; ++ WPA_PUT_LE16(eid, 0); /* no available admission capabity */ ++ eid += 2; ++ } ++ return eid; ++} ++ ++ ++static u8 ieee802_11_erp_info(struct hostapd_data *hapd) ++{ ++ u8 erp = 0; ++ ++ if (hapd->iface->current_mode == NULL || ++ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) ++ return 0; ++ ++ if (hapd->iface->olbc) ++ erp |= ERP_INFO_USE_PROTECTION; ++ if (hapd->iface->num_sta_non_erp > 0) { ++ erp |= ERP_INFO_NON_ERP_PRESENT | ++ ERP_INFO_USE_PROTECTION; ++ } ++ if (hapd->iface->num_sta_no_short_preamble > 0 || ++ hapd->iconf->preamble == LONG_PREAMBLE) ++ erp |= ERP_INFO_BARKER_PREAMBLE_MODE; ++ ++ return erp; ++} ++ ++ ++static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid) ++{ ++ *eid++ = WLAN_EID_DS_PARAMS; ++ *eid++ = 1; ++ *eid++ = hapd->iconf->channel; ++ return eid; ++} ++ ++ ++static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid) ++{ ++ if (hapd->iface->current_mode == NULL || ++ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) ++ return eid; ++ ++ /* Set NonERP_present and use_protection bits if there ++ * are any associated NonERP stations. */ ++ /* TODO: use_protection bit can be set to zero even if ++ * there are NonERP stations present. This optimization ++ * might be useful if NonERP stations are "quiet". ++ * See 802.11g/D6 E-1 for recommended practice. ++ * In addition, Non ERP present might be set, if AP detects Non ERP ++ * operation on other APs. */ ++ ++ /* Add ERP Information element */ ++ *eid++ = WLAN_EID_ERP_INFO; ++ *eid++ = 1; ++ *eid++ = ieee802_11_erp_info(hapd); ++ ++ return eid; ++} ++ ++ ++static u8 * hostapd_eid_pwr_constraint(struct hostapd_data *hapd, u8 *eid) ++{ ++ u8 *pos = eid; ++ u8 local_pwr_constraint = 0; ++ int dfs; ++ ++ if (hapd->iface->current_mode == NULL || ++ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) ++ return eid; ++ ++ /* Let host drivers add this IE if DFS support is offloaded */ ++ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) ++ return eid; ++ ++ /* ++ * There is no DFS support and power constraint was not directly ++ * requested by config option. ++ */ ++ if (!hapd->iconf->ieee80211h && ++ hapd->iconf->local_pwr_constraint == -1) ++ return eid; ++ ++ /* Check if DFS is required by regulatory. */ ++ dfs = hostapd_is_dfs_required(hapd->iface); ++ if (dfs < 0) { ++ wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d", ++ dfs); ++ dfs = 0; ++ } ++ ++ if (dfs == 0 && hapd->iconf->local_pwr_constraint == -1) ++ return eid; ++ ++ /* ++ * ieee80211h (DFS) is enabled so Power Constraint element shall ++ * be added when running on DFS channel whenever local_pwr_constraint ++ * is configured or not. In order to meet regulations when TPC is not ++ * implemented using a transmit power that is below the legal maximum ++ * (including any mitigation factor) should help. In this case, ++ * indicate 3 dB below maximum allowed transmit power. ++ */ ++ if (hapd->iconf->local_pwr_constraint == -1) ++ local_pwr_constraint = 3; ++ ++ /* ++ * A STA that is not an AP shall use a transmit power less than or ++ * equal to the local maximum transmit power level for the channel. ++ * The local maximum transmit power can be calculated from the formula: ++ * local max TX pwr = max TX pwr - local pwr constraint ++ * Where max TX pwr is maximum transmit power level specified for ++ * channel in Country element and local pwr constraint is specified ++ * for channel in this Power Constraint element. ++ */ ++ ++ /* Element ID */ ++ *pos++ = WLAN_EID_PWR_CONSTRAINT; ++ /* Length */ ++ *pos++ = 1; ++ /* Local Power Constraint */ ++ if (local_pwr_constraint) ++ *pos++ = local_pwr_constraint; ++ else ++ *pos++ = hapd->iconf->local_pwr_constraint; ++ ++ return pos; ++} ++ ++ ++static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing, ++ struct hostapd_channel_data *start, ++ struct hostapd_channel_data *prev) ++{ ++ if (end - pos < 3) ++ return pos; ++ ++ /* first channel number */ ++ *pos++ = start->chan; ++ /* number of channels */ ++ *pos++ = (prev->chan - start->chan) / chan_spacing + 1; ++ /* maximum transmit power level */ ++ *pos++ = start->max_tx_power; ++ ++ return pos; ++} ++ ++ ++static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, ++ int max_len) ++{ ++ u8 *pos = eid; ++ u8 *end = eid + max_len; ++ int i; ++ struct hostapd_hw_modes *mode; ++ struct hostapd_channel_data *start, *prev; ++ int chan_spacing = 1; ++ ++ if (!hapd->iconf->ieee80211d || max_len < 6 || ++ hapd->iface->current_mode == NULL) ++ return eid; ++ ++ *pos++ = WLAN_EID_COUNTRY; ++ pos++; /* length will be set later */ ++ os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */ ++ pos += 3; ++ ++ mode = hapd->iface->current_mode; ++ if (mode->mode == HOSTAPD_MODE_IEEE80211A) ++ chan_spacing = 4; ++ ++ start = prev = NULL; ++ for (i = 0; i < mode->num_channels; i++) { ++ struct hostapd_channel_data *chan = &mode->channels[i]; ++ if (chan->flag & HOSTAPD_CHAN_DISABLED) ++ continue; ++ if (start && prev && ++ prev->chan + chan_spacing == chan->chan && ++ start->max_tx_power == chan->max_tx_power) { ++ prev = chan; ++ continue; /* can use same entry */ ++ } ++ ++ if (start && prev) { ++ pos = hostapd_eid_country_add(pos, end, chan_spacing, ++ start, prev); ++ start = NULL; ++ } ++ ++ /* Start new group */ ++ start = prev = chan; ++ } ++ ++ if (start) { ++ pos = hostapd_eid_country_add(pos, end, chan_spacing, ++ start, prev); ++ } ++ ++ if ((pos - eid) & 1) { ++ if (end - pos < 1) ++ return eid; ++ *pos++ = 0; /* pad for 16-bit alignment */ ++ } ++ ++ eid[1] = (pos - eid) - 2; ++ ++ return pos; ++} ++ ++ ++static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len) ++{ ++ const u8 *ie; ++ size_t ielen; ++ ++ ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen); ++ if (ie == NULL || ielen > len) ++ return eid; ++ ++ os_memcpy(eid, ie, ielen); ++ return eid + ielen; ++} ++ ++ ++static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid) ++{ ++ u8 chan; ++ ++ if (!hapd->cs_freq_params.freq) ++ return eid; ++ ++ if (ieee80211_freq_to_chan(hapd->cs_freq_params.freq, &chan) == ++ NUM_HOSTAPD_MODES) ++ return eid; ++ ++ *eid++ = WLAN_EID_CHANNEL_SWITCH; ++ *eid++ = 3; ++ *eid++ = hapd->cs_block_tx; ++ *eid++ = chan; ++ *eid++ = hapd->cs_count; ++ ++ return eid; ++} ++ ++ ++static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid) ++{ ++ u8 sec_ch; ++ ++ if (!hapd->cs_freq_params.sec_channel_offset) ++ return eid; ++ ++ if (hapd->cs_freq_params.sec_channel_offset == -1) ++ sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW; ++ else if (hapd->cs_freq_params.sec_channel_offset == 1) ++ sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE; ++ else ++ return eid; ++ ++ *eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; ++ *eid++ = 1; ++ *eid++ = sec_ch; ++ ++ return eid; ++} ++ ++ ++static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos, ++ u8 *start, unsigned int *csa_counter_off) ++{ ++ u8 *old_pos = pos; ++ ++ if (!csa_counter_off) ++ return pos; ++ ++ *csa_counter_off = 0; ++ pos = hostapd_eid_csa(hapd, pos); ++ ++ if (pos != old_pos) { ++ /* save an offset to the counter - should be last byte */ ++ *csa_counter_off = pos - start - 1; ++ pos = hostapd_eid_secondary_channel(hapd, pos); ++ } ++ ++ return pos; ++} ++ ++ ++static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, ++ const struct ieee80211_mgmt *req, ++ int is_p2p, size_t *resp_len) ++{ ++ struct ieee80211_mgmt *resp; ++ u8 *pos, *epos; ++ size_t buflen; ++ ++#define MAX_PROBERESP_LEN 768 ++ buflen = MAX_PROBERESP_LEN; ++#ifdef CONFIG_WPS ++ if (hapd->wps_probe_resp_ie) ++ buflen += wpabuf_len(hapd->wps_probe_resp_ie); ++#endif /* CONFIG_WPS */ ++#ifdef CONFIG_P2P ++ if (hapd->p2p_probe_resp_ie) ++ buflen += wpabuf_len(hapd->p2p_probe_resp_ie); ++#endif /* CONFIG_P2P */ ++#ifdef CONFIG_FST ++ if (hapd->iface->fst_ies) ++ buflen += wpabuf_len(hapd->iface->fst_ies); ++#endif /* CONFIG_FST */ ++ if (hapd->conf->vendor_elements) ++ buflen += wpabuf_len(hapd->conf->vendor_elements); ++ if (hapd->conf->vendor_vht) { ++ buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) + ++ 2 + sizeof(struct ieee80211_vht_operation); ++ } ++ resp = os_zalloc(buflen); ++ if (resp == NULL) ++ return NULL; ++ ++ epos = ((u8 *) resp) + MAX_PROBERESP_LEN; ++ ++ resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, ++ WLAN_FC_STYPE_PROBE_RESP); ++ if (req) ++ os_memcpy(resp->da, req->sa, ETH_ALEN); ++ os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); ++ ++ os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); ++ resp->u.probe_resp.beacon_int = ++ host_to_le16(hapd->iconf->beacon_int); ++ ++ /* hardware or low-level driver will setup seq_ctrl and timestamp */ ++ resp->u.probe_resp.capab_info = ++ host_to_le16(hostapd_own_capab_info(hapd)); ++ ++ pos = resp->u.probe_resp.variable; ++ *pos++ = WLAN_EID_SSID; ++ *pos++ = hapd->conf->ssid.ssid_len; ++ os_memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len); ++ pos += hapd->conf->ssid.ssid_len; ++ ++ /* Supported rates */ ++ pos = hostapd_eid_supp_rates(hapd, pos); ++ ++ /* DS Params */ ++ pos = hostapd_eid_ds_params(hapd, pos); ++ ++ pos = hostapd_eid_country(hapd, pos, epos - pos); ++ ++ /* Power Constraint element */ ++ pos = hostapd_eid_pwr_constraint(hapd, pos); ++ ++ /* ERP Information element */ ++ pos = hostapd_eid_erp_info(hapd, pos); ++ ++ /* Extended supported rates */ ++ pos = hostapd_eid_ext_supp_rates(hapd, pos); ++ ++ /* RSN, MDIE, WPA */ ++ pos = hostapd_eid_wpa(hapd, pos, epos - pos); ++ ++ pos = hostapd_eid_bss_load(hapd, pos, epos - pos); ++ ++ pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos); ++ ++#ifdef CONFIG_IEEE80211N ++ pos = hostapd_eid_ht_capabilities(hapd, pos); ++ pos = hostapd_eid_ht_operation(hapd, pos); ++#endif /* CONFIG_IEEE80211N */ ++ ++ pos = hostapd_eid_ext_capab(hapd, pos); ++ ++ pos = hostapd_eid_time_adv(hapd, pos); ++ pos = hostapd_eid_time_zone(hapd, pos); ++ ++ pos = hostapd_eid_interworking(hapd, pos); ++ pos = hostapd_eid_adv_proto(hapd, pos); ++ pos = hostapd_eid_roaming_consortium(hapd, pos); ++ ++ pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp, ++ &hapd->cs_c_off_proberesp); ++ ++#ifdef CONFIG_FST ++ if (hapd->iface->fst_ies) { ++ os_memcpy(pos, wpabuf_head(hapd->iface->fst_ies), ++ wpabuf_len(hapd->iface->fst_ies)); ++ pos += wpabuf_len(hapd->iface->fst_ies); ++ } ++#endif /* CONFIG_FST */ ++ ++#ifdef CONFIG_IEEE80211AC ++ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) { ++ pos = hostapd_eid_vht_capabilities(hapd, pos); ++ pos = hostapd_eid_vht_operation(hapd, pos); ++ } ++ if (hapd->conf->vendor_vht) ++ pos = hostapd_eid_vendor_vht(hapd, pos); ++#endif /* CONFIG_IEEE80211AC */ ++ ++ /* Wi-Fi Alliance WMM */ ++ pos = hostapd_eid_wmm(hapd, pos); ++ ++#ifdef CONFIG_WPS ++ if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) { ++ os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie), ++ wpabuf_len(hapd->wps_probe_resp_ie)); ++ pos += wpabuf_len(hapd->wps_probe_resp_ie); ++ } ++#endif /* CONFIG_WPS */ ++ ++#ifdef CONFIG_P2P ++ if ((hapd->conf->p2p & P2P_ENABLED) && is_p2p && ++ hapd->p2p_probe_resp_ie) { ++ os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie), ++ wpabuf_len(hapd->p2p_probe_resp_ie)); ++ pos += wpabuf_len(hapd->p2p_probe_resp_ie); ++ } ++#endif /* CONFIG_P2P */ ++#ifdef CONFIG_P2P_MANAGER ++ if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) == ++ P2P_MANAGE) ++ pos = hostapd_eid_p2p_manage(hapd, pos); ++#endif /* CONFIG_P2P_MANAGER */ ++ ++#ifdef CONFIG_HS20 ++ pos = hostapd_eid_hs20_indication(hapd, pos); ++ pos = hostapd_eid_osen(hapd, pos); ++#endif /* CONFIG_HS20 */ ++ ++ if (hapd->conf->vendor_elements) { ++ os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements), ++ wpabuf_len(hapd->conf->vendor_elements)); ++ pos += wpabuf_len(hapd->conf->vendor_elements); ++ } ++ ++ *resp_len = pos - (u8 *) resp; ++ return (u8 *) resp; ++} ++ ++ ++enum ssid_match_result { ++ NO_SSID_MATCH, ++ EXACT_SSID_MATCH, ++ WILDCARD_SSID_MATCH ++}; ++ ++static enum ssid_match_result ssid_match(struct hostapd_data *hapd, ++ const u8 *ssid, size_t ssid_len, ++ const u8 *ssid_list, ++ size_t ssid_list_len) ++{ ++ const u8 *pos, *end; ++ int wildcard = 0; ++ ++ if (ssid_len == 0) ++ wildcard = 1; ++ if (ssid_len == hapd->conf->ssid.ssid_len && ++ os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0) ++ return EXACT_SSID_MATCH; ++ ++ if (ssid_list == NULL) ++ return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH; ++ ++ pos = ssid_list; ++ end = ssid_list + ssid_list_len; ++ while (pos + 1 <= end) { ++ if (pos + 2 + pos[1] > end) ++ break; ++ if (pos[1] == 0) ++ wildcard = 1; ++ if (pos[1] == hapd->conf->ssid.ssid_len && ++ os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0) ++ return EXACT_SSID_MATCH; ++ pos += 2 + pos[1]; ++ } ++ ++ return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH; ++} ++ ++ ++void sta_track_expire(struct hostapd_iface *iface, int force) ++{ ++ struct os_reltime now; ++ struct hostapd_sta_info *info; ++ ++ if (!iface->num_sta_seen) ++ return; ++ ++ os_get_reltime(&now); ++ while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info, ++ list))) { ++ if (!force && ++ !os_reltime_expired(&now, &info->last_seen, ++ iface->conf->track_sta_max_age)) ++ break; ++ force = 0; ++ ++ wpa_printf(MSG_MSGDUMP, "%s: Expire STA tracking entry for " ++ MACSTR, iface->bss[0]->conf->iface, ++ MAC2STR(info->addr)); ++ dl_list_del(&info->list); ++ iface->num_sta_seen--; ++ os_free(info); ++ } ++} ++ ++ ++static struct hostapd_sta_info * sta_track_get(struct hostapd_iface *iface, ++ const u8 *addr) ++{ ++ struct hostapd_sta_info *info; ++ ++ dl_list_for_each(info, &iface->sta_seen, struct hostapd_sta_info, list) ++ if (os_memcmp(addr, info->addr, ETH_ALEN) == 0) ++ return info; ++ ++ return NULL; ++} ++ ++ ++void sta_track_add(struct hostapd_iface *iface, const u8 *addr) ++{ ++ struct hostapd_sta_info *info; ++ ++ info = sta_track_get(iface, addr); ++ if (info) { ++ /* Move the most recent entry to the end of the list */ ++ dl_list_del(&info->list); ++ dl_list_add_tail(&iface->sta_seen, &info->list); ++ os_get_reltime(&info->last_seen); ++ return; ++ } ++ ++ /* Add a new entry */ ++ info = os_zalloc(sizeof(*info)); ++ os_memcpy(info->addr, addr, ETH_ALEN); ++ os_get_reltime(&info->last_seen); ++ ++ if (iface->num_sta_seen >= iface->conf->track_sta_max_num) { ++ /* Expire oldest entry to make room for a new one */ ++ sta_track_expire(iface, 1); ++ } ++ ++ wpa_printf(MSG_MSGDUMP, "%s: Add STA tracking entry for " ++ MACSTR, iface->bss[0]->conf->iface, MAC2STR(addr)); ++ dl_list_add_tail(&iface->sta_seen, &info->list); ++ iface->num_sta_seen++; ++} ++ ++ ++struct hostapd_data * ++sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr, ++ const char *ifname) ++{ ++ struct hapd_interfaces *interfaces = iface->interfaces; ++ size_t i, j; ++ ++ for (i = 0; i < interfaces->count; i++) { ++ struct hostapd_data *hapd = NULL; ++ ++ iface = interfaces->iface[i]; ++ for (j = 0; j < iface->num_bss; j++) { ++ hapd = iface->bss[j]; ++ if (os_strcmp(ifname, hapd->conf->iface) == 0) ++ break; ++ hapd = NULL; ++ } ++ ++ if (hapd && sta_track_get(iface, addr)) ++ return hapd; ++ } ++ ++ return NULL; ++} ++ ++ ++void handle_probe_req(struct hostapd_data *hapd, ++ const struct ieee80211_mgmt *mgmt, size_t len, ++ int ssi_signal) ++{ ++ u8 *resp; ++ struct ieee802_11_elems elems; ++ const u8 *ie; ++ size_t ie_len; ++ size_t i, resp_len; ++ int noack; ++ enum ssid_match_result res; ++ ++ ie = mgmt->u.probe_req.variable; ++ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) ++ return; ++ if (hapd->iconf->track_sta_max_num) ++ sta_track_add(hapd->iface, mgmt->sa); ++ ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); ++ ++ for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) ++ if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, ++ mgmt->sa, mgmt->da, mgmt->bssid, ++ ie, ie_len, ssi_signal) > 0) ++ return; ++ ++ if (!hapd->iconf->send_probe_response) ++ return; ++ ++ if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { ++ wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR, ++ MAC2STR(mgmt->sa)); ++ return; ++ } ++ ++ if ((!elems.ssid || !elems.supp_rates)) { ++ wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request " ++ "without SSID or supported rates element", ++ MAC2STR(mgmt->sa)); ++ return; ++ } ++ ++ /* ++ * No need to reply if the Probe Request frame was sent on an adjacent ++ * channel. IEEE Std 802.11-2012 describes this as a requirement for an ++ * AP with dot11RadioMeasurementActivated set to true, but strictly ++ * speaking does not allow such ignoring of Probe Request frames if ++ * dot11RadioMeasurementActivated is false. Anyway, this can help reduce ++ * number of unnecessary Probe Response frames for cases where the STA ++ * is less likely to see them (Probe Request frame sent on a ++ * neighboring, but partially overlapping, channel). ++ */ ++ if (elems.ds_params && ++ hapd->iface->current_mode && ++ (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G || ++ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) && ++ hapd->iconf->channel != elems.ds_params[0]) { ++ wpa_printf(MSG_DEBUG, ++ "Ignore Probe Request due to DS Params mismatch: chan=%u != ds.chan=%u", ++ hapd->iconf->channel, elems.ds_params[0]); ++ return; ++ } ++ ++#ifdef CONFIG_P2P ++ if (hapd->p2p && elems.wps_ie) { ++ struct wpabuf *wps; ++ wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); ++ if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) { ++ wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request " ++ "due to mismatch with Requested Device " ++ "Type"); ++ wpabuf_free(wps); ++ return; ++ } ++ wpabuf_free(wps); ++ } ++ ++ if (hapd->p2p && elems.p2p) { ++ struct wpabuf *p2p; ++ p2p = ieee802_11_vendor_ie_concat(ie, ie_len, P2P_IE_VENDOR_TYPE); ++ if (p2p && !p2p_group_match_dev_id(hapd->p2p_group, p2p)) { ++ wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request " ++ "due to mismatch with Device ID"); ++ wpabuf_free(p2p); ++ return; ++ } ++ wpabuf_free(p2p); ++ } ++#endif /* CONFIG_P2P */ ++ ++ if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 && ++ elems.ssid_list_len == 0) { ++ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for " ++ "broadcast SSID ignored", MAC2STR(mgmt->sa)); ++ return; ++ } ++ ++#ifdef CONFIG_P2P ++ if ((hapd->conf->p2p & P2P_GROUP_OWNER) && ++ elems.ssid_len == P2P_WILDCARD_SSID_LEN && ++ os_memcmp(elems.ssid, P2P_WILDCARD_SSID, ++ P2P_WILDCARD_SSID_LEN) == 0) { ++ /* Process P2P Wildcard SSID like Wildcard SSID */ ++ elems.ssid_len = 0; ++ } ++#endif /* CONFIG_P2P */ ++ ++ res = ssid_match(hapd, elems.ssid, elems.ssid_len, ++ elems.ssid_list, elems.ssid_list_len); ++ if (res == NO_SSID_MATCH) { ++ if (!(mgmt->da[0] & 0x01)) { ++ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR ++ " for foreign SSID '%s' (DA " MACSTR ")%s", ++ MAC2STR(mgmt->sa), ++ wpa_ssid_txt(elems.ssid, elems.ssid_len), ++ MAC2STR(mgmt->da), ++ elems.ssid_list ? " (SSID list)" : ""); ++ } ++ return; ++ } ++ ++#ifdef CONFIG_INTERWORKING ++ if (hapd->conf->interworking && ++ elems.interworking && elems.interworking_len >= 1) { ++ u8 ant = elems.interworking[0] & 0x0f; ++ if (ant != INTERWORKING_ANT_WILDCARD && ++ ant != hapd->conf->access_network_type) { ++ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR ++ " for mismatching ANT %u ignored", ++ MAC2STR(mgmt->sa), ant); ++ return; ++ } ++ } ++ ++ if (hapd->conf->interworking && elems.interworking && ++ (elems.interworking_len == 7 || elems.interworking_len == 9)) { ++ const u8 *hessid; ++ if (elems.interworking_len == 7) ++ hessid = elems.interworking + 1; ++ else ++ hessid = elems.interworking + 1 + 2; ++ if (!is_broadcast_ether_addr(hessid) && ++ os_memcmp(hessid, hapd->conf->hessid, ETH_ALEN) != 0) { ++ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR ++ " for mismatching HESSID " MACSTR ++ " ignored", ++ MAC2STR(mgmt->sa), MAC2STR(hessid)); ++ return; ++ } ++ } ++#endif /* CONFIG_INTERWORKING */ ++ ++#ifdef CONFIG_P2P ++ if ((hapd->conf->p2p & P2P_GROUP_OWNER) && ++ supp_rates_11b_only(&elems)) { ++ /* Indicates support for 11b rates only */ ++ wpa_printf(MSG_EXCESSIVE, "P2P: Ignore Probe Request from " ++ MACSTR " with only 802.11b rates", ++ MAC2STR(mgmt->sa)); ++ return; ++ } ++#endif /* CONFIG_P2P */ ++ ++ /* TODO: verify that supp_rates contains at least one matching rate ++ * with AP configuration */ ++ ++ if (hapd->conf->no_probe_resp_if_seen_on && ++ is_multicast_ether_addr(mgmt->da) && ++ is_multicast_ether_addr(mgmt->bssid) && ++ sta_track_seen_on(hapd->iface, mgmt->sa, ++ hapd->conf->no_probe_resp_if_seen_on)) { ++ wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR ++ " since STA has been seen on %s", ++ hapd->conf->iface, MAC2STR(mgmt->sa), ++ hapd->conf->no_probe_resp_if_seen_on); ++ return; ++ } ++ ++#ifdef CONFIG_TESTING_OPTIONS ++ if (hapd->iconf->ignore_probe_probability > 0.0 && ++ drand48() < hapd->iconf->ignore_probe_probability) { ++ wpa_printf(MSG_INFO, ++ "TESTING: ignoring probe request from " MACSTR, ++ MAC2STR(mgmt->sa)); ++ return; ++ } ++#endif /* CONFIG_TESTING_OPTIONS */ ++ ++ resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL, ++ &resp_len); ++ if (resp == NULL) ++ return; ++ ++ /* ++ * If this is a broadcast probe request, apply no ack policy to avoid ++ * excessive retries. ++ */ ++ noack = !!(res == WILDCARD_SSID_MATCH && ++ is_broadcast_ether_addr(mgmt->da)); ++ ++ if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0) ++ wpa_printf(MSG_INFO, "handle_probe_req: send failed"); ++ ++ os_free(resp); ++ ++ wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s " ++ "SSID", MAC2STR(mgmt->sa), ++ elems.ssid_len == 0 ? "broadcast" : "our"); ++} ++ ++ ++static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd, ++ size_t *resp_len) ++{ ++ /* check probe response offloading caps and print warnings */ ++ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD)) ++ return NULL; ++ ++#ifdef CONFIG_WPS ++ if (hapd->conf->wps_state && hapd->wps_probe_resp_ie && ++ (!(hapd->iface->probe_resp_offloads & ++ (WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS | ++ WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2)))) ++ wpa_printf(MSG_WARNING, "Device is trying to offload WPS " ++ "Probe Response while not supporting this"); ++#endif /* CONFIG_WPS */ ++ ++#ifdef CONFIG_P2P ++ if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_probe_resp_ie && ++ !(hapd->iface->probe_resp_offloads & ++ WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P)) ++ wpa_printf(MSG_WARNING, "Device is trying to offload P2P " ++ "Probe Response while not supporting this"); ++#endif /* CONFIG_P2P */ ++ ++ if (hapd->conf->interworking && ++ !(hapd->iface->probe_resp_offloads & ++ WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING)) ++ wpa_printf(MSG_WARNING, "Device is trying to offload " ++ "Interworking Probe Response while not supporting " ++ "this"); ++ ++ /* Generate a Probe Response template for the non-P2P case */ ++ return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len); ++} ++ ++#endif /* NEED_AP_MLME */ ++ ++ ++int ieee802_11_build_ap_params(struct hostapd_data *hapd, ++ struct wpa_driver_ap_params *params) ++{ ++ struct ieee80211_mgmt *head = NULL; ++ u8 *tail = NULL; ++ size_t head_len = 0, tail_len = 0; ++ u8 *resp = NULL; ++ size_t resp_len = 0; ++#ifdef NEED_AP_MLME ++ u16 capab_info; ++ u8 *pos, *tailpos; ++ ++#define BEACON_HEAD_BUF_SIZE 256 ++#define BEACON_TAIL_BUF_SIZE 512 ++ head = os_zalloc(BEACON_HEAD_BUF_SIZE); ++ tail_len = BEACON_TAIL_BUF_SIZE; ++#ifdef CONFIG_WPS ++ if (hapd->conf->wps_state && hapd->wps_beacon_ie) ++ tail_len += wpabuf_len(hapd->wps_beacon_ie); ++#endif /* CONFIG_WPS */ ++#ifdef CONFIG_P2P ++ if (hapd->p2p_beacon_ie) ++ tail_len += wpabuf_len(hapd->p2p_beacon_ie); ++#endif /* CONFIG_P2P */ ++#ifdef CONFIG_FST ++ if (hapd->iface->fst_ies) ++ tail_len += wpabuf_len(hapd->iface->fst_ies); ++#endif /* CONFIG_FST */ ++ if (hapd->conf->vendor_elements) ++ tail_len += wpabuf_len(hapd->conf->vendor_elements); ++ ++#ifdef CONFIG_IEEE80211AC ++ if (hapd->conf->vendor_vht) { ++ tail_len += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) + ++ 2 + sizeof(struct ieee80211_vht_operation); ++ } ++#endif /* CONFIG_IEEE80211AC */ ++ ++ tailpos = tail = os_malloc(tail_len); ++ if (head == NULL || tail == NULL) { ++ wpa_printf(MSG_ERROR, "Failed to set beacon data"); ++ os_free(head); ++ os_free(tail); ++ return -1; ++ } ++ ++ head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, ++ WLAN_FC_STYPE_BEACON); ++ head->duration = host_to_le16(0); ++ os_memset(head->da, 0xff, ETH_ALEN); ++ ++ os_memcpy(head->sa, hapd->own_addr, ETH_ALEN); ++ os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN); ++ head->u.beacon.beacon_int = ++ host_to_le16(hapd->iconf->beacon_int); ++ ++ /* hardware or low-level driver will setup seq_ctrl and timestamp */ ++ capab_info = hostapd_own_capab_info(hapd); ++ head->u.beacon.capab_info = host_to_le16(capab_info); ++ pos = &head->u.beacon.variable[0]; ++ ++ /* SSID */ ++ *pos++ = WLAN_EID_SSID; ++ if (hapd->conf->ignore_broadcast_ssid == 2) { ++ /* clear the data, but keep the correct length of the SSID */ ++ *pos++ = hapd->conf->ssid.ssid_len; ++ os_memset(pos, 0, hapd->conf->ssid.ssid_len); ++ pos += hapd->conf->ssid.ssid_len; ++ } else if (hapd->conf->ignore_broadcast_ssid) { ++ *pos++ = 0; /* empty SSID */ ++ } else { ++ *pos++ = hapd->conf->ssid.ssid_len; ++ os_memcpy(pos, hapd->conf->ssid.ssid, ++ hapd->conf->ssid.ssid_len); ++ pos += hapd->conf->ssid.ssid_len; ++ } ++ ++ /* Supported rates */ ++ pos = hostapd_eid_supp_rates(hapd, pos); ++ ++ /* DS Params */ ++ pos = hostapd_eid_ds_params(hapd, pos); ++ ++ head_len = pos - (u8 *) head; ++ ++ tailpos = hostapd_eid_country(hapd, tailpos, ++ tail + BEACON_TAIL_BUF_SIZE - tailpos); ++ ++ /* Power Constraint element */ ++ tailpos = hostapd_eid_pwr_constraint(hapd, tailpos); ++ ++ /* ERP Information element */ ++ tailpos = hostapd_eid_erp_info(hapd, tailpos); ++ ++ /* Extended supported rates */ ++ tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos); ++ ++ /* RSN, MDIE, WPA */ ++ tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE - ++ tailpos); ++ ++ tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos, ++ tail + BEACON_TAIL_BUF_SIZE - ++ tailpos); ++ ++ tailpos = hostapd_eid_bss_load(hapd, tailpos, ++ tail + BEACON_TAIL_BUF_SIZE - tailpos); ++ ++#ifdef CONFIG_IEEE80211N ++ tailpos = hostapd_eid_ht_capabilities(hapd, tailpos); ++ tailpos = hostapd_eid_ht_operation(hapd, tailpos); ++#endif /* CONFIG_IEEE80211N */ ++ ++ tailpos = hostapd_eid_ext_capab(hapd, tailpos); ++ ++ /* ++ * TODO: Time Advertisement element should only be included in some ++ * DTIM Beacon frames. ++ */ ++ tailpos = hostapd_eid_time_adv(hapd, tailpos); ++ ++ tailpos = hostapd_eid_interworking(hapd, tailpos); ++ tailpos = hostapd_eid_adv_proto(hapd, tailpos); ++ tailpos = hostapd_eid_roaming_consortium(hapd, tailpos); ++ tailpos = hostapd_add_csa_elems(hapd, tailpos, tail, ++ &hapd->cs_c_off_beacon); ++ ++#ifdef CONFIG_FST ++ if (hapd->iface->fst_ies) { ++ os_memcpy(tailpos, wpabuf_head(hapd->iface->fst_ies), ++ wpabuf_len(hapd->iface->fst_ies)); ++ tailpos += wpabuf_len(hapd->iface->fst_ies); ++ } ++#endif /* CONFIG_FST */ ++ ++#ifdef CONFIG_IEEE80211AC ++ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) { ++ tailpos = hostapd_eid_vht_capabilities(hapd, tailpos); ++ tailpos = hostapd_eid_vht_operation(hapd, tailpos); ++ } ++ if (hapd->conf->vendor_vht) ++ tailpos = hostapd_eid_vendor_vht(hapd, tailpos); ++#endif /* CONFIG_IEEE80211AC */ ++ ++ /* Wi-Fi Alliance WMM */ ++ tailpos = hostapd_eid_wmm(hapd, tailpos); ++ ++#ifdef CONFIG_WPS ++ if (hapd->conf->wps_state && hapd->wps_beacon_ie) { ++ os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie), ++ wpabuf_len(hapd->wps_beacon_ie)); ++ tailpos += wpabuf_len(hapd->wps_beacon_ie); ++ } ++#endif /* CONFIG_WPS */ ++ ++#ifdef CONFIG_P2P ++ if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_beacon_ie) { ++ os_memcpy(tailpos, wpabuf_head(hapd->p2p_beacon_ie), ++ wpabuf_len(hapd->p2p_beacon_ie)); ++ tailpos += wpabuf_len(hapd->p2p_beacon_ie); ++ } ++#endif /* CONFIG_P2P */ ++#ifdef CONFIG_P2P_MANAGER ++ if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) == ++ P2P_MANAGE) ++ tailpos = hostapd_eid_p2p_manage(hapd, tailpos); ++#endif /* CONFIG_P2P_MANAGER */ ++ ++#ifdef CONFIG_HS20 ++ tailpos = hostapd_eid_hs20_indication(hapd, tailpos); ++ tailpos = hostapd_eid_osen(hapd, tailpos); ++#endif /* CONFIG_HS20 */ ++ ++ if (hapd->conf->vendor_elements) { ++ os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements), ++ wpabuf_len(hapd->conf->vendor_elements)); ++ tailpos += wpabuf_len(hapd->conf->vendor_elements); ++ } ++ ++ tail_len = tailpos > tail ? tailpos - tail : 0; ++ ++ resp = hostapd_probe_resp_offloads(hapd, &resp_len); ++#endif /* NEED_AP_MLME */ ++ ++ os_memset(params, 0, sizeof(*params)); ++ params->head = (u8 *) head; ++ params->head_len = head_len; ++ params->tail = tail; ++ params->tail_len = tail_len; ++ params->proberesp = resp; ++ params->proberesp_len = resp_len; ++ params->dtim_period = hapd->conf->dtim_period; ++ params->beacon_int = hapd->iconf->beacon_int; ++ params->basic_rates = hapd->iface->basic_rates; ++ params->ssid = hapd->conf->ssid.ssid; ++ params->ssid_len = hapd->conf->ssid.ssid_len; ++ if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) == ++ (WPA_PROTO_WPA | WPA_PROTO_RSN)) ++ params->pairwise_ciphers = hapd->conf->wpa_pairwise | ++ hapd->conf->rsn_pairwise; ++ else if (hapd->conf->wpa & WPA_PROTO_RSN) ++ params->pairwise_ciphers = hapd->conf->rsn_pairwise; ++ else if (hapd->conf->wpa & WPA_PROTO_WPA) ++ params->pairwise_ciphers = hapd->conf->wpa_pairwise; ++ params->group_cipher = hapd->conf->wpa_group; ++ params->key_mgmt_suites = hapd->conf->wpa_key_mgmt; ++ params->auth_algs = hapd->conf->auth_algs; ++ params->wpa_version = hapd->conf->wpa; ++ params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa || ++ (hapd->conf->ieee802_1x && ++ (hapd->conf->default_wep_key_len || ++ hapd->conf->individual_wep_key_len)); ++ switch (hapd->conf->ignore_broadcast_ssid) { ++ case 0: ++ params->hide_ssid = NO_SSID_HIDING; ++ break; ++ case 1: ++ params->hide_ssid = HIDDEN_SSID_ZERO_LEN; ++ break; ++ case 2: ++ params->hide_ssid = HIDDEN_SSID_ZERO_CONTENTS; ++ break; ++ } ++ params->isolate = hapd->conf->isolate; ++ params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK; ++#ifdef NEED_AP_MLME ++ params->cts_protect = !!(ieee802_11_erp_info(hapd) & ++ ERP_INFO_USE_PROTECTION); ++ params->preamble = hapd->iface->num_sta_no_short_preamble == 0 && ++ hapd->iconf->preamble == SHORT_PREAMBLE; ++ if (hapd->iface->current_mode && ++ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) ++ params->short_slot_time = ++ hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1; ++ else ++ params->short_slot_time = -1; ++ if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n) ++ params->ht_opmode = -1; ++ else ++ params->ht_opmode = hapd->iface->ht_op_mode; ++#endif /* NEED_AP_MLME */ ++ params->interworking = hapd->conf->interworking; ++ if (hapd->conf->interworking && ++ !is_zero_ether_addr(hapd->conf->hessid)) ++ params->hessid = hapd->conf->hessid; ++ params->access_network_type = hapd->conf->access_network_type; ++ params->ap_max_inactivity = hapd->conf->ap_max_inactivity; ++#ifdef CONFIG_P2P ++ params->p2p_go_ctwindow = hapd->iconf->p2p_go_ctwindow; ++#endif /* CONFIG_P2P */ ++#ifdef CONFIG_HS20 ++ params->disable_dgaf = hapd->conf->disable_dgaf; ++ if (hapd->conf->osen) { ++ params->privacy = 1; ++ params->osen = 1; ++ } ++#endif /* CONFIG_HS20 */ ++ return 0; ++} ++ ++ ++void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params) ++{ ++ os_free(params->tail); ++ params->tail = NULL; ++ os_free(params->head); ++ params->head = NULL; ++ os_free(params->proberesp); ++ params->proberesp = NULL; ++} ++ ++ ++int ieee802_11_set_beacon(struct hostapd_data *hapd) ++{ ++ struct wpa_driver_ap_params params; ++ struct hostapd_freq_params freq; ++ struct hostapd_iface *iface = hapd->iface; ++ struct hostapd_config *iconf = iface->conf; ++ struct wpabuf *beacon, *proberesp, *assocresp; ++ int res, ret = -1; ++ ++ if (hapd->csa_in_progress) { ++ wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period"); ++ return -1; ++ } ++ ++ hapd->beacon_set_done = 1; ++ ++ if (ieee802_11_build_ap_params(hapd, ¶ms) < 0) ++ return -1; ++ ++ if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) < ++ 0) ++ goto fail; ++ ++ params.beacon_ies = beacon; ++ params.proberesp_ies = proberesp; ++ params.assocresp_ies = assocresp; ++ params.reenable = hapd->reenable_beacon; ++ hapd->reenable_beacon = 0; ++ ++ if (iface->current_mode && ++ hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq, ++ iconf->channel, iconf->ieee80211n, ++ iconf->ieee80211ac, ++ iconf->secondary_channel, ++ iconf->vht_oper_chwidth, ++ iconf->vht_oper_centr_freq_seg0_idx, ++ iconf->vht_oper_centr_freq_seg1_idx, ++ iface->current_mode->vht_capab) == 0) ++ params.freq = &freq; ++ ++ res = hostapd_drv_set_ap(hapd, ¶ms); ++ hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); ++ if (res) ++ wpa_printf(MSG_ERROR, "Failed to set beacon parameters"); ++ else ++ ret = 0; ++fail: ++ ieee802_11_free_ap_params(¶ms); ++ return ret; ++} ++ ++ ++int ieee802_11_set_beacons(struct hostapd_iface *iface) ++{ ++ size_t i; ++ int ret = 0; ++ ++ for (i = 0; i < iface->num_bss; i++) { ++ if (iface->bss[i]->started && ++ ieee802_11_set_beacon(iface->bss[i]) < 0) ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++/* only update beacons if started */ ++int ieee802_11_update_beacons(struct hostapd_iface *iface) ++{ ++ size_t i; ++ int ret = 0; ++ ++ for (i = 0; i < iface->num_bss; i++) { ++ if (iface->bss[i]->beacon_set_done && iface->bss[i]->started && ++ ieee802_11_set_beacon(iface->bss[i]) < 0) ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++#endif /* CONFIG_NATIVE_WINDOWS */ diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index fc8786d..efd3841 100644 --- a/src/ap/hw_features.c @@ -851,16 +2111,1002 @@ index fc8786d..efd3841 100644 + //return -1; + return 0;//ignore this error } - + if (ret < 0) { +diff --git a/src/ap/hw_features.c.orig b/src/ap/hw_features.c.orig +new file mode 100644 +index 0000000..fc8786d +--- /dev/null ++++ b/src/ap/hw_features.c.orig +@@ -0,0 +1,980 @@ ++/* ++ * hostapd / Hardware feature query and different modes ++ * Copyright 2002-2003, Instant802 Networks, Inc. ++ * Copyright 2005-2006, Devicescape Software, Inc. ++ * Copyright (c) 2008-2012, Jouni Malinen ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ */ ++ ++#include "utils/includes.h" ++ ++#include "utils/common.h" ++#include "utils/eloop.h" ++#include "common/ieee802_11_defs.h" ++#include "common/ieee802_11_common.h" ++#include "common/wpa_ctrl.h" ++#include "common/hw_features_common.h" ++#include "hostapd.h" ++#include "ap_config.h" ++#include "ap_drv_ops.h" ++#include "acs.h" ++#include "ieee802_11.h" ++#include "beacon.h" ++#include "hw_features.h" ++ ++ ++void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, ++ size_t num_hw_features) ++{ ++ size_t i; ++ ++ if (hw_features == NULL) ++ return; ++ ++ for (i = 0; i < num_hw_features; i++) { ++ os_free(hw_features[i].channels); ++ os_free(hw_features[i].rates); ++ } ++ ++ os_free(hw_features); ++} ++ ++ ++#ifndef CONFIG_NO_STDOUT_DEBUG ++static char * dfs_info(struct hostapd_channel_data *chan) ++{ ++ static char info[256]; ++ char *state; ++ ++ switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) { ++ case HOSTAPD_CHAN_DFS_UNKNOWN: ++ state = "unknown"; ++ break; ++ case HOSTAPD_CHAN_DFS_USABLE: ++ state = "usable"; ++ break; ++ case HOSTAPD_CHAN_DFS_UNAVAILABLE: ++ state = "unavailable"; ++ break; ++ case HOSTAPD_CHAN_DFS_AVAILABLE: ++ state = "available"; ++ break; ++ default: ++ return ""; ++ } ++ os_snprintf(info, sizeof(info), " (DFS state = %s)", state); ++ info[sizeof(info) - 1] = '\0'; ++ ++ return info; ++} ++#endif /* CONFIG_NO_STDOUT_DEBUG */ ++ ++ ++int hostapd_get_hw_features(struct hostapd_iface *iface) ++{ ++ struct hostapd_data *hapd = iface->bss[0]; ++ int i, j; ++ u16 num_modes, flags; ++ struct hostapd_hw_modes *modes; ++ ++ if (hostapd_drv_none(hapd)) ++ return -1; ++ modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags); ++ if (modes == NULL) { ++ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, ++ HOSTAPD_LEVEL_DEBUG, ++ "Fetching hardware channel/rate support not " ++ "supported."); ++ return -1; ++ } ++ ++ iface->hw_flags = flags; ++ ++ hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); ++ iface->hw_features = modes; ++ iface->num_hw_features = num_modes; ++ ++ for (i = 0; i < num_modes; i++) { ++ struct hostapd_hw_modes *feature = &modes[i]; ++ int dfs_enabled = hapd->iconf->ieee80211h && ++ (iface->drv_flags & WPA_DRIVER_FLAGS_RADAR); ++ ++ /* set flag for channels we can use in current regulatory ++ * domain */ ++ for (j = 0; j < feature->num_channels; j++) { ++ int dfs = 0; ++ ++ /* ++ * Disable all channels that are marked not to allow ++ * to initiate radiation (a.k.a. passive scan and no ++ * IBSS). ++ * Use radar channels only if the driver supports DFS. ++ */ ++ if ((feature->channels[j].flag & ++ HOSTAPD_CHAN_RADAR) && dfs_enabled) { ++ dfs = 1; ++ } else if (((feature->channels[j].flag & ++ HOSTAPD_CHAN_RADAR) && ++ !(iface->drv_flags & ++ WPA_DRIVER_FLAGS_DFS_OFFLOAD)) || ++ (feature->channels[j].flag & ++ HOSTAPD_CHAN_NO_IR)) { ++ feature->channels[j].flag |= ++ HOSTAPD_CHAN_DISABLED; ++ } ++ ++ if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED) ++ continue; ++ ++ wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d " ++ "chan=%d freq=%d MHz max_tx_power=%d dBm%s", ++ feature->mode, ++ feature->channels[j].chan, ++ feature->channels[j].freq, ++ feature->channels[j].max_tx_power, ++ dfs ? dfs_info(&feature->channels[j]) : ""); ++ } ++ } ++ ++ return 0; ++} ++ ++ ++int hostapd_prepare_rates(struct hostapd_iface *iface, ++ struct hostapd_hw_modes *mode) ++{ ++ int i, num_basic_rates = 0; ++ int basic_rates_a[] = { 60, 120, 240, -1 }; ++ int basic_rates_b[] = { 10, 20, -1 }; ++ int basic_rates_g[] = { 10, 20, 55, 110, -1 }; ++ int *basic_rates; ++ ++ if (iface->conf->basic_rates) ++ basic_rates = iface->conf->basic_rates; ++ else switch (mode->mode) { ++ case HOSTAPD_MODE_IEEE80211A: ++ basic_rates = basic_rates_a; ++ break; ++ case HOSTAPD_MODE_IEEE80211B: ++ basic_rates = basic_rates_b; ++ break; ++ case HOSTAPD_MODE_IEEE80211G: ++ basic_rates = basic_rates_g; ++ break; ++ case HOSTAPD_MODE_IEEE80211AD: ++ return 0; /* No basic rates for 11ad */ ++ default: ++ return -1; ++ } ++ ++ i = 0; ++ while (basic_rates[i] >= 0) ++ i++; ++ if (i) ++ i++; /* -1 termination */ ++ os_free(iface->basic_rates); ++ iface->basic_rates = os_malloc(i * sizeof(int)); ++ if (iface->basic_rates) ++ os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int)); ++ ++ os_free(iface->current_rates); ++ iface->num_rates = 0; ++ ++ iface->current_rates = ++ os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data)); ++ if (!iface->current_rates) { ++ wpa_printf(MSG_ERROR, "Failed to allocate memory for rate " ++ "table."); ++ return -1; ++ } ++ ++ for (i = 0; i < mode->num_rates; i++) { ++ struct hostapd_rate_data *rate; ++ ++ if (iface->conf->supported_rates && ++ !hostapd_rate_found(iface->conf->supported_rates, ++ mode->rates[i])) ++ continue; ++ ++ rate = &iface->current_rates[iface->num_rates]; ++ rate->rate = mode->rates[i]; ++ if (hostapd_rate_found(basic_rates, rate->rate)) { ++ rate->flags |= HOSTAPD_RATE_BASIC; ++ num_basic_rates++; ++ } ++ wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x", ++ iface->num_rates, rate->rate, rate->flags); ++ iface->num_rates++; ++ } ++ ++ if ((iface->num_rates == 0 || num_basic_rates == 0) && ++ (!iface->conf->ieee80211n || !iface->conf->require_ht)) { ++ wpa_printf(MSG_ERROR, "No rates remaining in supported/basic " ++ "rate sets (%d,%d).", ++ iface->num_rates, num_basic_rates); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++#ifdef CONFIG_IEEE80211N ++static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface) ++{ ++ int pri_chan, sec_chan; ++ ++ if (!iface->conf->secondary_channel) ++ return 1; /* HT40 not used */ ++ ++ pri_chan = iface->conf->channel; ++ sec_chan = pri_chan + iface->conf->secondary_channel * 4; ++ ++ return allowed_ht40_channel_pair(iface->current_mode, pri_chan, ++ sec_chan); ++} ++ ++ ++static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface) ++{ ++ if (iface->conf->secondary_channel > 0) { ++ iface->conf->channel += 4; ++ iface->conf->secondary_channel = -1; ++ } else { ++ iface->conf->channel -= 4; ++ iface->conf->secondary_channel = 1; ++ } ++} ++ ++ ++static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, ++ struct wpa_scan_results *scan_res) ++{ ++ int pri_chan, sec_chan; ++ int res; ++ ++ pri_chan = iface->conf->channel; ++ sec_chan = pri_chan + iface->conf->secondary_channel * 4; ++ ++ res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan); ++ ++ if (res == 2) { ++ if (iface->conf->no_pri_sec_switch) { ++ wpa_printf(MSG_DEBUG, ++ "Cannot switch PRI/SEC channels due to local constraint"); ++ } else { ++ ieee80211n_switch_pri_sec(iface); ++ } ++ } ++ ++ return !!res; ++} ++ ++ ++static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface, ++ struct wpa_scan_results *scan_res) ++{ ++ int pri_chan, sec_chan; ++ ++ pri_chan = iface->conf->channel; ++ sec_chan = pri_chan + iface->conf->secondary_channel * 4; ++ ++ return check_40mhz_2g4(iface->current_mode, scan_res, pri_chan, ++ sec_chan); ++} ++ ++ ++static void ieee80211n_check_scan(struct hostapd_iface *iface) ++{ ++ struct wpa_scan_results *scan_res; ++ int oper40; ++ int res; ++ ++ /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is ++ * allowed per IEEE Std 802.11-2012, 10.15.3.2 */ ++ ++ iface->scan_cb = NULL; ++ ++ scan_res = hostapd_driver_get_scan_results(iface->bss[0]); ++ if (scan_res == NULL) { ++ hostapd_setup_interface_complete(iface, 1); ++ return; ++ } ++ ++ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A) ++ oper40 = ieee80211n_check_40mhz_5g(iface, scan_res); ++ else ++ oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res); ++ wpa_scan_results_free(scan_res); ++ ++ iface->secondary_ch = iface->conf->secondary_channel; ++ if (!oper40) { ++ wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on " ++ "channel pri=%d sec=%d based on overlapping BSSes", ++ iface->conf->channel, ++ iface->conf->channel + ++ iface->conf->secondary_channel * 4); ++ iface->conf->secondary_channel = 0; ++ if (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX) { ++ /* ++ * TODO: Could consider scheduling another scan to check ++ * if channel width can be changed if no coex reports ++ * are received from associating stations. ++ */ ++ } ++ } ++ ++ res = ieee80211n_allowed_ht40_channel_pair(iface); ++ if (!res) { ++ iface->conf->secondary_channel = 0; ++ wpa_printf(MSG_INFO, "Fallback to 20 MHz"); ++ } ++ ++ hostapd_setup_interface_complete(iface, !res); ++} ++ ++ ++static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface, ++ struct wpa_driver_scan_params *params) ++{ ++ /* Scan only the affected frequency range */ ++ int pri_freq, sec_freq; ++ int affected_start, affected_end; ++ int i, pos; ++ struct hostapd_hw_modes *mode; ++ ++ if (iface->current_mode == NULL) ++ return; ++ ++ pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); ++ if (iface->conf->secondary_channel > 0) ++ sec_freq = pri_freq + 20; ++ else ++ sec_freq = pri_freq - 20; ++ /* ++ * Note: Need to find the PRI channel also in cases where the affected ++ * channel is the SEC channel of a 40 MHz BSS, so need to include the ++ * scanning coverage here to be 40 MHz from the center frequency. ++ */ ++ affected_start = (pri_freq + sec_freq) / 2 - 40; ++ affected_end = (pri_freq + sec_freq) / 2 + 40; ++ wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", ++ affected_start, affected_end); ++ ++ mode = iface->current_mode; ++ params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); ++ if (params->freqs == NULL) ++ return; ++ pos = 0; ++ ++ for (i = 0; i < mode->num_channels; i++) { ++ struct hostapd_channel_data *chan = &mode->channels[i]; ++ if (chan->flag & HOSTAPD_CHAN_DISABLED) ++ continue; ++ if (chan->freq < affected_start || ++ chan->freq > affected_end) ++ continue; ++ params->freqs[pos++] = chan->freq; ++ } ++} ++ ++ ++static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface, ++ struct wpa_driver_scan_params *params) ++{ ++ /* Scan only the affected frequency range */ ++ int pri_freq; ++ int affected_start, affected_end; ++ int i, pos; ++ struct hostapd_hw_modes *mode; ++ ++ if (iface->current_mode == NULL) ++ return; ++ ++ pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); ++ if (iface->conf->secondary_channel > 0) { ++ affected_start = pri_freq - 10; ++ affected_end = pri_freq + 30; ++ } else { ++ affected_start = pri_freq - 30; ++ affected_end = pri_freq + 10; ++ } ++ wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", ++ affected_start, affected_end); ++ ++ mode = iface->current_mode; ++ params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); ++ if (params->freqs == NULL) ++ return; ++ pos = 0; ++ ++ for (i = 0; i < mode->num_channels; i++) { ++ struct hostapd_channel_data *chan = &mode->channels[i]; ++ if (chan->flag & HOSTAPD_CHAN_DISABLED) ++ continue; ++ if (chan->freq < affected_start || ++ chan->freq > affected_end) ++ continue; ++ params->freqs[pos++] = chan->freq; ++ } ++} ++ ++ ++static void ap_ht40_scan_retry(void *eloop_data, void *user_data) ++{ ++#define HT2040_COEX_SCAN_RETRY 15 ++ struct hostapd_iface *iface = eloop_data; ++ struct wpa_driver_scan_params params; ++ int ret; ++ ++ os_memset(¶ms, 0, sizeof(params)); ++ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) ++ ieee80211n_scan_channels_2g4(iface, ¶ms); ++ else ++ ieee80211n_scan_channels_5g(iface, ¶ms); ++ ++ ret = hostapd_driver_scan(iface->bss[0], ¶ms); ++ iface->num_ht40_scan_tries++; ++ os_free(params.freqs); ++ ++ if (ret == -EBUSY && ++ iface->num_ht40_scan_tries < HT2040_COEX_SCAN_RETRY) { ++ wpa_printf(MSG_ERROR, ++ "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again (attempt %d)", ++ ret, strerror(-ret), iface->num_ht40_scan_tries); ++ eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL); ++ return; ++ } ++ ++ if (ret == 0) { ++ iface->scan_cb = ieee80211n_check_scan; ++ return; ++ } ++ ++ wpa_printf(MSG_DEBUG, ++ "Failed to request a scan in device, bringing up in HT20 mode"); ++ iface->conf->secondary_channel = 0; ++ iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; ++ hostapd_setup_interface_complete(iface, 0); ++} ++ ++ ++void hostapd_stop_setup_timers(struct hostapd_iface *iface) ++{ ++ eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL); ++} ++ ++ ++static int ieee80211n_check_40mhz(struct hostapd_iface *iface) ++{ ++ struct wpa_driver_scan_params params; ++ int ret; ++ ++ if (!iface->conf->secondary_channel) ++ return 0; /* HT40 not used */ ++ ++ hostapd_set_state(iface, HAPD_IFACE_HT_SCAN); ++ wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " ++ "40 MHz channel"); ++ os_memset(¶ms, 0, sizeof(params)); ++ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) ++ ieee80211n_scan_channels_2g4(iface, ¶ms); ++ else ++ ieee80211n_scan_channels_5g(iface, ¶ms); ++ ++ ret = hostapd_driver_scan(iface->bss[0], ¶ms); ++ os_free(params.freqs); ++ ++ if (ret == -EBUSY) { ++ wpa_printf(MSG_ERROR, ++ "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again", ++ ret, strerror(-ret)); ++ iface->num_ht40_scan_tries = 1; ++ eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL); ++ eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL); ++ return 1; ++ } ++ ++ if (ret < 0) { ++ wpa_printf(MSG_ERROR, ++ "Failed to request a scan of neighboring BSSes ret=%d (%s)", ++ ret, strerror(-ret)); ++ return -1; ++ } ++ ++ iface->scan_cb = ieee80211n_check_scan; ++ return 1; ++} ++ ++ ++static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) ++{ ++ u16 hw = iface->current_mode->ht_capab; ++ u16 conf = iface->conf->ht_capab; ++ ++ if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) && ++ !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [LDPC]"); ++ return 0; ++ } ++ ++ /* ++ * Driver ACS chosen channel may not be HT40 due to internal driver ++ * restrictions. ++ */ ++ if (!iface->conf->acs && (conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && ++ !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [HT40*]"); ++ return 0; ++ } ++ ++ switch (conf & HT_CAP_INFO_SMPS_MASK) { ++ case HT_CAP_INFO_SMPS_STATIC: ++ if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) { ++ wpa_printf(MSG_ERROR, ++ "Driver does not support configured HT capability [SMPS-STATIC]"); ++ return 0; ++ } ++ break; ++ case HT_CAP_INFO_SMPS_DYNAMIC: ++ if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) { ++ wpa_printf(MSG_ERROR, ++ "Driver does not support configured HT capability [SMPS-DYNAMIC]"); ++ return 0; ++ } ++ break; ++ case HT_CAP_INFO_SMPS_DISABLED: ++ default: ++ break; ++ } ++ ++ if ((conf & HT_CAP_INFO_GREEN_FIELD) && ++ !(hw & HT_CAP_INFO_GREEN_FIELD)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [GF]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) && ++ !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [SHORT-GI-20]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) && ++ !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [SHORT-GI-40]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [TX-STBC]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_RX_STBC_MASK) > ++ (hw & HT_CAP_INFO_RX_STBC_MASK)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [RX-STBC*]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_DELAYED_BA) && ++ !(hw & HT_CAP_INFO_DELAYED_BA)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [DELAYED-BA]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) && ++ !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [MAX-AMSDU-7935]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) && ++ !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [DSSS_CCK-40]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) && ++ !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [LSIG-TXOP-PROT]"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++#ifdef CONFIG_IEEE80211AC ++ ++static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name) ++{ ++ u32 req_cap = conf & cap; ++ ++ /* ++ * Make sure we support all requested capabilities. ++ * NOTE: We assume that 'cap' represents a capability mask, ++ * not a discrete value. ++ */ ++ if ((hw & req_cap) != req_cap) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]", ++ name); ++ return 0; ++ } ++ return 1; ++} ++ ++ ++static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask, ++ unsigned int shift, ++ const char *name) ++{ ++ u32 hw_max = hw & mask; ++ u32 conf_val = conf & mask; ++ ++ if (conf_val > hw_max) { ++ wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)", ++ name, conf_val >> shift, hw_max >> shift); ++ return 0; ++ } ++ return 1; ++} ++ ++ ++static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface) ++{ ++ struct hostapd_hw_modes *mode = iface->current_mode; ++ u32 hw = mode->vht_capab; ++ u32 conf = iface->conf->vht_capab; ++ ++ wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x", ++ hw, conf); ++ ++ if (mode->mode == HOSTAPD_MODE_IEEE80211G && ++ iface->conf->bss[0]->vendor_vht && ++ mode->vht_capab == 0 && iface->hw_features) { ++ int i; ++ ++ for (i = 0; i < iface->num_hw_features; i++) { ++ if (iface->hw_features[i].mode == ++ HOSTAPD_MODE_IEEE80211A) { ++ mode = &iface->hw_features[i]; ++ hw = mode->vht_capab; ++ wpa_printf(MSG_DEBUG, ++ "update hw vht capab based on 5 GHz band: 0x%x", ++ hw); ++ break; ++ } ++ } ++ } ++ ++#define VHT_CAP_CHECK(cap) \ ++ do { \ ++ if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \ ++ return 0; \ ++ } while (0) ++ ++#define VHT_CAP_CHECK_MAX(cap) \ ++ do { \ ++ if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \ ++ #cap)) \ ++ return 0; \ ++ } while (0) ++ ++ VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK); ++ VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ); ++ VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ); ++ VHT_CAP_CHECK(VHT_CAP_RXLDPC); ++ VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80); ++ VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160); ++ VHT_CAP_CHECK(VHT_CAP_TXSTBC); ++ VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK); ++ VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE); ++ VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE); ++ VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX); ++ VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX); ++ VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE); ++ VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE); ++ VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS); ++ VHT_CAP_CHECK(VHT_CAP_HTC_VHT); ++ VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX); ++ VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB); ++ VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB); ++ VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN); ++ VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN); ++ ++#undef VHT_CAP_CHECK ++#undef VHT_CAP_CHECK_MAX ++ ++ return 1; ++} ++#endif /* CONFIG_IEEE80211AC */ ++ ++#endif /* CONFIG_IEEE80211N */ ++ ++ ++int hostapd_check_ht_capab(struct hostapd_iface *iface) ++{ ++#ifdef CONFIG_IEEE80211N ++ int ret; ++ if (!iface->conf->ieee80211n) ++ return 0; ++ ++ if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211B && ++ iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G && ++ (iface->conf->ht_capab & HT_CAP_INFO_DSSS_CCK40MHZ)) { ++ wpa_printf(MSG_DEBUG, ++ "Disable HT capability [DSSS_CCK-40] on 5 GHz band"); ++ iface->conf->ht_capab &= ~HT_CAP_INFO_DSSS_CCK40MHZ; ++ } ++ ++ if (!ieee80211n_supported_ht_capab(iface)) ++ return -1; ++#ifdef CONFIG_IEEE80211AC ++ if (!ieee80211ac_supported_vht_capab(iface)) ++ return -1; ++#endif /* CONFIG_IEEE80211AC */ ++ ret = ieee80211n_check_40mhz(iface); ++ if (ret) ++ return ret; ++ if (!ieee80211n_allowed_ht40_channel_pair(iface)) ++ return -1; ++#endif /* CONFIG_IEEE80211N */ ++ ++ return 0; ++} ++ ++ ++static int hostapd_is_usable_chan(struct hostapd_iface *iface, ++ int channel, int primary) ++{ ++ int i; ++ struct hostapd_channel_data *chan; ++ ++ if (!iface->current_mode) ++ return 0; ++ ++ 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", ++ primary ? "" : "Configured HT40 secondary ", ++ i, chan->chan, chan->flag, ++ chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "", ++ 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 or channel=acs_survey ++ * which is used to trigger ACS. ++ */ ++ ++ switch (acs_init(iface)) { ++ case HOSTAPD_CHAN_ACS: ++ return HOSTAPD_CHAN_ACS; ++ case HOSTAPD_CHAN_VALID: ++ case HOSTAPD_CHAN_INVALID: ++ default: ++ return HOSTAPD_CHAN_INVALID; ++ } ++} ++ ++ ++static void hostapd_notify_bad_chans(struct hostapd_iface *iface) ++{ ++ if (!iface->current_mode) { ++ hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, ++ HOSTAPD_LEVEL_WARNING, ++ "Hardware does not support configured mode"); ++ return; ++ } ++ 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"); ++} ++ ++ ++int hostapd_acs_completed(struct hostapd_iface *iface, int err) ++{ ++ int ret = -1; ++ ++ if (err) ++ goto out; ++ ++ switch (hostapd_check_chans(iface)) { ++ case HOSTAPD_CHAN_VALID: ++ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ++ ACS_EVENT_COMPLETED "freq=%d channel=%d", ++ hostapd_hw_get_freq(iface->bss[0], ++ iface->conf->channel), ++ iface->conf->channel); ++ break; ++ case HOSTAPD_CHAN_ACS: ++ wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available"); ++ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED); ++ hostapd_notify_bad_chans(iface); ++ goto out; ++ case HOSTAPD_CHAN_INVALID: ++ default: ++ wpa_printf(MSG_ERROR, "ACS picked unusable channels"); ++ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED); ++ hostapd_notify_bad_chans(iface); ++ goto out; ++ } ++ ++ ret = hostapd_check_ht_capab(iface); ++ if (ret < 0) ++ goto out; ++ if (ret == 1) { ++ wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback"); ++ return 0; ++ } ++ ++ ret = 0; ++out: ++ return hostapd_setup_interface_complete(iface, ret); ++} ++ ++ ++/** ++ * hostapd_select_hw_mode - Select the hardware mode ++ * @iface: Pointer to interface data. ++ * Returns: 0 on success, < 0 on failure ++ * ++ * Sets up the hardware mode, channel, rates, and passive scanning ++ * based on the configuration. ++ */ ++int hostapd_select_hw_mode(struct hostapd_iface *iface) ++{ ++ int i; ++ ++ if (iface->num_hw_features < 1) ++ return -1; ++ ++ if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G || ++ iface->conf->ieee80211n || iface->conf->ieee80211ac) && ++ iface->conf->channel == 14) { ++ wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14"); ++ iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B; ++ iface->conf->ieee80211n = 0; ++ iface->conf->ieee80211ac = 0; ++ } ++ ++ iface->current_mode = NULL; ++ for (i = 0; i < iface->num_hw_features; i++) { ++ struct hostapd_hw_modes *mode = &iface->hw_features[i]; ++ if (mode->mode == iface->conf->hw_mode) { ++ iface->current_mode = mode; ++ break; ++ } ++ } ++ ++ if (iface->current_mode == NULL) { ++ if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) || ++ !(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY)) ++ { ++ wpa_printf(MSG_ERROR, ++ "Hardware does not support configured mode"); ++ hostapd_logger(iface->bss[0], NULL, ++ HOSTAPD_MODULE_IEEE80211, ++ HOSTAPD_LEVEL_WARNING, ++ "Hardware does not support configured mode (%d) (hw_mode in hostapd.conf)", ++ (int) iface->conf->hw_mode); ++ return -2; ++ } ++ } ++ ++ switch (hostapd_check_chans(iface)) { ++ case HOSTAPD_CHAN_VALID: ++ return 0; ++ case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */ ++ return 1; ++ case HOSTAPD_CHAN_INVALID: ++ default: ++ hostapd_notify_bad_chans(iface); ++ return -3; ++ } ++} ++ ++ ++const char * hostapd_hw_mode_txt(int mode) ++{ ++ switch (mode) { ++ case HOSTAPD_MODE_IEEE80211A: ++ return "IEEE 802.11a"; ++ case HOSTAPD_MODE_IEEE80211B: ++ return "IEEE 802.11b"; ++ case HOSTAPD_MODE_IEEE80211G: ++ return "IEEE 802.11g"; ++ case HOSTAPD_MODE_IEEE80211AD: ++ return "IEEE 802.11ad"; ++ default: ++ return "UNKNOWN"; ++ } ++} ++ ++ ++int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) ++{ ++ return hw_get_freq(hapd->iface->current_mode, chan); ++} ++ ++ ++int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq) ++{ ++ return hw_get_chan(hapd->iface->current_mode, freq); ++} diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c index bab1f03..555d0d8 100644 --- a/src/drivers/driver_bsd.c +++ b/src/drivers/driver_bsd.c @@ -47,6 +47,12 @@ - + #include "l2_packet/l2_packet.h" - + +#ifdef HOSTAPD +#ifdef CONFIG_SUPPORT_RTW_DRIVER +#define RTW_BSD_HOSTAPD_SET_BEACON (1100) @@ -869,11 +3115,11 @@ index bab1f03..555d0d8 100644 + struct bsd_driver_data { struct hostapd_data *hapd; /* back pointer */ - + @@ -800,6 +806,296 @@ handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) drv_event_eapol_rx(drv->hapd, src_addr, buf, len); } - + +#ifdef CONFIG_SUPPORT_RTW_DRIVER +static int rtw_set_beacon_ops(void *priv, const u8 *head, size_t head_len, + const u8 *tail, size_t tail_len, int dtim_period, @@ -1136,13 +3382,13 @@ index bab1f03..555d0d8 100644 +static int rtw_set_wps_beacon_ie(void *priv, const void *ie, size_t len) +{ + return bsd_set80211(priv, IEEE80211_IOC_APPIE, RTW_IEEE80211_APPIE_BEACON, -+ ie, len); ++ ie, len); +} + +static int rtw_set_wps_probe_resp_ie(void *priv, const void *ie, size_t len) +{ + return bsd_set80211(priv, IEEE80211_IOC_APPIE, RTW_IEEE80211_APPIE_PROBE_RESP, -+ ie, len); ++ ie, len); +} + +static int rtw_set_ap_wps_ie_ops(void *priv, const struct wpabuf *beacon, @@ -1170,7 +3416,7 @@ index bab1f03..555d0d8 100644 @@ -854,6 +1150,12 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) goto bad; } - + +#ifdef CONFIG_SUPPORT_RTW_DRIVER + /* mark up after init */ + if (bsd_ctrl_iface(drv, 1) < 0) @@ -1199,7 +3445,7 @@ index bab1f03..555d0d8 100644 @@ -1609,7 +1920,52 @@ wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa) } #endif /* HOSTAPD */ - + - +#ifdef CONFIG_SUPPORT_RTW_DRIVER +const struct wpa_driver_ops wpa_driver_bsd_ops = { @@ -1255,6 +3501,1658 @@ index bab1f03..555d0d8 100644 .set_generic_elem = bsd_set_opt_ie, }; +#endif +diff --git a/src/drivers/driver_bsd.c.orig b/src/drivers/driver_bsd.c.orig +new file mode 100644 +index 0000000..bab1f03 +--- /dev/null ++++ b/src/drivers/driver_bsd.c.orig +@@ -0,0 +1,1646 @@ ++/* ++ * WPA Supplicant - driver interaction with BSD net80211 layer ++ * Copyright (c) 2004, Sam Leffler ++ * Copyright (c) 2004, 2Wire, Inc ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ */ ++ ++#include "includes.h" ++#include ++#include ++ ++#include "common.h" ++#include "driver.h" ++#include "eloop.h" ++#include "common/ieee802_11_defs.h" ++#include "common/wpa_common.h" ++ ++#include ++#include ++ ++#ifdef __NetBSD__ ++#include ++#else ++#include ++#endif ++#include ++ ++#ifdef __DragonFly__ ++#include ++#include ++#else /* __DragonFly__ */ ++#ifdef __GLIBC__ ++#include ++#endif /* __GLIBC__ */ ++#include ++#include ++#include ++#endif /* __DragonFly__ || __GLIBC__ */ ++#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) ++#include ++#endif ++#if __NetBSD__ ++#include ++#endif ++ ++#include "l2_packet/l2_packet.h" ++ ++struct bsd_driver_data { ++ struct hostapd_data *hapd; /* back pointer */ ++ ++ int sock; /* open socket for 802.11 ioctls */ ++ struct l2_packet_data *sock_xmit;/* raw packet xmit socket */ ++ int route; /* routing socket for events */ ++ char ifname[IFNAMSIZ+1]; /* interface name */ ++ unsigned int ifindex; /* interface index */ ++ void *ctx; ++ struct wpa_driver_capa capa; /* driver capability */ ++ int is_ap; /* Access point mode */ ++ int prev_roaming; /* roaming state to restore on deinit */ ++ int prev_privacy; /* privacy state to restore on deinit */ ++ int prev_wpa; /* wpa state to restore on deinit */ ++ enum ieee80211_opmode opmode; /* operation mode */ ++ char *event_buf; ++ size_t event_buf_len; ++}; ++ ++/* Generic functions for hostapd and wpa_supplicant */ ++ ++static int ++bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len) ++{ ++ struct bsd_driver_data *drv = priv; ++ struct ieee80211req ireq; ++ ++ os_memset(&ireq, 0, sizeof(ireq)); ++ os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name)); ++ ireq.i_type = op; ++ ireq.i_val = val; ++ ireq.i_data = (void *) arg; ++ ireq.i_len = arg_len; ++ ++ if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, " ++ "arg_len=%u]: %s", op, val, arg_len, ++ strerror(errno)); ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg, ++ int arg_len) ++{ ++ struct bsd_driver_data *drv = priv; ++ ++ os_memset(ireq, 0, sizeof(*ireq)); ++ os_strlcpy(ireq->i_name, drv->ifname, sizeof(ireq->i_name)); ++ ireq->i_type = op; ++ ireq->i_len = arg_len; ++ ireq->i_data = arg; ++ ++ if (ioctl(drv->sock, SIOCG80211, ireq) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, " ++ "arg_len=%u]: %s", op, arg_len, strerror(errno)); ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++get80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len) ++{ ++ struct ieee80211req ireq; ++ ++ if (bsd_get80211(drv, &ireq, op, arg, arg_len) < 0) ++ return -1; ++ return ireq.i_len; ++} ++ ++static int ++set80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len) ++{ ++ return bsd_set80211(drv, op, 0, arg, arg_len); ++} ++ ++static int ++set80211param(struct bsd_driver_data *drv, int op, int arg) ++{ ++ return bsd_set80211(drv, op, arg, NULL, 0); ++} ++ ++static int ++bsd_get_ssid(void *priv, u8 *ssid, int len) ++{ ++ struct bsd_driver_data *drv = priv; ++#ifdef SIOCG80211NWID ++ struct ieee80211_nwid nwid; ++ struct ifreq ifr; ++ ++ os_memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); ++ ifr.ifr_data = (void *)&nwid; ++ if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 || ++ nwid.i_len > IEEE80211_NWID_LEN) ++ return -1; ++ os_memcpy(ssid, nwid.i_nwid, nwid.i_len); ++ return nwid.i_len; ++#else ++ return get80211var(drv, IEEE80211_IOC_SSID, ssid, IEEE80211_NWID_LEN); ++#endif ++} ++ ++static int ++bsd_set_ssid(void *priv, const u8 *ssid, int ssid_len) ++{ ++ struct bsd_driver_data *drv = priv; ++#ifdef SIOCS80211NWID ++ struct ieee80211_nwid nwid; ++ struct ifreq ifr; ++ ++ os_memcpy(nwid.i_nwid, ssid, ssid_len); ++ nwid.i_len = ssid_len; ++ os_memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); ++ ifr.ifr_data = (void *)&nwid; ++ return ioctl(drv->sock, SIOCS80211NWID, &ifr); ++#else ++ return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len); ++#endif ++} ++ ++static int ++bsd_get_if_media(void *priv) ++{ ++ struct bsd_driver_data *drv = priv; ++ struct ifmediareq ifmr; ++ ++ os_memset(&ifmr, 0, sizeof(ifmr)); ++ os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name)); ++ ++ if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) { ++ wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__, ++ strerror(errno)); ++ return -1; ++ } ++ ++ return ifmr.ifm_current; ++} ++ ++static int ++bsd_set_if_media(void *priv, int media) ++{ ++ struct bsd_driver_data *drv = priv; ++ struct ifreq ifr; ++ ++ os_memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); ++ ifr.ifr_media = media; ++ ++ if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) { ++ wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__, ++ strerror(errno)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++bsd_set_mediaopt(void *priv, uint32_t mask, uint32_t mode) ++{ ++ int media = bsd_get_if_media(priv); ++ ++ if (media < 0) ++ return -1; ++ media &= ~mask; ++ media |= mode; ++ if (bsd_set_if_media(priv, media) < 0) ++ return -1; ++ return 0; ++} ++ ++static int ++bsd_del_key(void *priv, const u8 *addr, int key_idx) ++{ ++ struct ieee80211req_del_key wk; ++ ++ os_memset(&wk, 0, sizeof(wk)); ++ if (addr == NULL) { ++ wpa_printf(MSG_DEBUG, "%s: key_idx=%d", __func__, key_idx); ++ wk.idk_keyix = key_idx; ++ } else { ++ wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, ++ MAC2STR(addr)); ++ os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); ++ wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE; /* XXX */ ++ } ++ ++ return set80211var(priv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk)); ++} ++ ++static int ++bsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr) ++{ ++ struct ieee80211req_mlme mlme; ++ ++ os_memset(&mlme, 0, sizeof(mlme)); ++ mlme.im_op = op; ++ mlme.im_reason = reason; ++ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); ++ return set80211var(priv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); ++} ++ ++static int ++bsd_ctrl_iface(void *priv, int enable) ++{ ++ struct bsd_driver_data *drv = priv; ++ struct ifreq ifr; ++ ++ os_memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); ++ ++ if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s", ++ strerror(errno)); ++ return -1; ++ } ++ ++ if (enable) { ++ if (ifr.ifr_flags & IFF_UP) ++ return 0; ++ ifr.ifr_flags |= IFF_UP; ++ } else { ++ if (!(ifr.ifr_flags & IFF_UP)) ++ return 0; ++ ifr.ifr_flags &= ~IFF_UP; ++ } ++ ++ if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s", ++ strerror(errno)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg, ++ const unsigned char *addr, int key_idx, int set_tx, const u8 *seq, ++ size_t seq_len, const u8 *key, size_t key_len) ++{ ++ struct ieee80211req_key wk; ++#ifdef IEEE80211_KEY_NOREPLAY ++ struct bsd_driver_data *drv = priv; ++#endif /* IEEE80211_KEY_NOREPLAY */ ++ ++ wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d " ++ "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx, ++ set_tx, seq_len, key_len); ++ ++ if (alg == WPA_ALG_NONE) { ++#ifndef HOSTAPD ++ if (addr == NULL || is_broadcast_ether_addr(addr)) ++ return bsd_del_key(priv, NULL, key_idx); ++ else ++#endif /* HOSTAPD */ ++ return bsd_del_key(priv, addr, key_idx); ++ } ++ ++ os_memset(&wk, 0, sizeof(wk)); ++ switch (alg) { ++ case WPA_ALG_WEP: ++ wk.ik_type = IEEE80211_CIPHER_WEP; ++ break; ++ case WPA_ALG_TKIP: ++ wk.ik_type = IEEE80211_CIPHER_TKIP; ++ break; ++ case WPA_ALG_CCMP: ++ wk.ik_type = IEEE80211_CIPHER_AES_CCM; ++ break; ++ default: ++ wpa_printf(MSG_ERROR, "%s: unknown alg=%d", __func__, alg); ++ return -1; ++ } ++ ++ wk.ik_flags = IEEE80211_KEY_RECV; ++ if (set_tx) ++ wk.ik_flags |= IEEE80211_KEY_XMIT; ++ ++ if (addr == NULL) { ++ os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); ++ wk.ik_keyix = key_idx; ++ } else { ++ os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); ++ /* ++ * Deduce whether group/global or unicast key by checking ++ * the address (yech). Note also that we can only mark global ++ * keys default; doing this for a unicast key is an error. ++ */ ++ if (is_broadcast_ether_addr(addr)) { ++ wk.ik_flags |= IEEE80211_KEY_GROUP; ++ wk.ik_keyix = key_idx; ++ } else { ++ wk.ik_keyix = key_idx == 0 ? IEEE80211_KEYIX_NONE : ++ key_idx; ++ } ++ } ++ if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx) ++ wk.ik_flags |= IEEE80211_KEY_DEFAULT; ++#ifndef HOSTAPD ++#ifdef IEEE80211_KEY_NOREPLAY ++ /* ++ * Ignore replay failures in IBSS and AHDEMO mode. ++ */ ++ if (drv->opmode == IEEE80211_M_IBSS || ++ drv->opmode == IEEE80211_M_AHDEMO) ++ wk.ik_flags |= IEEE80211_KEY_NOREPLAY; ++#endif /* IEEE80211_KEY_NOREPLAY */ ++#endif /* HOSTAPD */ ++ wk.ik_keylen = key_len; ++ if (seq) { ++#ifdef WORDS_BIGENDIAN ++ /* ++ * wk.ik_keyrsc is in host byte order (big endian), need to ++ * swap it to match with the byte order used in WPA. ++ */ ++ int i; ++ u8 *keyrsc = (u8 *) &wk.ik_keyrsc; ++ for (i = 0; i < seq_len; i++) ++ keyrsc[WPA_KEY_RSC_LEN - i - 1] = seq[i]; ++#else /* WORDS_BIGENDIAN */ ++ os_memcpy(&wk.ik_keyrsc, seq, seq_len); ++#endif /* WORDS_BIGENDIAN */ ++ } ++ os_memcpy(wk.ik_keydata, key, key_len); ++ ++ return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)); ++} ++ ++static int ++bsd_configure_wpa(void *priv, struct wpa_bss_params *params) ++{ ++#ifndef IEEE80211_IOC_APPIE ++ static const char *ciphernames[] = ++ { "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" }; ++ int v; ++ ++ switch (params->wpa_group) { ++ case WPA_CIPHER_CCMP: ++ v = IEEE80211_CIPHER_AES_CCM; ++ break; ++ case WPA_CIPHER_TKIP: ++ v = IEEE80211_CIPHER_TKIP; ++ break; ++ case WPA_CIPHER_WEP104: ++ v = IEEE80211_CIPHER_WEP; ++ break; ++ case WPA_CIPHER_WEP40: ++ v = IEEE80211_CIPHER_WEP; ++ break; ++ case WPA_CIPHER_NONE: ++ v = IEEE80211_CIPHER_NONE; ++ break; ++ default: ++ wpa_printf(MSG_INFO, "Unknown group key cipher %u", ++ params->wpa_group); ++ return -1; ++ } ++ wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)", ++ __func__, ciphernames[v], v); ++ if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) { ++ wpa_printf(MSG_INFO, ++ "Unable to set group key cipher to %u (%s)", ++ v, ciphernames[v]); ++ return -1; ++ } ++ if (v == IEEE80211_CIPHER_WEP) { ++ /* key length is done only for specific ciphers */ ++ v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); ++ if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) { ++ wpa_printf(MSG_INFO, ++ "Unable to set group key length to %u", v); ++ return -1; ++ } ++ } ++ ++ v = 0; ++ if (params->wpa_pairwise & WPA_CIPHER_CCMP) ++ v |= 1<wpa_pairwise & WPA_CIPHER_TKIP) ++ v |= 1<wpa_pairwise & WPA_CIPHER_NONE) ++ v |= 1<wpa_key_mgmt); ++ if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS, ++ params->wpa_key_mgmt)) { ++ wpa_printf(MSG_INFO, ++ "Unable to set key management algorithms to 0x%x", ++ params->wpa_key_mgmt); ++ return -1; ++ } ++ ++ v = 0; ++ if (params->rsn_preauth) ++ v |= BIT(0); ++ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", ++ __func__, params->rsn_preauth); ++ if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) { ++ wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x", ++ v); ++ return -1; ++ } ++#endif /* IEEE80211_IOC_APPIE */ ++ ++ wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa); ++ if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) { ++ wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa); ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++bsd_set_ieee8021x(void *priv, struct wpa_bss_params *params) ++{ ++ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); ++ ++ if (!params->enabled) { ++ /* XXX restore state */ ++ return set80211param(priv, IEEE80211_IOC_AUTHMODE, ++ IEEE80211_AUTH_AUTO); ++ } ++ if (!params->wpa && !params->ieee802_1x) { ++ wpa_printf(MSG_ERROR, "%s: No 802.1X or WPA enabled", ++ __func__); ++ return -1; ++ } ++ if (params->wpa && bsd_configure_wpa(priv, params) != 0) { ++ wpa_printf(MSG_ERROR, "%s: Failed to configure WPA state", ++ __func__); ++ return -1; ++ } ++ if (set80211param(priv, IEEE80211_IOC_AUTHMODE, ++ (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { ++ wpa_printf(MSG_ERROR, "%s: Failed to enable WPA/802.1X", ++ __func__); ++ return -1; ++ } ++ return bsd_ctrl_iface(priv, 1); ++} ++ ++static void ++bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN]) ++{ ++ struct ieee80211req_wpaie ie; ++ int ielen = 0; ++ u8 *iebuf = NULL; ++ ++ /* ++ * Fetch and validate any negotiated WPA/RSN parameters. ++ */ ++ memset(&ie, 0, sizeof(ie)); ++ memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); ++ if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) { ++ wpa_printf(MSG_INFO, ++ "Failed to get WPA/RSN information element"); ++ goto no_ie; ++ } ++ iebuf = ie.wpa_ie; ++ ielen = ie.wpa_ie[1]; ++ if (ielen == 0) ++ iebuf = NULL; ++ else ++ ielen += 2; ++ ++no_ie: ++ drv_event_assoc(ctx, addr, iebuf, ielen, 0); ++} ++ ++static int ++bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, ++ int encrypt, const u8 *own_addr, u32 flags) ++{ ++ struct bsd_driver_data *drv = priv; ++ ++ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", data, data_len); ++ ++ return l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, data, ++ data_len); ++} ++ ++static int ++bsd_set_freq(void *priv, struct hostapd_freq_params *freq) ++{ ++ struct bsd_driver_data *drv = priv; ++#ifdef SIOCS80211CHANNEL ++ struct ieee80211chanreq creq; ++#endif /* SIOCS80211CHANNEL */ ++ u32 mode; ++ int channel = freq->channel; ++ ++ if (channel < 14) { ++ mode = ++#ifdef CONFIG_IEEE80211N ++ freq->ht_enabled ? IFM_IEEE80211_11NG : ++#endif /* CONFIG_IEEE80211N */ ++ IFM_IEEE80211_11G; ++ } else if (channel == 14) { ++ mode = IFM_IEEE80211_11B; ++ } else { ++ mode = ++#ifdef CONFIG_IEEE80211N ++ freq->ht_enabled ? IFM_IEEE80211_11NA : ++#endif /* CONFIG_IEEE80211N */ ++ IFM_IEEE80211_11A; ++ } ++ if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) { ++ wpa_printf(MSG_ERROR, "%s: failed to set modulation mode", ++ __func__); ++ return -1; ++ } ++ ++#ifdef SIOCS80211CHANNEL ++ os_memset(&creq, 0, sizeof(creq)); ++ os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name)); ++ creq.i_channel = (u_int16_t)channel; ++ return ioctl(drv->sock, SIOCS80211CHANNEL, &creq); ++#else /* SIOCS80211CHANNEL */ ++ return set80211param(priv, IEEE80211_IOC_CHANNEL, channel); ++#endif /* SIOCS80211CHANNEL */ ++} ++ ++static int ++bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) ++{ ++#ifdef IEEE80211_IOC_APPIE ++ wpa_printf(MSG_DEBUG, "%s: set WPA+RSN ie (len %lu)", __func__, ++ (unsigned long)ie_len); ++ return bsd_set80211(priv, IEEE80211_IOC_APPIE, IEEE80211_APPIE_WPA, ++ ie, ie_len); ++#endif /* IEEE80211_IOC_APPIE */ ++ return 0; ++} ++ ++static size_t ++rtbuf_len(void) ++{ ++ size_t len; ++ ++ int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0}; ++ ++ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { ++ wpa_printf(MSG_WARNING, "%s failed: %s", __func__, ++ strerror(errno)); ++ len = 2048; ++ } ++ ++ return len; ++} ++ ++#ifdef HOSTAPD ++ ++/* ++ * Avoid conflicts with hostapd definitions by undefining couple of defines ++ * from net80211 header files. ++ */ ++#undef RSN_VERSION ++#undef WPA_VERSION ++#undef WPA_OUI_TYPE ++ ++static int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, ++ int reason_code); ++ ++static const char * ++ether_sprintf(const u8 *addr) ++{ ++ static char buf[sizeof(MACSTR)]; ++ ++ if (addr != NULL) ++ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); ++ else ++ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); ++ return buf; ++} ++ ++static int ++bsd_set_privacy(void *priv, int enabled) ++{ ++ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); ++ ++ return set80211param(priv, IEEE80211_IOC_PRIVACY, enabled); ++} ++ ++static int ++bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, ++ u8 *seq) ++{ ++ struct ieee80211req_key wk; ++ ++ wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", ++ __func__, ether_sprintf(addr), idx); ++ ++ memset(&wk, 0, sizeof(wk)); ++ if (addr == NULL) ++ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); ++ else ++ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); ++ wk.ik_keyix = idx; ++ ++ if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) { ++ wpa_printf(MSG_INFO, "Failed to get encryption"); ++ return -1; ++ } ++ ++#ifdef WORDS_BIGENDIAN ++ { ++ /* ++ * wk.ik_keytsc is in host byte order (big endian), need to ++ * swap it to match with the byte order used in WPA. ++ */ ++ int i; ++ u8 tmp[WPA_KEY_RSC_LEN]; ++ memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); ++ for (i = 0; i < WPA_KEY_RSC_LEN; i++) { ++ seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; ++ } ++ } ++#else /* WORDS_BIGENDIAN */ ++ memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); ++#endif /* WORDS_BIGENDIAN */ ++ return 0; ++} ++ ++ ++static int ++bsd_flush(void *priv) ++{ ++ u8 allsta[IEEE80211_ADDR_LEN]; ++ ++ memset(allsta, 0xff, IEEE80211_ADDR_LEN); ++ return bsd_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE); ++} ++ ++ ++static int ++bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, ++ const u8 *addr) ++{ ++ struct ieee80211req_sta_stats stats; ++ ++ memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); ++ if (get80211var(priv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats)) ++ > 0) { ++ /* XXX? do packets counts include non-data frames? */ ++ data->rx_packets = stats.is_stats.ns_rx_data; ++ data->rx_bytes = stats.is_stats.ns_rx_bytes; ++ data->tx_packets = stats.is_stats.ns_tx_data; ++ data->tx_bytes = stats.is_stats.ns_tx_bytes; ++ } ++ return 0; ++} ++ ++static int ++bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code) ++{ ++ return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, ++ addr); ++} ++ ++static int ++bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, ++ int reason_code) ++{ ++ return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code, ++ addr); ++} ++ ++static void ++bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) ++{ ++ struct bsd_driver_data *drv = ctx; ++ struct if_announcemsghdr *ifan; ++ struct rt_msghdr *rtm; ++ struct ieee80211_michael_event *mic; ++ struct ieee80211_join_event *join; ++ struct ieee80211_leave_event *leave; ++ int n; ++ union wpa_event_data data; ++ ++ n = read(sock, drv->event_buf, drv->event_buf_len); ++ if (n < 0) { ++ if (errno != EINTR && errno != EAGAIN) ++ wpa_printf(MSG_ERROR, "%s read() failed: %s", ++ __func__, strerror(errno)); ++ return; ++ } ++ ++ rtm = (struct rt_msghdr *) drv->event_buf; ++ if (rtm->rtm_version != RTM_VERSION) { ++ wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", ++ rtm->rtm_version); ++ return; ++ } ++ ifan = (struct if_announcemsghdr *) rtm; ++ switch (rtm->rtm_type) { ++ case RTM_IEEE80211: ++ switch (ifan->ifan_what) { ++ case RTM_IEEE80211_ASSOC: ++ case RTM_IEEE80211_REASSOC: ++ case RTM_IEEE80211_DISASSOC: ++ case RTM_IEEE80211_SCAN: ++ break; ++ case RTM_IEEE80211_LEAVE: ++ leave = (struct ieee80211_leave_event *) &ifan[1]; ++ drv_event_disassoc(drv->hapd, leave->iev_addr); ++ break; ++ case RTM_IEEE80211_JOIN: ++#ifdef RTM_IEEE80211_REJOIN ++ case RTM_IEEE80211_REJOIN: ++#endif ++ join = (struct ieee80211_join_event *) &ifan[1]; ++ bsd_new_sta(drv, drv->hapd, join->iev_addr); ++ break; ++ case RTM_IEEE80211_REPLAY: ++ /* ignore */ ++ break; ++ case RTM_IEEE80211_MICHAEL: ++ mic = (struct ieee80211_michael_event *) &ifan[1]; ++ wpa_printf(MSG_DEBUG, ++ "Michael MIC failure wireless event: " ++ "keyix=%u src_addr=" MACSTR, mic->iev_keyix, ++ MAC2STR(mic->iev_src)); ++ os_memset(&data, 0, sizeof(data)); ++ data.michael_mic_failure.unicast = 1; ++ data.michael_mic_failure.src = mic->iev_src; ++ wpa_supplicant_event(drv->hapd, ++ EVENT_MICHAEL_MIC_FAILURE, &data); ++ break; ++ } ++ break; ++ } ++} ++ ++static void ++handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) ++{ ++ struct bsd_driver_data *drv = ctx; ++ drv_event_eapol_rx(drv->hapd, src_addr, buf, len); ++} ++ ++static void * ++bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) ++{ ++ struct bsd_driver_data *drv; ++ ++ drv = os_zalloc(sizeof(struct bsd_driver_data)); ++ if (drv == NULL) { ++ wpa_printf(MSG_ERROR, "Could not allocate memory for bsd driver data"); ++ return NULL; ++ } ++ ++ drv->event_buf_len = rtbuf_len(); ++ ++ drv->event_buf = os_malloc(drv->event_buf_len); ++ if (drv->event_buf == NULL) { ++ wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__); ++ goto bad; ++ } ++ ++ drv->hapd = hapd; ++ drv->sock = socket(PF_INET, SOCK_DGRAM, 0); ++ if (drv->sock < 0) { ++ wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s", ++ strerror(errno)); ++ goto bad; ++ } ++ os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); ++ ++ drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, ++ handle_read, drv, 0); ++ if (drv->sock_xmit == NULL) ++ goto bad; ++ if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) ++ goto bad; ++ ++ /* mark down during setup */ ++ if (bsd_ctrl_iface(drv, 0) < 0) ++ goto bad; ++ ++ drv->route = socket(PF_ROUTE, SOCK_RAW, 0); ++ if (drv->route < 0) { ++ wpa_printf(MSG_ERROR, "socket(PF_ROUTE,SOCK_RAW): %s", ++ strerror(errno)); ++ goto bad; ++ } ++ eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv, ++ NULL); ++ ++ if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) { ++ wpa_printf(MSG_ERROR, "%s: failed to set operation mode", ++ __func__); ++ goto bad; ++ } ++ ++ return drv; ++bad: ++ if (drv->sock_xmit != NULL) ++ l2_packet_deinit(drv->sock_xmit); ++ if (drv->sock >= 0) ++ close(drv->sock); ++ os_free(drv->event_buf); ++ os_free(drv); ++ return NULL; ++} ++ ++ ++static void ++bsd_deinit(void *priv) ++{ ++ struct bsd_driver_data *drv = priv; ++ ++ if (drv->route >= 0) { ++ eloop_unregister_read_sock(drv->route); ++ close(drv->route); ++ } ++ bsd_ctrl_iface(drv, 0); ++ if (drv->sock >= 0) ++ close(drv->sock); ++ if (drv->sock_xmit != NULL) ++ l2_packet_deinit(drv->sock_xmit); ++ os_free(drv->event_buf); ++ os_free(drv); ++} ++ ++ ++static int ++bsd_commit(void *priv) ++{ ++ return bsd_ctrl_iface(priv, 1); ++} ++ ++ ++static int ++bsd_set_sta_authorized(void *priv, const u8 *addr, ++ unsigned int total_flags, unsigned int flags_or, ++ unsigned int flags_and) ++{ ++ int authorized = -1; ++ ++ /* For now, only support setting Authorized flag */ ++ if (flags_or & WPA_STA_AUTHORIZED) ++ authorized = 1; ++ if (!(flags_and & WPA_STA_AUTHORIZED)) ++ authorized = 0; ++ ++ if (authorized < 0) ++ return 0; ++ ++ return bsd_send_mlme_param(priv, authorized ? ++ IEEE80211_MLME_AUTHORIZE : ++ IEEE80211_MLME_UNAUTHORIZE, 0, addr); ++} ++#else /* HOSTAPD */ ++ ++static int ++get80211param(struct bsd_driver_data *drv, int op) ++{ ++ struct ieee80211req ireq; ++ ++ if (bsd_get80211(drv, &ireq, op, NULL, 0) < 0) ++ return -1; ++ return ireq.i_val; ++} ++ ++static int ++wpa_driver_bsd_get_bssid(void *priv, u8 *bssid) ++{ ++ struct bsd_driver_data *drv = priv; ++#ifdef SIOCG80211BSSID ++ struct ieee80211_bssid bs; ++ ++ os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name)); ++ if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0) ++ return -1; ++ os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid)); ++ return 0; ++#else ++ return get80211var(drv, IEEE80211_IOC_BSSID, ++ bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0; ++#endif ++} ++ ++static int ++wpa_driver_bsd_get_ssid(void *priv, u8 *ssid) ++{ ++ struct bsd_driver_data *drv = priv; ++ return bsd_get_ssid(drv, ssid, 0); ++} ++ ++static int ++wpa_driver_bsd_set_wpa_ie(struct bsd_driver_data *drv, const u8 *wpa_ie, ++ size_t wpa_ie_len) ++{ ++#ifdef IEEE80211_IOC_APPIE ++ return bsd_set_opt_ie(drv, wpa_ie, wpa_ie_len); ++#else /* IEEE80211_IOC_APPIE */ ++ return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len); ++#endif /* IEEE80211_IOC_APPIE */ ++} ++ ++static int ++wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy) ++{ ++ int ret = 0; ++ ++ wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d", ++ __FUNCTION__, wpa, privacy); ++ ++ if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0) ++ ret = -1; ++ if (set80211param(priv, IEEE80211_IOC_PRIVACY, privacy) < 0) ++ ret = -1; ++ if (set80211param(priv, IEEE80211_IOC_WPA, wpa) < 0) ++ ret = -1; ++ ++ return ret; ++} ++ ++static int ++wpa_driver_bsd_set_wpa(void *priv, int enabled) ++{ ++ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); ++ ++ return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled); ++} ++ ++static int ++wpa_driver_bsd_set_countermeasures(void *priv, int enabled) ++{ ++ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); ++ return set80211param(priv, IEEE80211_IOC_COUNTERMEASURES, enabled); ++} ++ ++ ++static int ++wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled) ++{ ++ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); ++ return set80211param(priv, IEEE80211_IOC_DROPUNENCRYPTED, enabled); ++} ++ ++static int ++wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code) ++{ ++ return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, ++ addr); ++} ++ ++static int ++wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg) ++{ ++ int authmode; ++ ++ if ((auth_alg & WPA_AUTH_ALG_OPEN) && ++ (auth_alg & WPA_AUTH_ALG_SHARED)) ++ authmode = IEEE80211_AUTH_AUTO; ++ else if (auth_alg & WPA_AUTH_ALG_SHARED) ++ authmode = IEEE80211_AUTH_SHARED; ++ else ++ authmode = IEEE80211_AUTH_OPEN; ++ ++ return set80211param(priv, IEEE80211_IOC_AUTHMODE, authmode); ++} ++ ++static void ++handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) ++{ ++ struct bsd_driver_data *drv = ctx; ++ ++ drv_event_eapol_rx(drv->ctx, src_addr, buf, len); ++} ++ ++static int ++wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params) ++{ ++ struct bsd_driver_data *drv = priv; ++ struct ieee80211req_mlme mlme; ++ u32 mode; ++ int privacy; ++ int ret = 0; ++ ++ wpa_printf(MSG_DEBUG, ++ "%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u" ++ , __func__ ++ , (unsigned int) params->ssid_len, params->ssid ++ , (unsigned int) params->wpa_ie_len ++ , params->pairwise_suite ++ , params->group_suite ++ , params->key_mgmt_suite ++ ); ++ ++ switch (params->mode) { ++ case IEEE80211_MODE_INFRA: ++ mode = 0 /* STA */; ++ break; ++ case IEEE80211_MODE_IBSS: ++ mode = IFM_IEEE80211_IBSS; ++ break; ++ case IEEE80211_MODE_AP: ++ mode = IFM_IEEE80211_HOSTAP; ++ break; ++ default: ++ wpa_printf(MSG_ERROR, "%s: unknown operation mode", __func__); ++ return -1; ++ } ++ if (bsd_set_mediaopt(drv, IFM_OMASK, mode) < 0) { ++ wpa_printf(MSG_ERROR, "%s: failed to set operation mode", ++ __func__); ++ return -1; ++ } ++ ++ if (params->mode == IEEE80211_MODE_AP) { ++ drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, ++ handle_read, drv, 0); ++ if (drv->sock_xmit == NULL) ++ return -1; ++ drv->is_ap = 1; ++ return 0; ++ } ++ ++ if (wpa_driver_bsd_set_drop_unencrypted(drv, params->drop_unencrypted) ++ < 0) ++ ret = -1; ++ if (wpa_driver_bsd_set_auth_alg(drv, params->auth_alg) < 0) ++ ret = -1; ++ /* XXX error handling is wrong but unclear what to do... */ ++ if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0) ++ return -1; ++ ++ privacy = !(params->pairwise_suite == WPA_CIPHER_NONE && ++ params->group_suite == WPA_CIPHER_NONE && ++ params->key_mgmt_suite == WPA_KEY_MGMT_NONE && ++ params->wpa_ie_len == 0); ++ wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy); ++ ++ if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0) ++ return -1; ++ ++ if (params->wpa_ie_len && ++ set80211param(drv, IEEE80211_IOC_WPA, ++ params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0) ++ return -1; ++ ++ os_memset(&mlme, 0, sizeof(mlme)); ++ mlme.im_op = IEEE80211_MLME_ASSOC; ++ if (params->ssid != NULL) ++ os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len); ++ mlme.im_ssid_len = params->ssid_len; ++ if (params->bssid != NULL) ++ os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN); ++ if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0) ++ return -1; ++ return ret; ++} ++ ++static int ++wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params) ++{ ++ struct bsd_driver_data *drv = priv; ++#ifdef IEEE80211_IOC_SCAN_MAX_SSID ++ struct ieee80211_scan_req sr; ++ int i; ++#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ ++ ++ if (bsd_set_mediaopt(drv, IFM_OMASK, 0 /* STA */) < 0) { ++ wpa_printf(MSG_ERROR, "%s: failed to set operation mode", ++ __func__); ++ return -1; ++ } ++ ++ if (set80211param(drv, IEEE80211_IOC_ROAMING, ++ IEEE80211_ROAMING_MANUAL) < 0) { ++ wpa_printf(MSG_ERROR, "%s: failed to set " ++ "wpa_supplicant-based roaming: %s", __func__, ++ strerror(errno)); ++ return -1; ++ } ++ ++ if (wpa_driver_bsd_set_wpa(drv, 1) < 0) { ++ wpa_printf(MSG_ERROR, "%s: failed to set wpa: %s", __func__, ++ strerror(errno)); ++ return -1; ++ } ++ ++ /* NB: interface must be marked UP to do a scan */ ++ if (bsd_ctrl_iface(drv, 1) < 0) ++ return -1; ++ ++#ifdef IEEE80211_IOC_SCAN_MAX_SSID ++ os_memset(&sr, 0, sizeof(sr)); ++ sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE | ++ IEEE80211_IOC_SCAN_NOJOIN; ++ sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; ++ if (params->num_ssids > 0) { ++ sr.sr_nssid = params->num_ssids; ++#if 0 ++ /* Boundary check is done by upper layer */ ++ if (sr.sr_nssid > IEEE80211_IOC_SCAN_MAX_SSID) ++ sr.sr_nssid = IEEE80211_IOC_SCAN_MAX_SSID; ++#endif ++ ++ /* NB: check scan cache first */ ++ sr.sr_flags |= IEEE80211_IOC_SCAN_CHECK; ++ } ++ for (i = 0; i < sr.sr_nssid; i++) { ++ sr.sr_ssid[i].len = params->ssids[i].ssid_len; ++ os_memcpy(sr.sr_ssid[i].ssid, params->ssids[i].ssid, ++ sr.sr_ssid[i].len); ++ } ++ ++ /* NB: net80211 delivers a scan complete event so no need to poll */ ++ return set80211var(drv, IEEE80211_IOC_SCAN_REQ, &sr, sizeof(sr)); ++#else /* IEEE80211_IOC_SCAN_MAX_SSID */ ++ /* set desired ssid before scan */ ++ if (bsd_set_ssid(drv, params->ssids[0].ssid, ++ params->ssids[0].ssid_len) < 0) ++ return -1; ++ ++ /* NB: net80211 delivers a scan complete event so no need to poll */ ++ return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0); ++#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ ++} ++ ++static void ++wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) ++{ ++ struct bsd_driver_data *drv = sock_ctx; ++ struct if_announcemsghdr *ifan; ++ struct if_msghdr *ifm; ++ struct rt_msghdr *rtm; ++ union wpa_event_data event; ++ struct ieee80211_michael_event *mic; ++ struct ieee80211_leave_event *leave; ++ struct ieee80211_join_event *join; ++ int n; ++ ++ n = read(sock, drv->event_buf, drv->event_buf_len); ++ if (n < 0) { ++ if (errno != EINTR && errno != EAGAIN) ++ wpa_printf(MSG_ERROR, "%s read() failed: %s", ++ __func__, strerror(errno)); ++ return; ++ } ++ ++ rtm = (struct rt_msghdr *) drv->event_buf; ++ if (rtm->rtm_version != RTM_VERSION) { ++ wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", ++ rtm->rtm_version); ++ return; ++ } ++ os_memset(&event, 0, sizeof(event)); ++ switch (rtm->rtm_type) { ++ case RTM_IFANNOUNCE: ++ ifan = (struct if_announcemsghdr *) rtm; ++ if (ifan->ifan_index != drv->ifindex) ++ break; ++ os_strlcpy(event.interface_status.ifname, drv->ifname, ++ sizeof(event.interface_status.ifname)); ++ switch (ifan->ifan_what) { ++ case IFAN_DEPARTURE: ++ event.interface_status.ievent = EVENT_INTERFACE_REMOVED; ++ default: ++ return; ++ } ++ wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s", ++ event.interface_status.ifname, ++ ifan->ifan_what == IFAN_DEPARTURE ? ++ "removed" : "added"); ++ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); ++ break; ++ case RTM_IEEE80211: ++ ifan = (struct if_announcemsghdr *) rtm; ++ if (ifan->ifan_index != drv->ifindex) ++ break; ++ switch (ifan->ifan_what) { ++ case RTM_IEEE80211_ASSOC: ++ case RTM_IEEE80211_REASSOC: ++ if (drv->is_ap) ++ break; ++ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); ++ break; ++ case RTM_IEEE80211_DISASSOC: ++ if (drv->is_ap) ++ break; ++ wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL); ++ break; ++ case RTM_IEEE80211_SCAN: ++ if (drv->is_ap) ++ break; ++ wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL); ++ break; ++ case RTM_IEEE80211_LEAVE: ++ leave = (struct ieee80211_leave_event *) &ifan[1]; ++ drv_event_disassoc(ctx, leave->iev_addr); ++ break; ++ case RTM_IEEE80211_JOIN: ++#ifdef RTM_IEEE80211_REJOIN ++ case RTM_IEEE80211_REJOIN: ++#endif ++ join = (struct ieee80211_join_event *) &ifan[1]; ++ bsd_new_sta(drv, ctx, join->iev_addr); ++ break; ++ case RTM_IEEE80211_REPLAY: ++ /* ignore */ ++ break; ++ case RTM_IEEE80211_MICHAEL: ++ mic = (struct ieee80211_michael_event *) &ifan[1]; ++ wpa_printf(MSG_DEBUG, ++ "Michael MIC failure wireless event: " ++ "keyix=%u src_addr=" MACSTR, mic->iev_keyix, ++ MAC2STR(mic->iev_src)); ++ ++ os_memset(&event, 0, sizeof(event)); ++ event.michael_mic_failure.unicast = ++ !IEEE80211_IS_MULTICAST(mic->iev_dst); ++ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, ++ &event); ++ break; ++ } ++ break; ++ case RTM_IFINFO: ++ ifm = (struct if_msghdr *) rtm; ++ if (ifm->ifm_index != drv->ifindex) ++ break; ++ if ((rtm->rtm_flags & RTF_UP) == 0) { ++ os_strlcpy(event.interface_status.ifname, drv->ifname, ++ sizeof(event.interface_status.ifname)); ++ event.interface_status.ievent = EVENT_INTERFACE_REMOVED; ++ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN", ++ event.interface_status.ifname); ++ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); ++ } ++ break; ++ } ++} ++ ++static void ++wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res, ++ struct ieee80211req_scan_result *sr) ++{ ++ struct wpa_scan_res *result, **tmp; ++ size_t extra_len; ++ u8 *pos; ++ ++ extra_len = 2 + sr->isr_ssid_len; ++ extra_len += 2 + sr->isr_nrates; ++ extra_len += 3; /* ERP IE */ ++ extra_len += sr->isr_ie_len; ++ ++ result = os_zalloc(sizeof(*result) + extra_len); ++ if (result == NULL) ++ return; ++ os_memcpy(result->bssid, sr->isr_bssid, ETH_ALEN); ++ result->freq = sr->isr_freq; ++ result->beacon_int = sr->isr_intval; ++ result->caps = sr->isr_capinfo; ++ result->qual = sr->isr_rssi; ++ result->noise = sr->isr_noise; ++ /* ++ * the rssi value reported by the kernel is in 0.5dB steps relative to ++ * the reported noise floor. see ieee80211_node.h for details. ++ */ ++ result->level = sr->isr_rssi / 2 + sr->isr_noise; ++ ++ pos = (u8 *)(result + 1); ++ ++ *pos++ = WLAN_EID_SSID; ++ *pos++ = sr->isr_ssid_len; ++ os_memcpy(pos, sr + 1, sr->isr_ssid_len); ++ pos += sr->isr_ssid_len; ++ ++ /* ++ * Deal all rates as supported rate. ++ * Because net80211 doesn't report extended supported rate or not. ++ */ ++ *pos++ = WLAN_EID_SUPP_RATES; ++ *pos++ = sr->isr_nrates; ++ os_memcpy(pos, sr->isr_rates, sr->isr_nrates); ++ pos += sr->isr_nrates; ++ ++ *pos++ = WLAN_EID_ERP_INFO; ++ *pos++ = 1; ++ *pos++ = sr->isr_erp; ++ ++#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) ++ os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len + sr->isr_meshid_len, ++ sr->isr_ie_len); ++#else ++ os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len); ++#endif ++ pos += sr->isr_ie_len; ++ ++ result->ie_len = pos - (u8 *)(result + 1); ++ ++ tmp = os_realloc_array(res->res, res->num + 1, ++ sizeof(struct wpa_scan_res *)); ++ if (tmp == NULL) { ++ os_free(result); ++ return; ++ } ++ tmp[res->num++] = result; ++ res->res = tmp; ++} ++ ++struct wpa_scan_results * ++wpa_driver_bsd_get_scan_results2(void *priv) ++{ ++ struct ieee80211req_scan_result *sr; ++ struct wpa_scan_results *res; ++ int len, rest; ++ uint8_t buf[24*1024], *pos; ++ ++ len = get80211var(priv, IEEE80211_IOC_SCAN_RESULTS, buf, 24*1024); ++ if (len < 0) ++ return NULL; ++ ++ res = os_zalloc(sizeof(*res)); ++ if (res == NULL) ++ return NULL; ++ ++ pos = buf; ++ rest = len; ++ while (rest >= sizeof(struct ieee80211req_scan_result)) { ++ sr = (struct ieee80211req_scan_result *)pos; ++ wpa_driver_bsd_add_scan_entry(res, sr); ++ pos += sr->isr_len; ++ rest -= sr->isr_len; ++ } ++ ++ wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%lu BSSes)", ++ len, (unsigned long)res->num); ++ ++ return res; ++} ++ ++static int wpa_driver_bsd_capa(struct bsd_driver_data *drv) ++{ ++#ifdef IEEE80211_IOC_DEVCAPS ++/* kernel definitions copied from net80211/ieee80211_var.h */ ++#define IEEE80211_CIPHER_WEP 0 ++#define IEEE80211_CIPHER_TKIP 1 ++#define IEEE80211_CIPHER_AES_CCM 3 ++#define IEEE80211_CRYPTO_WEP (1<capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | ++ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; ++ if (devcaps.dc_drivercaps & IEEE80211_C_WPA2) ++ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | ++ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; ++ ++ if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP) ++ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | ++ WPA_DRIVER_CAPA_ENC_WEP104; ++ if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_TKIP) ++ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; ++ if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM) ++ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; ++ ++ if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP) ++ drv->capa.flags |= WPA_DRIVER_FLAGS_AP; ++#undef IEEE80211_CIPHER_WEP ++#undef IEEE80211_CIPHER_TKIP ++#undef IEEE80211_CIPHER_AES_CCM ++#undef IEEE80211_CRYPTO_WEP ++#undef IEEE80211_CRYPTO_TKIP ++#undef IEEE80211_CRYPTO_AES_CCM ++#undef IEEE80211_C_HOSTAP ++#undef IEEE80211_C_WPA1 ++#undef IEEE80211_C_WPA2 ++#else /* IEEE80211_IOC_DEVCAPS */ ++ /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ ++ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | ++ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | ++ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | ++ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; ++ drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | ++ WPA_DRIVER_CAPA_ENC_WEP104 | ++ WPA_DRIVER_CAPA_ENC_TKIP | ++ WPA_DRIVER_CAPA_ENC_CCMP; ++ drv->capa.flags |= WPA_DRIVER_FLAGS_AP; ++#endif /* IEEE80211_IOC_DEVCAPS */ ++#ifdef IEEE80211_IOC_SCAN_MAX_SSID ++ drv->capa.max_scan_ssids = IEEE80211_IOC_SCAN_MAX_SSID; ++#else /* IEEE80211_IOC_SCAN_MAX_SSID */ ++ drv->capa.max_scan_ssids = 1; ++#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ ++ drv->capa.auth = WPA_DRIVER_AUTH_OPEN | ++ WPA_DRIVER_AUTH_SHARED | ++ WPA_DRIVER_AUTH_LEAP; ++ return 0; ++} ++ ++static enum ieee80211_opmode ++get80211opmode(struct bsd_driver_data *drv) ++{ ++ struct ifmediareq ifmr; ++ ++ (void) memset(&ifmr, 0, sizeof(ifmr)); ++ (void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name)); ++ ++ if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { ++ if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) { ++ if (ifmr.ifm_current & IFM_FLAG0) ++ return IEEE80211_M_AHDEMO; ++ else ++ return IEEE80211_M_IBSS; ++ } ++ if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) ++ return IEEE80211_M_HOSTAP; ++ if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) ++ return IEEE80211_M_MONITOR; ++#ifdef IEEE80211_M_MBSS ++ if (ifmr.ifm_current & IFM_IEEE80211_MBSS) ++ return IEEE80211_M_MBSS; ++#endif /* IEEE80211_M_MBSS */ ++ } ++ return IEEE80211_M_STA; ++} ++ ++static void * ++wpa_driver_bsd_init(void *ctx, const char *ifname) ++{ ++#define GETPARAM(drv, param, v) \ ++ (((v) = get80211param(drv, param)) != -1) ++ struct bsd_driver_data *drv; ++ ++ drv = os_zalloc(sizeof(*drv)); ++ if (drv == NULL) ++ return NULL; ++ ++ drv->event_buf_len = rtbuf_len(); ++ ++ drv->event_buf = os_malloc(drv->event_buf_len); ++ if (drv->event_buf == NULL) { ++ wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__); ++ goto fail1; ++ } ++ ++ /* ++ * NB: We require the interface name be mappable to an index. ++ * This implies we do not support having wpa_supplicant ++ * wait for an interface to appear. This seems ok; that ++ * doesn't belong here; it's really the job of devd. ++ */ ++ drv->ifindex = if_nametoindex(ifname); ++ if (drv->ifindex == 0) { ++ wpa_printf(MSG_DEBUG, "%s: interface %s does not exist", ++ __func__, ifname); ++ goto fail1; ++ } ++ drv->sock = socket(PF_INET, SOCK_DGRAM, 0); ++ if (drv->sock < 0) ++ goto fail1; ++ ++ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); ++ /* Down interface during setup. */ ++ if (bsd_ctrl_iface(drv, 0) < 0) ++ goto fail; ++ ++ drv->route = socket(PF_ROUTE, SOCK_RAW, 0); ++ if (drv->route < 0) ++ goto fail; ++ eloop_register_read_sock(drv->route, ++ wpa_driver_bsd_event_receive, ctx, drv); ++ ++ drv->ctx = ctx; ++ ++ if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) { ++ wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s", ++ __func__, strerror(errno)); ++ goto fail; ++ } ++ if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) { ++ wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s", ++ __func__, strerror(errno)); ++ goto fail; ++ } ++ if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) { ++ wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s", ++ __func__, strerror(errno)); ++ goto fail; ++ } ++ ++ if (wpa_driver_bsd_capa(drv)) ++ goto fail; ++ ++ drv->opmode = get80211opmode(drv); ++ ++ return drv; ++fail: ++ close(drv->sock); ++fail1: ++ os_free(drv->event_buf); ++ os_free(drv); ++ return NULL; ++#undef GETPARAM ++} ++ ++static void ++wpa_driver_bsd_deinit(void *priv) ++{ ++ struct bsd_driver_data *drv = priv; ++ ++ wpa_driver_bsd_set_wpa(drv, 0); ++ eloop_unregister_read_sock(drv->route); ++ ++ /* NB: mark interface down */ ++ bsd_ctrl_iface(drv, 0); ++ ++ wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy); ++ if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0) ++ wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state", ++ __func__); ++ ++ if (drv->sock_xmit != NULL) ++ l2_packet_deinit(drv->sock_xmit); ++ (void) close(drv->route); /* ioctl socket */ ++ (void) close(drv->sock); /* event socket */ ++ os_free(drv->event_buf); ++ os_free(drv); ++} ++ ++static int ++wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa) ++{ ++ struct bsd_driver_data *drv = priv; ++ ++ os_memcpy(capa, &drv->capa, sizeof(*capa)); ++ return 0; ++} ++#endif /* HOSTAPD */ ++ ++ ++const struct wpa_driver_ops wpa_driver_bsd_ops = { ++ .name = "bsd", ++ .desc = "BSD 802.11 support", ++#ifdef HOSTAPD ++ .hapd_init = bsd_init, ++ .hapd_deinit = bsd_deinit, ++ .set_privacy = bsd_set_privacy, ++ .get_seqnum = bsd_get_seqnum, ++ .flush = bsd_flush, ++ .read_sta_data = bsd_read_sta_driver_data, ++ .sta_disassoc = bsd_sta_disassoc, ++ .sta_deauth = bsd_sta_deauth, ++ .sta_set_flags = bsd_set_sta_authorized, ++ .commit = bsd_commit, ++#else /* HOSTAPD */ ++ .init = wpa_driver_bsd_init, ++ .deinit = wpa_driver_bsd_deinit, ++ .get_bssid = wpa_driver_bsd_get_bssid, ++ .get_ssid = wpa_driver_bsd_get_ssid, ++ .set_countermeasures = wpa_driver_bsd_set_countermeasures, ++ .scan2 = wpa_driver_bsd_scan, ++ .get_scan_results2 = wpa_driver_bsd_get_scan_results2, ++ .deauthenticate = wpa_driver_bsd_deauthenticate, ++ .associate = wpa_driver_bsd_associate, ++ .get_capa = wpa_driver_bsd_get_capa, ++#endif /* HOSTAPD */ ++ .set_freq = bsd_set_freq, ++ .set_key = bsd_set_key, ++ .set_ieee8021x = bsd_set_ieee8021x, ++ .hapd_set_ssid = bsd_set_ssid, ++ .hapd_get_ssid = bsd_get_ssid, ++ .hapd_send_eapol = bsd_send_eapol, ++ .set_generic_elem = bsd_set_opt_ie, ++}; diff --git a/src/drivers/driver_rtl.h b/src/drivers/driver_rtl.h new file mode 100644 index 0000000..2200e18 @@ -1325,7 +5223,7 @@ index 0000000..2200e18 + u16 aid; + u16 capability; + int flags; -+ u8 tx_supp_rates[16]; ++ u8 tx_supp_rates[16]; + //struct ieee80211_ht_capability ht_cap; + struct ieee80211_ht_capabilities ht_cap; + } add_sta; @@ -1335,9 +5233,9 @@ index 0000000..2200e18 + } bcn_ie; + + } u; -+ ++ +} ieee_param; -+ ++ + + +#define IEEE80211_CCK_RATE_LEN 4 @@ -1468,12 +5366,12 @@ index 0000000..436dd14 + +struct rtl871x_driver_data { + struct hostapd_data *hapd; -+ ++ + char iface[IFNAMSIZ + 1]; + int ifindex; + struct l2_packet_data *l2_sock;/* socket for sending eapol frames*/ + struct l2_packet_data *l2_sock_recv;/* raw packet recv socket from bridge interface*/ -+#ifdef CONFIG_MGNT_L2SOCK ++#ifdef CONFIG_MGNT_L2SOCK + struct l2_packet_data *mgnt_l2_sock; /* socket for tx/rx management frames*/ +#else + int mgnt_sock;/* socket for tx/rx management frames*/ @@ -1482,15 +5380,15 @@ index 0000000..436dd14 + int wext_sock; /* socket for wireless events */ + + struct netlink_data *netlink; -+ ++ + int we_version; + + u8 hw_mac[ETH_ALEN]; -+ ++ + u8 acct_mac[ETH_ALEN]; -+ ++ + struct hostap_sta_driver_data acct_data; -+ ++ +}; + +/* @@ -1502,7 +5400,7 @@ index 0000000..436dd14 + snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); + else + snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); -+ ++ + return buf; +} +*/ @@ -1556,7 +5454,7 @@ index 0000000..436dd14 +#endif + +static int rtl871x_hostapd_ioctl(struct rtl871x_driver_data *drv, ieee_param *param, int len) -+{ ++{ + struct iwreq iwr; + + memset(&iwr, 0, sizeof(iwr)); @@ -1578,14 +5476,14 @@ index 0000000..436dd14 + + if (drv->ioctl_sock < 0) + return -1; -+ ++ + memset(&iwr, 0, sizeof(iwr)); + + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + + //iwr.u.mode = IW_MODE_MASTER; + iwr.u.mode = mode; -+ ++ + if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { + perror("ioctl[SIOCSIWMODE]"); + printf("Could not set interface to mode(%d)!\n", mode); @@ -1593,7 +5491,7 @@ index 0000000..436dd14 + } + + return 0; -+ ++ +} + +/* @@ -1613,9 +5511,9 @@ index 0000000..436dd14 + sta = ap_sta_add(hapd, addr); + if (sta == NULL) + { -+ rtl871x_sta_remove_ops(hapd->drv_priv, addr); ++ rtl871x_sta_remove_ops(hapd->drv_priv, addr); + return -1; -+ } ++ } + } + sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); + @@ -1676,7 +5574,7 @@ index 0000000..436dd14 +*/ + +static int rtl871x_get_sta_wpaie(struct rtl871x_driver_data *drv, u8 *iebuf, u8 *addr) -+{ ++{ + struct ieee_param param; + + printf("+%s, " MACSTR " is sta's address\n", __func__, MAC2STR(addr)); @@ -1684,9 +5582,9 @@ index 0000000..436dd14 + memset(¶m, 0, sizeof(param)); + + param.cmd = RTL871X_HOSTAPD_GET_WPAIE_STA; -+ ++ + memcpy(param.sta_addr, addr, ETH_ALEN); -+ ++ + if (rtl871x_hostapd_ioctl(drv, ¶m, sizeof(param))) { + printf("Could not get sta wpaie from kernel driver.\n"); + return -1; @@ -1697,15 +5595,15 @@ index 0000000..436dd14 + return -1; + + memcpy(iebuf, param.u.wpa_ie.reserved, param.u.wpa_ie.len); -+ -+ return 0; ++ ++ return 0; + +} + +static int rtl871x_del_sta(struct rtl871x_driver_data *drv, u8 *addr) +{ + struct hostapd_data *hapd = drv->hapd; -+ ++ +#if 1 + + //union wpa_event_data event; @@ -1714,7 +5612,7 @@ index 0000000..436dd14 + //wpa_supplicant_event(hapd, EVENT_DISASSOC, &event); + + drv_event_disassoc(hapd, addr); -+ ++ +#else + + struct sta_info *sta; @@ -1723,7 +5621,7 @@ index 0000000..436dd14 + // HOSTAPD_LEVEL_INFO, "disassociated"); + + sta = ap_get_sta(hapd, addr); -+ if (sta != NULL) ++ if (sta != NULL) + { + sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); + wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); @@ -1739,7 +5637,7 @@ index 0000000..436dd14 +#endif + + return 0; -+ ++ +} + +static int rtl871x_new_sta(struct rtl871x_driver_data *drv, u8 *addr) @@ -1758,21 +5656,21 @@ index 0000000..436dd14 + memset(iebuf, 0 , sizeof(iebuf)); + if (rtl871x_get_sta_wpaie(drv, iebuf, addr)) { + //if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { -+ ++ + wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE: %s", + __func__, strerror(errno)); + goto no_ie; + } -+ ++ + //wpa_hexdump(MSG_MSGDUMP, "req WPA IE", + // ie.wpa_ie, IEEE80211_MAX_OPT_IE); -+ ++ + //wpa_hexdump(MSG_MSGDUMP, "req RSN IE", + // ie.rsn_ie, IEEE80211_MAX_OPT_IE); -+ ++ + //iebuf = ie.wpa_ie; -+ -+/* ++ ++/* + if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) + iebuf[1] = 0; + if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) { @@ -1786,15 +5684,15 @@ index 0000000..436dd14 + { + piebuf = iebuf; + ielen = iebuf[1]; -+ ++ + if (ielen == 0) + piebuf = NULL; + else -+ ielen += 2; ++ ielen += 2; + } + +no_ie: -+ ++ + //res = rtl871x_notif_assoc(hapd, addr, piebuf, ielen); + //drv_event_assoc(hapd, addr, piebuf, ielen); + drv_event_assoc(hapd, addr, piebuf, ielen, 0); @@ -1806,7 +5704,7 @@ index 0000000..436dd14 + } + + return res; -+ ++ +} + +static void rtl871x_wireless_event_wireless(struct rtl871x_driver_data *drv, @@ -1861,14 +5759,14 @@ index 0000000..436dd14 + return; /* XXX */ + memcpy(buf, custom, iwe->u.data.length); + buf[iwe->u.data.length] = '\0'; -+ //madwifi_wireless_event_wireless_custom(drv, buf); ++ //madwifi_wireless_event_wireless_custom(drv, buf); + free(buf); + break; + } + + pos += iwe->len; + } -+ ++ +} + +#if 1 @@ -1980,7 +5878,7 @@ index 0000000..436dd14 + if (left > 0) { + printf("%d extra bytes in the end of netlink message\n", left); + } -+ ++ +} +*/ + @@ -2010,7 +5908,7 @@ index 0000000..436dd14 + int s; + struct sockaddr_nl local; + struct rtl871x_driver_data *drv = priv; -+ ++ + //madwifi_get_we_version(drv); + + drv->wext_sock = -1; @@ -2034,7 +5932,7 @@ index 0000000..436dd14 + drv->wext_sock = s; + + return 0; -+ ++ +} + +static void rtl871x_wireless_event_deinit_ops(void *priv) @@ -2103,7 +6001,7 @@ index 0000000..436dd14 + return -1; + } + } -+ ++ + eth = (struct l2_ethhdr *) bp; + memcpy(eth->h_dest, addr, ETH_ALEN); + memcpy(eth->h_source, own_addr, ETH_ALEN); @@ -2116,9 +6014,9 @@ index 0000000..436dd14 + + if (bp != buf) + free(bp); -+ ++ + return status; -+ ++ +} + +#ifndef CONFIG_MLME_OFFLOAD @@ -2132,14 +6030,14 @@ index 0000000..436dd14 + + //printf("+rtl871x_receive_mgnt, " MACSTR " is our address\n", MAC2STR(hapd->own_addr)); + -+ ++ +#if 0 + { + int i; + for(i=0; ihapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + + return sock; -+ ++ +} +#endif +#endif @@ -2336,8 +6234,8 @@ index 0000000..436dd14 + printf("unknown TX callback frame type %d\n", type); + break; + } -+#endif -+} ++#endif ++} + +static int rtl871x_send_mgnt(struct rtl871x_driver_data *drv, const void *msg, size_t len) +{ @@ -2355,14 +6253,14 @@ index 0000000..436dd14 + + //printf("%s\n", __func__); + -+ ++ + //hdr->frame_control |= host_to_le16(BIT(1));/* Request TX callback */ +#ifdef CONFIG_MGNT_L2SOCK + //res = send(drv->mgnt_l2_sock, msg, len, flags); + //res = l2_packet_send(drv->mgnt_l2_sock, addr, ETH_P_EAPOL, msg, len); + if(drv->mgnt_l2_sock == NULL) + return res; -+ ++ + res = l2_packet_send(drv->mgnt_l2_sock, NULL, ETH_P_80211_RAW, msg, len); +#else + @@ -2372,14 +6270,14 @@ index 0000000..436dd14 + res = send(drv->mgnt_sock, msg, len, flags); +#endif + //hdr->frame_control &= ~host_to_le16(BIT(1)); -+ ++ + + rtl871x_send_mgnt(drv, msg, len); + + rtl871x_handle_tx_callback(drv->hapd, (u8*)msg, len, 1); + + return res; -+ ++ +} + +/* @@ -2404,7 +6302,7 @@ index 0000000..436dd14 + + *num_modes = 3; + *flags = 0; -+ ++ + modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes)); + if (modes == NULL) + return NULL; @@ -2467,8 +6365,8 @@ index 0000000..436dd14 + modes[2].num_channels = MAX_NUM_CHANNEL_5G; +#else /* CONFIG_DRIVER_RTL_DFS */ + modes[2].num_channels = 9; -+#endif /* CONFIG_DRIVER_RTL_DFS */ -+ ++#endif /* CONFIG_DRIVER_RTL_DFS */ ++ + modes[2].num_rates = 8; + modes[2].channels = os_zalloc(modes[2].num_channels * sizeof(struct hostapd_channel_data)); + modes[2].rates = os_zalloc(modes[2].num_rates * sizeof(int)); @@ -2510,7 +6408,7 @@ index 0000000..436dd14 + modes[2].channels[k].flag = 0; + k++; + } -+ ++ + modes[2].rates[0] = 60; + modes[2].rates[1] = 90; + modes[2].rates[2] = 120; @@ -2520,9 +6418,9 @@ index 0000000..436dd14 + modes[2].rates[6] = 480; + modes[2].rates[7] = 540; + -+ ++ + // -+#if 0 ++#if 0 +#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0)) +#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1)) +#define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3))) @@ -2548,19 +6446,19 @@ index 0000000..436dd14 + //HOSTAPD_MODE_IEEE80211G + modes[0].ht_capab = HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET|HT_CAP_INFO_SHORT_GI20MHZ| + HT_CAP_INFO_SHORT_GI40MHZ|HT_CAP_INFO_MAX_AMSDU_SIZE|HT_CAP_INFO_DSSS_CCK40MHZ; -+ ++ + modes[0].mcs_set[0]= 0xff; + modes[0].mcs_set[1]= 0xff; -+ ++ + //HOSTAPD_MODE_IEEE80211B + modes[1].ht_capab = 0; -+ ++ + //HOSTAPD_MODE_IEEE80211A + modes[2].ht_capab = modes[0].ht_capab; -+ ++ + modes[2].mcs_set[0]= 0xff; + modes[2].mcs_set[1]= 0xff; -+ ++ + return modes; + +fail: @@ -2571,9 +6469,9 @@ index 0000000..436dd14 + } + os_free(modes); + } -+ -+ return NULL; -+ ++ ++ return NULL; ++ +} + +#if 0 @@ -2586,7 +6484,7 @@ index 0000000..436dd14 +#if 1 + printf("+%s, " MACSTR " is new sta address added\n", __func__, MAC2STR(addr)); + return 0; -+#else ++#else + struct hostap_driver_data *drv = priv; + struct prism2_hostapd_param param; + int tx_supp_rates = 0; @@ -2615,7 +6513,7 @@ index 0000000..436dd14 + param.u.add_sta.capability = capability; + param.u.add_sta.tx_supp_rates = tx_supp_rates; + return hostapd_ioctl(drv, ¶m, sizeof(param)); -+#endif ++#endif +} + +static int rtl871x_sta_add2_ops(const char *ifname, void *priv, @@ -2625,7 +6523,7 @@ index 0000000..436dd14 + ieee_param param; + //int i, tx_supp_rates = 0; + struct rtl871x_driver_data *drv = priv; -+ ++ + printf("%s\n", __func__); + + memset(¶m, 0, sizeof(param)); @@ -2637,9 +6535,9 @@ index 0000000..436dd14 + + memcpy(param.u.add_sta.tx_supp_rates, params->supp_rates, params->supp_rates_len); + -+/* ++/* + for (i = 0; i < params->supp_rates_len; i++) -+ { ++ { + if ((params->supp_rates[i] & 0x7f) == IEEE80211_CCK_RATE_1MB) + tx_supp_rates |= IEEE80211_CCK_RATE_1MB_MASK; + if ((params->supp_rates[i] & 0x7f) == IEEE80211_CCK_RATE_2MB) @@ -2666,21 +6564,21 @@ index 0000000..436dd14 + tx_supp_rates |= IEEE80211_OFDM_RATE_48MB_MASK; + if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_54MB) + tx_supp_rates |= IEEE80211_OFDM_RATE_54MB_MASK; -+ ++ + } + + param.u.add_sta.tx_supp_rates = tx_supp_rates; -+*/ -+ ++*/ ++ +#ifdef CONFIG_IEEE80211N -+ if (params->ht_capabilities && params->ht_capabilities->length>0) ++ if (params->ht_capabilities && params->ht_capabilities->length>0) + { + struct ieee80211_ht_capability *pht_cap = (struct ieee80211_ht_capability *)¶ms->ht_capabilities->data; + memcpy((u8*)¶m.u.add_sta.ht_cap, (u8*)pht_cap, sizeof(struct ieee80211_ht_capability)); -+ ++ + } +#endif /* CONFIG_IEEE80211N */ -+ ++ + return rtl871x_hostapd_ioctl(drv, ¶m, sizeof(param)); +#else + return 0; @@ -2704,8 +6602,8 @@ index 0000000..436dd14 + printf("Could not remove station from kernel driver.\n"); + return -1; + } -+ -+ return 0; ++ ++ return 0; + +} + @@ -2714,7 +6612,7 @@ index 0000000..436dd14 +static int rtl871x_set_hidden_ssid_ops(const char *iface, void *priv, u8 value) +{ + int ret; -+ ieee_param pparam; ++ ieee_param pparam; + struct rtl871x_driver_data *drv = priv; + struct hostapd_data *hapd = drv->hapd; + @@ -2726,7 +6624,7 @@ index 0000000..436dd14 + + ret = rtl871x_hostapd_ioctl(drv, &pparam, sizeof(ieee_param)); + -+ return ret; ++ return ret; +} + +static const u8 * get_ie(u8 *ies, size_t ies_len, u8 id) @@ -2741,7 +6639,7 @@ index 0000000..436dd14 + break; + + //printf("id:%u, clen:%u\n", pos[0], pos[1]); -+ ++ + if (pos[0] == id) + return pos; + pos += 2 + pos[1]; @@ -2762,7 +6660,7 @@ index 0000000..436dd14 + u8 *ssid_ie; + u8 ssid_len; + u8 expend_len = 0; -+ ++ + if((params->head_len<24) ||(!params->head)) + return -1; + @@ -2773,13 +6671,13 @@ index 0000000..436dd14 + rtl871x_set_hidden_ssid_ops(drv->iface, priv, hapd->conf->ignore_broadcast_ssid); + + ssid_ie = get_ie((params->head+24+12), (params->head_len-24-12), WLAN_EID_SSID); -+ ++ + if(hapd->conf->ignore_broadcast_ssid == 2) + { + ssid_len = ssid_ie[1]; -+ ++ + //confirm the ssid_len -+ if(ssid_len != hapd->conf->ssid.ssid_len) ++ if(ssid_len != hapd->conf->ssid.ssid_len) + { + printf("%s ssid_len(%u) != hapd->conf->ssid.ssid_len(%u)!!\n", __func__ + , ssid_len, hapd->conf->ssid.ssid_len @@ -2796,7 +6694,7 @@ index 0000000..436dd14 + , hapd->conf->ssid.ssid + , hapd->conf->ssid.ssid_len + , expend_len -+ ); ++ ); + } +#endif //RTL871X_HIDDEN_SSID_SUPPORT + @@ -2816,13 +6714,13 @@ index 0000000..436dd14 + u8 *ssid_ie_next = params->head+24+12+2; + size_t head_remain_len = params->head_len-24-12-2; + -+ memcpy(pparam->u.bcn_ie.buf, (params->head+24), 12); -+ ++ memcpy(pparam->u.bcn_ie.buf, (params->head+24), 12); ++ + pparam->u.bcn_ie.buf[12] = WLAN_EID_SSID; + pparam->u.bcn_ie.buf[13] = expend_len; + memcpy(pparam->u.bcn_ie.buf+12+2, hapd->conf->ssid.ssid, expend_len); -+ -+ memcpy(pparam->u.bcn_ie.buf+12+2+expend_len, ssid_ie_next, head_remain_len);// 24=beacon header len. ++ ++ memcpy(pparam->u.bcn_ie.buf+12+2+expend_len, ssid_ie_next, head_remain_len);// 24=beacon header len. + memcpy(&pparam->u.bcn_ie.buf[params->head_len-24+expend_len], params->tail, params->tail_len); + } + else @@ -2831,15 +6729,15 @@ index 0000000..436dd14 + memcpy(pparam->u.bcn_ie.buf, (params->head+24), (params->head_len-24));// 24=beacon header len. + memcpy(&pparam->u.bcn_ie.buf[params->head_len-24], params->tail, params->tail_len); + } -+ ++ + ret = rtl871x_hostapd_ioctl(drv, pparam, sz); + + os_free(pparam); + + //rtl871x_set_max_num_sta(drv); -+ ++ + return ret; -+ ++ +} + +/* @@ -2856,7 +6754,7 @@ index 0000000..436dd14 + const u8 *addr, int idx, int txkey, const u8 *seq, + size_t seq_len, const u8 *key, size_t key_len) +{ -+ ieee_param *param; ++ ieee_param *param; + u8 *buf; + char *alg_str; + size_t blen; @@ -2898,16 +6796,16 @@ index 0000000..436dd14 + printf("%s: unknown/unsupported algorithm %d\n", + __func__, alg); + return -1; -+ } -+ ++ } ++ + os_strlcpy((char *) param->u.crypt.alg, alg_str, + IEEE_CRYPT_ALG_NAME_LEN); -+ ++ + //param->u.crypt.flags = txkey ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; + param->u.crypt.set_tx = txkey ? 1 : 0; + param->u.crypt.idx = idx; + param->u.crypt.key_len = key_len; -+ ++ + //memcpy((u8 *) (param + 1), key, key_len); + memcpy(param->u.crypt.key, key, key_len); + @@ -2915,7 +6813,7 @@ index 0000000..436dd14 + printf("Failed to set encryption.\n"); + ret = -1; + } -+ ++ + os_free(buf); + + return ret; @@ -2928,7 +6826,7 @@ index 0000000..436dd14 + int idx, const u8 *key, size_t key_len, + int txkey) +{ -+ ieee_param *param; ++ ieee_param *param; + u8 *buf; + size_t blen; + int ret = 0; @@ -2947,15 +6845,15 @@ index 0000000..436dd14 + memset(param->sta_addr, 0xff, ETH_ALEN); + else + memcpy(param->sta_addr, addr, ETH_ALEN); -+ ++ + os_strlcpy((char *) param->u.crypt.alg, alg, + IEEE_CRYPT_ALG_NAME_LEN); -+ ++ + //param->u.crypt.flags = txkey ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; + param->u.crypt.set_tx = txkey ? 1 : 0; + param->u.crypt.idx = idx; + param->u.crypt.key_len = key_len; -+ ++ + //memcpy((u8 *) (param + 1), key, key_len); + memcpy(param->u.crypt.key, key, key_len); + @@ -2963,11 +6861,11 @@ index 0000000..436dd14 + printf("Failed to set encryption.\n"); + ret = -1; + } -+ ++ + os_free(buf); +#endif + return ret; -+ ++ +} +*/ + @@ -2984,7 +6882,7 @@ index 0000000..436dd14 + memset(&mgmt, 0, sizeof(mgmt)); + mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_DEAUTH); -+ ++ + memcpy(mgmt.da, addr, ETH_ALEN); + //memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); + //memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); @@ -2994,7 +6892,7 @@ index 0000000..436dd14 + + return rtl871x_send_mgmt_frame_ops(drv, &mgmt, IEEE80211_HDRLEN + + sizeof(mgmt.u.deauth), 0); -+ ++ +} + + @@ -3010,15 +6908,15 @@ index 0000000..436dd14 + memset(&mgmt, 0, sizeof(mgmt)); + mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_DISASSOC); -+ ++ + memcpy(mgmt.da, addr, ETH_ALEN); + //memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); + //memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); + memcpy(mgmt.sa, own_addr, ETH_ALEN); + memcpy(mgmt.bssid, own_addr, ETH_ALEN); -+ ++ + mgmt.u.disassoc.reason_code = host_to_le16(reason); -+ ++ + return rtl871x_send_mgmt_frame_ops(drv, &mgmt, IEEE80211_HDRLEN + + sizeof(mgmt.u.disassoc), 0); + @@ -3030,7 +6928,7 @@ index 0000000..436dd14 + size_t sz; + ieee_param *pparam; + -+ ++ + printf("%s\n", __func__); + + sz = len + 12 + 2;// 12+2 = cmd+sta_addr+reserved, sizeof(ieee_param)=64, no packed @@ -3039,8 +6937,8 @@ index 0000000..436dd14 + return -ENOMEM; + } + -+ pparam->cmd = RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP; -+ ++ pparam->cmd = RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP; ++ + if(ie && len>0) + { + memcpy(pparam->u.bcn_ie.buf, ie, len); @@ -3051,7 +6949,7 @@ index 0000000..436dd14 + os_free(pparam); + + return ret; -+ ++ +} + +static int rtl871x_set_wps_beacon_ie(struct rtl871x_driver_data *drv, const void *ie, size_t len) @@ -3060,7 +6958,7 @@ index 0000000..436dd14 + size_t sz; + ieee_param *pparam; + -+ ++ + printf("%s\n", __func__); + + sz = len + 12 + 2;// 12+2 = cmd+sta_addr+reserved, sizeof(ieee_param)=64, no packed @@ -3069,8 +6967,8 @@ index 0000000..436dd14 + return -ENOMEM; + } + -+ pparam->cmd = RTL871X_HOSTAPD_SET_WPS_BEACON; -+ ++ pparam->cmd = RTL871X_HOSTAPD_SET_WPS_BEACON; ++ + if(ie && len>0) + { + memcpy(pparam->u.bcn_ie.buf, ie, len); @@ -3081,7 +6979,7 @@ index 0000000..436dd14 + os_free(pparam); + + return ret; -+ ++ +} + +static int rtl871x_set_wps_probe_resp_ie(struct rtl871x_driver_data *drv, const void *ie, size_t len) @@ -3089,8 +6987,8 @@ index 0000000..436dd14 + int ret; + size_t sz; + ieee_param *pparam; -+ -+ ++ ++ + printf("%s\n", __func__); + + sz = len + 12 + 2;// 12+2 = cmd+sta_addr+reserved, sizeof(ieee_param)=64, no packed @@ -3099,8 +6997,8 @@ index 0000000..436dd14 + return -ENOMEM; + } + -+ pparam->cmd = RTL871X_HOSTAPD_SET_WPS_PROBE_RESP; -+ ++ pparam->cmd = RTL871X_HOSTAPD_SET_WPS_PROBE_RESP; ++ + if(ie && len>0) + { + memcpy(pparam->u.bcn_ie.buf, ie, len); @@ -3111,13 +7009,13 @@ index 0000000..436dd14 + os_free(pparam); + + return ret; -+ ++ +} + +static int rtl871x_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, + const struct wpabuf *proberesp, const struct wpabuf *assocresp) +{ -+ struct rtl871x_driver_data *drv = priv; ++ struct rtl871x_driver_data *drv = priv; + + if (rtl871x_set_wps_assoc_resp_ie(drv, assocresp ? wpabuf_head(assocresp) : NULL, + assocresp ? wpabuf_len(assocresp) : 0)) @@ -3129,19 +7027,19 @@ index 0000000..436dd14 + + return rtl871x_set_wps_probe_resp_ie(drv, + proberesp ? wpabuf_head(proberesp) : NULL, -+ proberesp ? wpabuf_len(proberesp): 0); ++ proberesp ? wpabuf_len(proberesp): 0); + +} + +static int rtl871x_sta_flush_ops(void *priv) +{ + ieee_param param; -+ struct rtl871x_driver_data *drv = priv; ++ struct rtl871x_driver_data *drv = priv; + + memset(¶m, 0, sizeof(param)); -+ -+ param.cmd = RTL871X_HOSTAPD_FLUSH; -+ ++ ++ param.cmd = RTL871X_HOSTAPD_FLUSH; ++ + return rtl871x_hostapd_ioctl(drv, ¶m, sizeof(param)); +} + @@ -3196,11 +7094,11 @@ index 0000000..436dd14 + 1); + if (drv->l2_sock_recv == NULL) + { -+ //goto bad; ++ //goto bad; + drv->l2_sock_recv = drv->l2_sock; -+ printf("no br0 interface , let l2_sock_recv==l2_sock_xmit=0x%p\n", drv->l2_sock); ++ printf("no br0 interface , let l2_sock_recv==l2_sock_xmit=0x%p\n", drv->l2_sock); + } -+ ++ + } else if (linux_br_get(brname, drv->iface) == 0) { + wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for " + "EAPOL receive", brname); @@ -3212,27 +7110,27 @@ index 0000000..436dd14 + else + { + drv->l2_sock_recv = drv->l2_sock; -+ printf("l2_sock_recv==l2_sock_xmit=0x%p\n", drv->l2_sock); ++ printf("l2_sock_recv==l2_sock_xmit=0x%p\n", drv->l2_sock); + } + + + os_memset(ifrn_name, 0, sizeof(ifrn_name)); + //snprintf(ifrn_name, sizeof(ifrn_name), "mgnt.%s_rena", drv->iface); + snprintf(ifrn_name, sizeof(ifrn_name), "mgnt.%s", "wlan0"/*drv->iface*/); -+#ifdef CONFIG_MGNT_L2SOCK ++#ifdef CONFIG_MGNT_L2SOCK + drv->mgnt_l2_sock = NULL; + drv->mgnt_l2_sock = l2_packet_init(ifrn_name, NULL, ETH_P_80211_RAW, + rtl871x_recvive_mgmt_frame, drv, 1); + if (drv->mgnt_l2_sock == NULL) + goto bad; -+ ++ +#else + +#ifdef CONFIG_MLME_OFFLOAD + drv->mgnt_sock = -1; +#else + drv->mgnt_sock = rtl871x_mgnt_sock_init(drv, ifrn_name); -+ if (drv->mgnt_sock < 0) { ++ if (drv->mgnt_sock < 0) { + goto bad; + } +#endif @@ -3246,7 +7144,7 @@ index 0000000..436dd14 + + //linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);/*set interface up*/ + -+ ++ + //enter MASTER MODE when init. + if(rtl871x_set_mode(drv, IW_MODE_MASTER)<0) + { @@ -3263,13 +7161,13 @@ index 0000000..436dd14 + printf("Could not set interface to master mode!\n"); + goto bad; + } -+*/ ++*/ + +#ifndef CONFIG_MLME_OFFLOAD + rtl871x_set_iface_flags(drv, 1); /*set mgnt interface up*/ +#endif + -+ ++ + if (rtl871x_wireless_event_init(drv)) + goto bad; + @@ -3277,15 +7175,15 @@ index 0000000..436dd14 + os_memcpy(drv->hw_mac, params->own_addr, ETH_ALEN); + + return drv; -+ ++ +bad: + + if (drv->l2_sock_recv != NULL && drv->l2_sock_recv != drv->l2_sock) + l2_packet_deinit(drv->l2_sock_recv); -+ ++ + if (drv->l2_sock != NULL) + l2_packet_deinit(drv->l2_sock); -+ ++ + if (drv->ioctl_sock >= 0) + close(drv->ioctl_sock); + @@ -3296,12 +7194,12 @@ index 0000000..436dd14 + if (drv->mgnt_sock >= 0) + close(drv->mgnt_sock); +#endif -+ ++ + if (drv != NULL) + free(drv); -+ ++ + return NULL; -+ ++ +} + +static void rtl871x_driver_deinit_ops(void *priv) @@ -3310,31 +7208,31 @@ index 0000000..436dd14 + struct rtl871x_driver_data *drv = priv; + + //back to INFRA MODE when exit. -+/* ++/* + memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); + iwr.u.mode = IW_MODE_INFRA; + if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { + perror("ioctl[SIOCSIWMODE]"); + } -+*/ ++*/ + rtl871x_set_mode(drv, IW_MODE_INFRA); -+ ++ + + if (drv->ioctl_sock >= 0) + close(drv->ioctl_sock); + -+ ++ + if (drv->l2_sock_recv != NULL && drv->l2_sock_recv != drv->l2_sock) + l2_packet_deinit(drv->l2_sock_recv); + + if(drv->l2_sock) -+ l2_packet_deinit(drv->l2_sock); -+ ++ l2_packet_deinit(drv->l2_sock); ++ + //if (drv->sock_xmit != NULL) + // l2_packet_deinit(drv->sock_xmit); + -+#ifdef CONFIG_MGNT_L2SOCK ++#ifdef CONFIG_MGNT_L2SOCK + if (drv->mgnt_l2_sock) + l2_packet_deinit(drv->mgnt_l2_sock); +#else @@ -3343,7 +7241,7 @@ index 0000000..436dd14 +#endif + + os_free(drv); -+ ++ +} + + @@ -3381,13 +7279,13 @@ index 01defdf..1de29c8 100644 @@ -1081,6 +1081,38 @@ void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx) wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); } - + +//added for wps2.0 @20110519 +static int wpa_driver_wext_set_probe_req_ie(struct wpa_driver_wext_data *drv, const u8 *extra_ies, + size_t extra_ies_len) +{ + unsigned char *pbuf; -+ struct iwreq iwr; ++ struct iwreq iwr; + int ret = 0; + + pbuf = os_malloc(extra_ies_len); @@ -3414,24 +7312,24 @@ index 01defdf..1de29c8 100644 + +} + - + /** * wpa_driver_wext_scan - Request the driver to initiate scan @@ -1103,6 +1135,10 @@ int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params) return -1; } - + + //added for wps2.0 @20110519 + wpa_driver_wext_set_probe_req_ie(drv, params->extra_ies, + params->extra_ies_len); + os_memset(&iwr, 0, sizeof(iwr)); os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - + @@ -2403,6 +2439,28 @@ int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv, return 0; } - + +// Aries 20120120, append rssi information at the end of "status" command +int wext_signal_poll(void *priv, struct wpa_signal_info *signal_info) +{ @@ -3454,9 +7352,2526 @@ index 01defdf..1de29c8 100644 + signal_info->current_noise = stat.qual.noise; + return ret; +} - + int wpa_driver_wext_set_operstate(void *priv, int state) { +diff --git a/src/drivers/driver_wext.c.orig b/src/drivers/driver_wext.c.orig +new file mode 100644 +index 0000000..01defdf +--- /dev/null ++++ b/src/drivers/driver_wext.c.orig +@@ -0,0 +1,2511 @@ ++/* ++ * Driver interaction with generic Linux Wireless Extensions ++ * Copyright (c) 2003-2015, Jouni Malinen ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ * ++ * This file implements a driver interface for the Linux Wireless Extensions. ++ * When used with WE-18 or newer, this interface can be used as-is with number ++ * of drivers. In addition to this, some of the common functions in this file ++ * can be used by other driver interface implementations that use generic WE ++ * ioctls, but require private ioctls for some of the functionality. ++ */ ++ ++#include "includes.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "linux_wext.h" ++#include "common.h" ++#include "eloop.h" ++#include "common/ieee802_11_defs.h" ++#include "common/wpa_common.h" ++#include "priv_netlink.h" ++#include "netlink.h" ++#include "linux_ioctl.h" ++#include "rfkill.h" ++#include "driver.h" ++#include "driver_wext.h" ++ ++static int wpa_driver_wext_flush_pmkid(void *priv); ++static int wpa_driver_wext_get_range(void *priv); ++static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv); ++static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv); ++static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg); ++ ++ ++int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv, ++ int idx, u32 value) ++{ ++ struct iwreq iwr; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.param.flags = idx & IW_AUTH_INDEX; ++ iwr.u.param.value = value; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) { ++ if (errno != EOPNOTSUPP) { ++ wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d " ++ "value 0x%x) failed: %s)", ++ idx, value, strerror(errno)); ++ } ++ ret = errno == EOPNOTSUPP ? -2 : -1; ++ } ++ ++ return ret; ++} ++ ++ ++/** ++ * wpa_driver_wext_get_bssid - Get BSSID, SIOCGIWAP ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @bssid: Buffer for BSSID ++ * Returns: 0 on success, -1 on failure ++ */ ++int wpa_driver_wext_get_bssid(void *priv, u8 *bssid) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWAP]: %s", strerror(errno)); ++ ret = -1; ++ } ++ os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN); ++ ++ return ret; ++} ++ ++ ++/** ++ * wpa_driver_wext_set_bssid - Set BSSID, SIOCSIWAP ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @bssid: BSSID ++ * Returns: 0 on success, -1 on failure ++ */ ++int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.ap_addr.sa_family = ARPHRD_ETHER; ++ if (bssid) ++ os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN); ++ else ++ os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN); ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWAP]: %s", strerror(errno)); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++/** ++ * wpa_driver_wext_get_ssid - Get SSID, SIOCGIWESSID ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @ssid: Buffer for the SSID; must be at least 32 bytes long ++ * Returns: SSID length on success, -1 on failure ++ */ ++int wpa_driver_wext_get_ssid(void *priv, u8 *ssid) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.essid.pointer = (caddr_t) ssid; ++ iwr.u.essid.length = SSID_MAX_LEN; ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s", ++ strerror(errno)); ++ ret = -1; ++ } else { ++ ret = iwr.u.essid.length; ++ if (ret > SSID_MAX_LEN) ++ ret = SSID_MAX_LEN; ++ /* Some drivers include nul termination in the SSID, so let's ++ * remove it here before further processing. WE-21 changes this ++ * to explicitly require the length _not_ to include nul ++ * termination. */ ++ if (ret > 0 && ssid[ret - 1] == '\0' && ++ drv->we_version_compiled < 21) ++ ret--; ++ } ++ ++ return ret; ++} ++ ++ ++/** ++ * wpa_driver_wext_set_ssid - Set SSID, SIOCSIWESSID ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @ssid: SSID ++ * @ssid_len: Length of SSID (0..32) ++ * Returns: 0 on success, -1 on failure ++ */ ++int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ char buf[33]; ++ ++ if (ssid_len > SSID_MAX_LEN) ++ return -1; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ /* flags: 1 = ESSID is active, 0 = not (promiscuous) */ ++ iwr.u.essid.flags = (ssid_len != 0); ++ os_memset(buf, 0, sizeof(buf)); ++ os_memcpy(buf, ssid, ssid_len); ++ iwr.u.essid.pointer = (caddr_t) buf; ++ if (drv->we_version_compiled < 21) { ++ /* For historic reasons, set SSID length to include one extra ++ * character, C string nul termination, even though SSID is ++ * really an octet string that should not be presented as a C ++ * string. Some Linux drivers decrement the length by one and ++ * can thus end up missing the last octet of the SSID if the ++ * length is not incremented here. WE-21 changes this to ++ * explicitly require the length _not_ to include nul ++ * termination. */ ++ if (ssid_len) ++ ssid_len++; ++ } ++ iwr.u.essid.length = ssid_len; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++/** ++ * wpa_driver_wext_set_freq - Set frequency/channel, SIOCSIWFREQ ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @freq: Frequency in MHz ++ * Returns: 0 on success, -1 on failure ++ */ ++int wpa_driver_wext_set_freq(void *priv, int freq) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.freq.m = freq * 100000; ++ iwr.u.freq.e = 1; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWFREQ]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++static void ++wpa_driver_wext_event_wireless_custom(void *ctx, char *custom) ++{ ++ union wpa_event_data data; ++ ++ wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'", ++ custom); ++ ++ os_memset(&data, 0, sizeof(data)); ++ /* Host AP driver */ ++ if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { ++ data.michael_mic_failure.unicast = ++ os_strstr(custom, " unicast ") != NULL; ++ /* TODO: parse parameters(?) */ ++ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); ++ } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) { ++ char *spos; ++ int bytes; ++ u8 *req_ies = NULL, *resp_ies = NULL; ++ ++ spos = custom + 17; ++ ++ bytes = strspn(spos, "0123456789abcdefABCDEF"); ++ if (!bytes || (bytes & 1)) ++ return; ++ bytes /= 2; ++ ++ req_ies = os_malloc(bytes); ++ if (req_ies == NULL || ++ hexstr2bin(spos, req_ies, bytes) < 0) ++ goto done; ++ data.assoc_info.req_ies = req_ies; ++ data.assoc_info.req_ies_len = bytes; ++ ++ spos += bytes * 2; ++ ++ data.assoc_info.resp_ies = NULL; ++ data.assoc_info.resp_ies_len = 0; ++ ++ if (os_strncmp(spos, " RespIEs=", 9) == 0) { ++ spos += 9; ++ ++ bytes = strspn(spos, "0123456789abcdefABCDEF"); ++ if (!bytes || (bytes & 1)) ++ goto done; ++ bytes /= 2; ++ ++ resp_ies = os_malloc(bytes); ++ if (resp_ies == NULL || ++ hexstr2bin(spos, resp_ies, bytes) < 0) ++ goto done; ++ data.assoc_info.resp_ies = resp_ies; ++ data.assoc_info.resp_ies_len = bytes; ++ } ++ ++ wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data); ++ ++ done: ++ os_free(resp_ies); ++ os_free(req_ies); ++#ifdef CONFIG_PEERKEY ++ } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) { ++ if (hwaddr_aton(custom + 17, data.stkstart.peer)) { ++ wpa_printf(MSG_DEBUG, "WEXT: unrecognized " ++ "STKSTART.request '%s'", custom + 17); ++ return; ++ } ++ wpa_supplicant_event(ctx, EVENT_STKSTART, &data); ++#endif /* CONFIG_PEERKEY */ ++ } ++} ++ ++ ++static int wpa_driver_wext_event_wireless_michaelmicfailure( ++ void *ctx, const char *ev, size_t len) ++{ ++ const struct iw_michaelmicfailure *mic; ++ union wpa_event_data data; ++ ++ if (len < sizeof(*mic)) ++ return -1; ++ ++ mic = (const struct iw_michaelmicfailure *) ev; ++ ++ wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: " ++ "flags=0x%x src_addr=" MACSTR, mic->flags, ++ MAC2STR(mic->src_addr.sa_data)); ++ ++ os_memset(&data, 0, sizeof(data)); ++ data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP); ++ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); ++ ++ return 0; ++} ++ ++ ++static int wpa_driver_wext_event_wireless_pmkidcand( ++ struct wpa_driver_wext_data *drv, const char *ev, size_t len) ++{ ++ const struct iw_pmkid_cand *cand; ++ union wpa_event_data data; ++ const u8 *addr; ++ ++ if (len < sizeof(*cand)) ++ return -1; ++ ++ cand = (const struct iw_pmkid_cand *) ev; ++ addr = (const u8 *) cand->bssid.sa_data; ++ ++ wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: " ++ "flags=0x%x index=%d bssid=" MACSTR, cand->flags, ++ cand->index, MAC2STR(addr)); ++ ++ os_memset(&data, 0, sizeof(data)); ++ os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN); ++ data.pmkid_candidate.index = cand->index; ++ data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH; ++ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); ++ ++ return 0; ++} ++ ++ ++static int wpa_driver_wext_event_wireless_assocreqie( ++ struct wpa_driver_wext_data *drv, const char *ev, int len) ++{ ++ if (len < 0) ++ return -1; ++ ++ wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev, ++ len); ++ os_free(drv->assoc_req_ies); ++ drv->assoc_req_ies = os_malloc(len); ++ if (drv->assoc_req_ies == NULL) { ++ drv->assoc_req_ies_len = 0; ++ return -1; ++ } ++ os_memcpy(drv->assoc_req_ies, ev, len); ++ drv->assoc_req_ies_len = len; ++ ++ return 0; ++} ++ ++ ++static int wpa_driver_wext_event_wireless_assocrespie( ++ struct wpa_driver_wext_data *drv, const char *ev, int len) ++{ ++ if (len < 0) ++ return -1; ++ ++ wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev, ++ len); ++ os_free(drv->assoc_resp_ies); ++ drv->assoc_resp_ies = os_malloc(len); ++ if (drv->assoc_resp_ies == NULL) { ++ drv->assoc_resp_ies_len = 0; ++ return -1; ++ } ++ os_memcpy(drv->assoc_resp_ies, ev, len); ++ drv->assoc_resp_ies_len = len; ++ ++ return 0; ++} ++ ++ ++static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv) ++{ ++ union wpa_event_data data; ++ ++ if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL) ++ return; ++ ++ os_memset(&data, 0, sizeof(data)); ++ if (drv->assoc_req_ies) { ++ data.assoc_info.req_ies = drv->assoc_req_ies; ++ data.assoc_info.req_ies_len = drv->assoc_req_ies_len; ++ } ++ if (drv->assoc_resp_ies) { ++ data.assoc_info.resp_ies = drv->assoc_resp_ies; ++ data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len; ++ } ++ ++ wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data); ++ ++ os_free(drv->assoc_req_ies); ++ drv->assoc_req_ies = NULL; ++ os_free(drv->assoc_resp_ies); ++ drv->assoc_resp_ies = NULL; ++} ++ ++ ++static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, ++ char *data, int len) ++{ ++ struct iw_event iwe_buf, *iwe = &iwe_buf; ++ char *pos, *end, *custom, *buf; ++ ++ pos = data; ++ end = data + len; ++ ++ while (pos + IW_EV_LCP_LEN <= end) { ++ /* Event data may be unaligned, so make a local, aligned copy ++ * before processing. */ ++ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); ++ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", ++ iwe->cmd, iwe->len); ++ if (iwe->len <= IW_EV_LCP_LEN) ++ return; ++ ++ custom = pos + IW_EV_POINT_LEN; ++ if (drv->we_version_compiled > 18 && ++ (iwe->cmd == IWEVMICHAELMICFAILURE || ++ iwe->cmd == IWEVCUSTOM || ++ iwe->cmd == IWEVASSOCREQIE || ++ iwe->cmd == IWEVASSOCRESPIE || ++ iwe->cmd == IWEVPMKIDCAND)) { ++ /* WE-19 removed the pointer from struct iw_point */ ++ char *dpos = (char *) &iwe_buf.u.data.length; ++ int dlen = dpos - (char *) &iwe_buf; ++ os_memcpy(dpos, pos + IW_EV_LCP_LEN, ++ sizeof(struct iw_event) - dlen); ++ } else { ++ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); ++ custom += IW_EV_POINT_OFF; ++ } ++ ++ switch (iwe->cmd) { ++ case SIOCGIWAP: ++ wpa_printf(MSG_DEBUG, "Wireless event: new AP: " ++ MACSTR, ++ MAC2STR((u8 *) iwe->u.ap_addr.sa_data)); ++ if (is_zero_ether_addr( ++ (const u8 *) iwe->u.ap_addr.sa_data) || ++ os_memcmp(iwe->u.ap_addr.sa_data, ++ "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == ++ 0) { ++ os_free(drv->assoc_req_ies); ++ drv->assoc_req_ies = NULL; ++ os_free(drv->assoc_resp_ies); ++ drv->assoc_resp_ies = NULL; ++ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, ++ NULL); ++ ++ } else { ++ wpa_driver_wext_event_assoc_ies(drv); ++ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, ++ NULL); ++ } ++ break; ++ case IWEVMICHAELMICFAILURE: ++ if (custom + iwe->u.data.length > end) { ++ wpa_printf(MSG_DEBUG, "WEXT: Invalid " ++ "IWEVMICHAELMICFAILURE length"); ++ return; ++ } ++ wpa_driver_wext_event_wireless_michaelmicfailure( ++ drv->ctx, custom, iwe->u.data.length); ++ break; ++ case IWEVCUSTOM: ++ if (custom + iwe->u.data.length > end) { ++ wpa_printf(MSG_DEBUG, "WEXT: Invalid " ++ "IWEVCUSTOM length"); ++ return; ++ } ++ buf = dup_binstr(custom, iwe->u.data.length); ++ if (buf == NULL) ++ return; ++ wpa_driver_wext_event_wireless_custom(drv->ctx, buf); ++ os_free(buf); ++ break; ++ case SIOCGIWSCAN: ++ drv->scan_complete_events = 1; ++ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, ++ drv, drv->ctx); ++ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, ++ NULL); ++ break; ++ case IWEVASSOCREQIE: ++ if (custom + iwe->u.data.length > end) { ++ wpa_printf(MSG_DEBUG, "WEXT: Invalid " ++ "IWEVASSOCREQIE length"); ++ return; ++ } ++ wpa_driver_wext_event_wireless_assocreqie( ++ drv, custom, iwe->u.data.length); ++ break; ++ case IWEVASSOCRESPIE: ++ if (custom + iwe->u.data.length > end) { ++ wpa_printf(MSG_DEBUG, "WEXT: Invalid " ++ "IWEVASSOCRESPIE length"); ++ return; ++ } ++ wpa_driver_wext_event_wireless_assocrespie( ++ drv, custom, iwe->u.data.length); ++ break; ++ case IWEVPMKIDCAND: ++ if (custom + iwe->u.data.length > end) { ++ wpa_printf(MSG_DEBUG, "WEXT: Invalid " ++ "IWEVPMKIDCAND length"); ++ return; ++ } ++ wpa_driver_wext_event_wireless_pmkidcand( ++ drv, custom, iwe->u.data.length); ++ break; ++ } ++ ++ pos += iwe->len; ++ } ++} ++ ++ ++static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv, ++ char *buf, size_t len, int del) ++{ ++ union wpa_event_data event; ++ ++ os_memset(&event, 0, sizeof(event)); ++ if (len > sizeof(event.interface_status.ifname)) ++ len = sizeof(event.interface_status.ifname) - 1; ++ os_memcpy(event.interface_status.ifname, buf, len); ++ event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED : ++ EVENT_INTERFACE_ADDED; ++ ++ wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s", ++ del ? "DEL" : "NEW", ++ event.interface_status.ifname, ++ del ? "removed" : "added"); ++ ++ if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) { ++ if (del) { ++ if (drv->if_removed) { ++ wpa_printf(MSG_DEBUG, "WEXT: if_removed " ++ "already set - ignore event"); ++ return; ++ } ++ drv->if_removed = 1; ++ } else { ++ if (if_nametoindex(drv->ifname) == 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: Interface %s " ++ "does not exist - ignore " ++ "RTM_NEWLINK", ++ drv->ifname); ++ return; ++ } ++ if (!drv->if_removed) { ++ wpa_printf(MSG_DEBUG, "WEXT: if_removed " ++ "already cleared - ignore event"); ++ return; ++ } ++ drv->if_removed = 0; ++ } ++ } ++ ++ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); ++} ++ ++ ++static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv, ++ u8 *buf, size_t len) ++{ ++ int attrlen, rta_len; ++ struct rtattr *attr; ++ ++ attrlen = len; ++ attr = (struct rtattr *) buf; ++ ++ rta_len = RTA_ALIGN(sizeof(struct rtattr)); ++ while (RTA_OK(attr, attrlen)) { ++ if (attr->rta_type == IFLA_IFNAME) { ++ if (os_strcmp(((char *) attr) + rta_len, drv->ifname) ++ == 0) ++ return 1; ++ else ++ break; ++ } ++ attr = RTA_NEXT(attr, attrlen); ++ } ++ ++ return 0; ++} ++ ++ ++static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv, ++ int ifindex, u8 *buf, size_t len) ++{ ++ if (drv->ifindex == ifindex || drv->ifindex2 == ifindex) ++ return 1; ++ ++ if (drv->if_removed && wpa_driver_wext_own_ifname(drv, buf, len)) { ++ drv->ifindex = if_nametoindex(drv->ifname); ++ wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed " ++ "interface"); ++ wpa_driver_wext_finish_drv_init(drv); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++ ++static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, ++ u8 *buf, size_t len) ++{ ++ struct wpa_driver_wext_data *drv = ctx; ++ int attrlen, rta_len; ++ struct rtattr *attr; ++ char namebuf[IFNAMSIZ]; ++ ++ if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) { ++ wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d", ++ ifi->ifi_index); ++ return; ++ } ++ ++ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x " ++ "(%s%s%s%s)", ++ drv->operstate, ifi->ifi_flags, ++ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", ++ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", ++ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", ++ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); ++ ++ if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) { ++ wpa_printf(MSG_DEBUG, "WEXT: Interface down"); ++ drv->if_disabled = 1; ++ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); ++ } ++ ++ if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) { ++ if (if_indextoname(ifi->ifi_index, namebuf) && ++ linux_iface_up(drv->ioctl_sock, drv->ifname) == 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up " ++ "event since interface %s is down", ++ namebuf); ++ } else if (if_nametoindex(drv->ifname) == 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up " ++ "event since interface %s does not exist", ++ drv->ifname); ++ } else if (drv->if_removed) { ++ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up " ++ "event since interface %s is marked " ++ "removed", drv->ifname); ++ } else { ++ wpa_printf(MSG_DEBUG, "WEXT: Interface up"); ++ drv->if_disabled = 0; ++ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, ++ NULL); ++ } ++ } ++ ++ /* ++ * Some drivers send the association event before the operup event--in ++ * this case, lifting operstate in wpa_driver_wext_set_operstate() ++ * fails. This will hit us when wpa_supplicant does not need to do ++ * IEEE 802.1X authentication ++ */ ++ if (drv->operstate == 1 && ++ (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && ++ !(ifi->ifi_flags & IFF_RUNNING)) ++ netlink_send_oper_ifla(drv->netlink, drv->ifindex, ++ -1, IF_OPER_UP); ++ ++ attrlen = len; ++ attr = (struct rtattr *) buf; ++ ++ rta_len = RTA_ALIGN(sizeof(struct rtattr)); ++ while (RTA_OK(attr, attrlen)) { ++ if (attr->rta_type == IFLA_WIRELESS) { ++ wpa_driver_wext_event_wireless( ++ drv, ((char *) attr) + rta_len, ++ attr->rta_len - rta_len); ++ } else if (attr->rta_type == IFLA_IFNAME) { ++ wpa_driver_wext_event_link(drv, ++ ((char *) attr) + rta_len, ++ attr->rta_len - rta_len, 0); ++ } ++ attr = RTA_NEXT(attr, attrlen); ++ } ++} ++ ++ ++static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi, ++ u8 *buf, size_t len) ++{ ++ struct wpa_driver_wext_data *drv = ctx; ++ int attrlen, rta_len; ++ struct rtattr *attr; ++ ++ attrlen = len; ++ attr = (struct rtattr *) buf; ++ ++ rta_len = RTA_ALIGN(sizeof(struct rtattr)); ++ while (RTA_OK(attr, attrlen)) { ++ if (attr->rta_type == IFLA_IFNAME) { ++ wpa_driver_wext_event_link(drv, ++ ((char *) attr) + rta_len, ++ attr->rta_len - rta_len, 1); ++ } ++ attr = RTA_NEXT(attr, attrlen); ++ } ++} ++ ++ ++static void wpa_driver_wext_rfkill_blocked(void *ctx) ++{ ++ wpa_printf(MSG_DEBUG, "WEXT: RFKILL blocked"); ++ /* ++ * This may be for any interface; use ifdown event to disable ++ * interface. ++ */ ++} ++ ++ ++static void wpa_driver_wext_rfkill_unblocked(void *ctx) ++{ ++ struct wpa_driver_wext_data *drv = ctx; ++ wpa_printf(MSG_DEBUG, "WEXT: RFKILL unblocked"); ++ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1)) { ++ wpa_printf(MSG_DEBUG, "WEXT: Could not set interface UP " ++ "after rfkill unblock"); ++ return; ++ } ++ /* rtnetlink ifup handler will report interface as enabled */ ++} ++ ++ ++static void wext_get_phy_name(struct wpa_driver_wext_data *drv) ++{ ++ /* Find phy (radio) to which this interface belongs */ ++ char buf[90], *pos; ++ int f, rv; ++ ++ drv->phyname[0] = '\0'; ++ snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name", ++ drv->ifname); ++ f = open(buf, O_RDONLY); ++ if (f < 0) { ++ wpa_printf(MSG_DEBUG, "Could not open file %s: %s", ++ buf, strerror(errno)); ++ return; ++ } ++ ++ rv = read(f, drv->phyname, sizeof(drv->phyname) - 1); ++ close(f); ++ if (rv < 0) { ++ wpa_printf(MSG_DEBUG, "Could not read file %s: %s", ++ buf, strerror(errno)); ++ return; ++ } ++ ++ drv->phyname[rv] = '\0'; ++ pos = os_strchr(drv->phyname, '\n'); ++ if (pos) ++ *pos = '\0'; ++ wpa_printf(MSG_DEBUG, "wext: interface %s phy: %s", ++ drv->ifname, drv->phyname); ++} ++ ++ ++/** ++ * wpa_driver_wext_init - Initialize WE driver interface ++ * @ctx: context to be used when calling wpa_supplicant functions, ++ * e.g., wpa_supplicant_event() ++ * @ifname: interface name, e.g., wlan0 ++ * Returns: Pointer to private data, %NULL on failure ++ */ ++void * wpa_driver_wext_init(void *ctx, const char *ifname) ++{ ++ struct wpa_driver_wext_data *drv; ++ struct netlink_config *cfg; ++ struct rfkill_config *rcfg; ++ char path[128]; ++ struct stat buf; ++ ++ drv = os_zalloc(sizeof(*drv)); ++ if (drv == NULL) ++ return NULL; ++ drv->ctx = ctx; ++ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); ++ ++ os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname); ++ if (stat(path, &buf) == 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected"); ++ drv->cfg80211 = 1; ++ wext_get_phy_name(drv); ++ } ++ ++ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); ++ if (drv->ioctl_sock < 0) { ++ wpa_printf(MSG_ERROR, "socket(PF_INET,SOCK_DGRAM): %s", ++ strerror(errno)); ++ goto err1; ++ } ++ ++ cfg = os_zalloc(sizeof(*cfg)); ++ if (cfg == NULL) ++ goto err1; ++ cfg->ctx = drv; ++ cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink; ++ cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink; ++ drv->netlink = netlink_init(cfg); ++ if (drv->netlink == NULL) { ++ os_free(cfg); ++ goto err2; ++ } ++ ++ rcfg = os_zalloc(sizeof(*rcfg)); ++ if (rcfg == NULL) ++ goto err3; ++ rcfg->ctx = drv; ++ os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname)); ++ rcfg->blocked_cb = wpa_driver_wext_rfkill_blocked; ++ rcfg->unblocked_cb = wpa_driver_wext_rfkill_unblocked; ++ drv->rfkill = rfkill_init(rcfg); ++ if (drv->rfkill == NULL) { ++ wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available"); ++ os_free(rcfg); ++ } ++ ++ drv->mlme_sock = -1; ++ ++ if (wpa_driver_wext_finish_drv_init(drv) < 0) ++ goto err3; ++ ++ wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1); ++ ++ return drv; ++ ++err3: ++ rfkill_deinit(drv->rfkill); ++ netlink_deinit(drv->netlink); ++err2: ++ close(drv->ioctl_sock); ++err1: ++ os_free(drv); ++ return NULL; ++} ++ ++ ++static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx) ++{ ++ wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); ++} ++ ++ ++static int wext_hostap_ifname(struct wpa_driver_wext_data *drv, ++ const char *ifname) ++{ ++ char buf[200], *res; ++ int type; ++ FILE *f; ++ ++ if (strcmp(ifname, ".") == 0 || strcmp(ifname, "..") == 0) ++ return -1; ++ ++ snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net/%s/type", ++ drv->ifname, ifname); ++ ++ f = fopen(buf, "r"); ++ if (!f) ++ return -1; ++ res = fgets(buf, sizeof(buf), f); ++ fclose(f); ++ ++ type = res ? atoi(res) : -1; ++ wpa_printf(MSG_DEBUG, "WEXT: hostap ifname %s type %d", ifname, type); ++ ++ if (type == ARPHRD_IEEE80211) { ++ wpa_printf(MSG_DEBUG, ++ "WEXT: Found hostap driver wifi# interface (%s)", ++ ifname); ++ wpa_driver_wext_alternative_ifindex(drv, ifname); ++ return 0; ++ } ++ return -1; ++} ++ ++ ++static int wext_add_hostap(struct wpa_driver_wext_data *drv) ++{ ++ char buf[200]; ++ int n; ++ struct dirent **names; ++ int ret = -1; ++ ++ snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net", drv->ifname); ++ n = scandir(buf, &names, NULL, alphasort); ++ if (n < 0) ++ return -1; ++ ++ while (n--) { ++ if (ret < 0 && wext_hostap_ifname(drv, names[n]->d_name) == 0) ++ ret = 0; ++ free(names[n]); ++ } ++ free(names); ++ ++ return ret; ++} ++ ++ ++static void wext_check_hostap(struct wpa_driver_wext_data *drv) ++{ ++ char buf[200], *pos; ++ ssize_t res; ++ ++ /* ++ * Host AP driver may use both wlan# and wifi# interface in wireless ++ * events. Since some of the versions included WE-18 support, let's add ++ * the alternative ifindex also from driver_wext.c for the time being. ++ * This may be removed at some point once it is believed that old ++ * versions of the driver are not in use anymore. However, it looks like ++ * the wifi# interface is still used in the current kernel tree, so it ++ * may not really be possible to remove this before the Host AP driver ++ * gets removed from the kernel. ++ */ ++ ++ /* First, try to see if driver information is available from sysfs */ ++ snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver", ++ drv->ifname); ++ res = readlink(buf, buf, sizeof(buf) - 1); ++ if (res > 0) { ++ buf[res] = '\0'; ++ pos = strrchr(buf, '/'); ++ if (pos) ++ pos++; ++ else ++ pos = buf; ++ wpa_printf(MSG_DEBUG, "WEXT: Driver: %s", pos); ++ if (os_strncmp(pos, "hostap", 6) == 0 && ++ wext_add_hostap(drv) == 0) ++ return; ++ } ++ ++ /* Second, use the old design with hardcoded ifname */ ++ if (os_strncmp(drv->ifname, "wlan", 4) == 0) { ++ char ifname2[IFNAMSIZ + 1]; ++ os_strlcpy(ifname2, drv->ifname, sizeof(ifname2)); ++ os_memcpy(ifname2, "wifi", 4); ++ wpa_driver_wext_alternative_ifindex(drv, ifname2); ++ } ++} ++ ++ ++static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) ++{ ++ int send_rfkill_event = 0; ++ ++ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) { ++ if (rfkill_is_blocked(drv->rfkill)) { ++ wpa_printf(MSG_DEBUG, "WEXT: Could not yet enable " ++ "interface '%s' due to rfkill", ++ drv->ifname); ++ drv->if_disabled = 1; ++ send_rfkill_event = 1; ++ } else { ++ wpa_printf(MSG_ERROR, "WEXT: Could not set " ++ "interface '%s' UP", drv->ifname); ++ return -1; ++ } ++ } ++ ++ /* ++ * Make sure that the driver does not have any obsolete PMKID entries. ++ */ ++ wpa_driver_wext_flush_pmkid(drv); ++ ++ if (wpa_driver_wext_set_mode(drv, 0) < 0) { ++ wpa_printf(MSG_DEBUG, "Could not configure driver to use " ++ "managed mode"); ++ /* Try to use it anyway */ ++ } ++ ++ wpa_driver_wext_get_range(drv); ++ ++ /* ++ * Unlock the driver's BSSID and force to a random SSID to clear any ++ * previous association the driver might have when the supplicant ++ * starts up. ++ */ ++ wpa_driver_wext_disconnect(drv); ++ ++ drv->ifindex = if_nametoindex(drv->ifname); ++ ++ wext_check_hostap(drv); ++ ++ netlink_send_oper_ifla(drv->netlink, drv->ifindex, ++ 1, IF_OPER_DORMANT); ++ ++ if (send_rfkill_event) { ++ eloop_register_timeout(0, 0, wpa_driver_wext_send_rfkill, ++ drv, drv->ctx); ++ } ++ ++ return 0; ++} ++ ++ ++/** ++ * wpa_driver_wext_deinit - Deinitialize WE driver interface ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * ++ * Shut down driver interface and processing of driver events. Free ++ * private data buffer if one was allocated in wpa_driver_wext_init(). ++ */ ++void wpa_driver_wext_deinit(void *priv) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ ++ wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 0); ++ ++ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); ++ ++ /* ++ * Clear possibly configured driver parameters in order to make it ++ * easier to use the driver after wpa_supplicant has been terminated. ++ */ ++ wpa_driver_wext_disconnect(drv); ++ ++ netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); ++ netlink_deinit(drv->netlink); ++ rfkill_deinit(drv->rfkill); ++ ++ if (drv->mlme_sock >= 0) ++ eloop_unregister_read_sock(drv->mlme_sock); ++ ++ (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); ++ ++ close(drv->ioctl_sock); ++ if (drv->mlme_sock >= 0) ++ close(drv->mlme_sock); ++ os_free(drv->assoc_req_ies); ++ os_free(drv->assoc_resp_ies); ++ os_free(drv); ++} ++ ++ ++/** ++ * wpa_driver_wext_scan_timeout - Scan timeout to report scan completion ++ * @eloop_ctx: Unused ++ * @timeout_ctx: ctx argument given to wpa_driver_wext_init() ++ * ++ * This function can be used as registered timeout when starting a scan to ++ * generate a scan completed event if the driver does not report this. ++ */ ++void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx) ++{ ++ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); ++ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); ++} ++ ++ ++/** ++ * wpa_driver_wext_scan - Request the driver to initiate scan ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @param: Scan parameters (specific SSID to scan for (ProbeReq), etc.) ++ * Returns: 0 on success, -1 on failure ++ */ ++int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0, timeout; ++ struct iw_scan_req req; ++ const u8 *ssid = params->ssids[0].ssid; ++ size_t ssid_len = params->ssids[0].ssid_len; ++ ++ if (ssid_len > IW_ESSID_MAX_SIZE) { ++ wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)", ++ __FUNCTION__, (unsigned long) ssid_len); ++ return -1; ++ } ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ ++ if (ssid && ssid_len) { ++ os_memset(&req, 0, sizeof(req)); ++ req.essid_len = ssid_len; ++ req.bssid.sa_family = ARPHRD_ETHER; ++ os_memset(req.bssid.sa_data, 0xff, ETH_ALEN); ++ os_memcpy(req.essid, ssid, ssid_len); ++ iwr.u.data.pointer = (caddr_t) &req; ++ iwr.u.data.length = sizeof(req); ++ iwr.u.data.flags = IW_SCAN_THIS_ESSID; ++ } ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWSCAN]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ /* Not all drivers generate "scan completed" wireless event, so try to ++ * read results after a timeout. */ ++ timeout = 10; ++ if (drv->scan_complete_events) { ++ /* ++ * The driver seems to deliver SIOCGIWSCAN events to notify ++ * when scan is complete, so use longer timeout to avoid race ++ * conditions with scanning and following association request. ++ */ ++ timeout = 30; ++ } ++ wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " ++ "seconds", ret, timeout); ++ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); ++ eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv, ++ drv->ctx); ++ ++ return ret; ++} ++ ++ ++static u8 * wpa_driver_wext_giwscan(struct wpa_driver_wext_data *drv, ++ size_t *len) ++{ ++ struct iwreq iwr; ++ u8 *res_buf; ++ size_t res_buf_len; ++ ++ res_buf_len = IW_SCAN_MAX_DATA; ++ for (;;) { ++ res_buf = os_malloc(res_buf_len); ++ if (res_buf == NULL) ++ return NULL; ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.data.pointer = res_buf; ++ iwr.u.data.length = res_buf_len; ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0) ++ break; ++ ++ if (errno == E2BIG && res_buf_len < 65535) { ++ os_free(res_buf); ++ res_buf = NULL; ++ res_buf_len *= 2; ++ if (res_buf_len > 65535) ++ res_buf_len = 65535; /* 16-bit length field */ ++ wpa_printf(MSG_DEBUG, "Scan results did not fit - " ++ "trying larger buffer (%lu bytes)", ++ (unsigned long) res_buf_len); ++ } else { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWSCAN]: %s", ++ strerror(errno)); ++ os_free(res_buf); ++ return NULL; ++ } ++ } ++ ++ if (iwr.u.data.length > res_buf_len) { ++ os_free(res_buf); ++ return NULL; ++ } ++ *len = iwr.u.data.length; ++ ++ return res_buf; ++} ++ ++ ++/* ++ * Data structure for collecting WEXT scan results. This is needed to allow ++ * the various methods of reporting IEs to be combined into a single IE buffer. ++ */ ++struct wext_scan_data { ++ struct wpa_scan_res res; ++ u8 *ie; ++ size_t ie_len; ++ u8 ssid[SSID_MAX_LEN]; ++ size_t ssid_len; ++ int maxrate; ++}; ++ ++ ++static void wext_get_scan_mode(struct iw_event *iwe, ++ struct wext_scan_data *res) ++{ ++ if (iwe->u.mode == IW_MODE_ADHOC) ++ res->res.caps |= IEEE80211_CAP_IBSS; ++ else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA) ++ res->res.caps |= IEEE80211_CAP_ESS; ++} ++ ++ ++static void wext_get_scan_ssid(struct iw_event *iwe, ++ struct wext_scan_data *res, char *custom, ++ char *end) ++{ ++ int ssid_len = iwe->u.essid.length; ++ if (custom + ssid_len > end) ++ return; ++ if (iwe->u.essid.flags && ++ ssid_len > 0 && ++ ssid_len <= IW_ESSID_MAX_SIZE) { ++ os_memcpy(res->ssid, custom, ssid_len); ++ res->ssid_len = ssid_len; ++ } ++} ++ ++ ++static void wext_get_scan_freq(struct iw_event *iwe, ++ struct wext_scan_data *res) ++{ ++ int divi = 1000000, i; ++ ++ if (iwe->u.freq.e == 0) { ++ /* ++ * Some drivers do not report frequency, but a channel. ++ * Try to map this to frequency by assuming they are using ++ * IEEE 802.11b/g. But don't overwrite a previously parsed ++ * frequency if the driver sends both frequency and channel, ++ * since the driver may be sending an A-band channel that we ++ * don't handle here. ++ */ ++ ++ if (res->res.freq) ++ return; ++ ++ if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) { ++ res->res.freq = 2407 + 5 * iwe->u.freq.m; ++ return; ++ } else if (iwe->u.freq.m == 14) { ++ res->res.freq = 2484; ++ return; ++ } ++ } ++ ++ if (iwe->u.freq.e > 6) { ++ wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID=" ++ MACSTR " m=%d e=%d)", ++ MAC2STR(res->res.bssid), iwe->u.freq.m, ++ iwe->u.freq.e); ++ return; ++ } ++ ++ for (i = 0; i < iwe->u.freq.e; i++) ++ divi /= 10; ++ res->res.freq = iwe->u.freq.m / divi; ++} ++ ++ ++static void wext_get_scan_qual(struct wpa_driver_wext_data *drv, ++ struct iw_event *iwe, ++ struct wext_scan_data *res) ++{ ++ res->res.qual = iwe->u.qual.qual; ++ res->res.noise = iwe->u.qual.noise; ++ res->res.level = iwe->u.qual.level; ++ if (iwe->u.qual.updated & IW_QUAL_QUAL_INVALID) ++ res->res.flags |= WPA_SCAN_QUAL_INVALID; ++ if (iwe->u.qual.updated & IW_QUAL_LEVEL_INVALID) ++ res->res.flags |= WPA_SCAN_LEVEL_INVALID; ++ if (iwe->u.qual.updated & IW_QUAL_NOISE_INVALID) ++ res->res.flags |= WPA_SCAN_NOISE_INVALID; ++ if (iwe->u.qual.updated & IW_QUAL_DBM) ++ res->res.flags |= WPA_SCAN_LEVEL_DBM; ++ if ((iwe->u.qual.updated & IW_QUAL_DBM) || ++ ((iwe->u.qual.level != 0) && ++ (iwe->u.qual.level > drv->max_level))) { ++ if (iwe->u.qual.level >= 64) ++ res->res.level -= 0x100; ++ if (iwe->u.qual.noise >= 64) ++ res->res.noise -= 0x100; ++ } ++} ++ ++ ++static void wext_get_scan_encode(struct iw_event *iwe, ++ struct wext_scan_data *res) ++{ ++ if (!(iwe->u.data.flags & IW_ENCODE_DISABLED)) ++ res->res.caps |= IEEE80211_CAP_PRIVACY; ++} ++ ++ ++static void wext_get_scan_rate(struct iw_event *iwe, ++ struct wext_scan_data *res, char *pos, ++ char *end) ++{ ++ int maxrate; ++ char *custom = pos + IW_EV_LCP_LEN; ++ struct iw_param p; ++ size_t clen; ++ ++ clen = iwe->len; ++ if (custom + clen > end) ++ return; ++ maxrate = 0; ++ while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) { ++ /* Note: may be misaligned, make a local, aligned copy */ ++ os_memcpy(&p, custom, sizeof(struct iw_param)); ++ if (p.value > maxrate) ++ maxrate = p.value; ++ clen -= sizeof(struct iw_param); ++ custom += sizeof(struct iw_param); ++ } ++ ++ /* Convert the maxrate from WE-style (b/s units) to ++ * 802.11 rates (500000 b/s units). ++ */ ++ res->maxrate = maxrate / 500000; ++} ++ ++ ++static void wext_get_scan_iwevgenie(struct iw_event *iwe, ++ struct wext_scan_data *res, char *custom, ++ char *end) ++{ ++ char *genie, *gpos, *gend; ++ u8 *tmp; ++ ++ if (iwe->u.data.length == 0) ++ return; ++ ++ gpos = genie = custom; ++ gend = genie + iwe->u.data.length; ++ if (gend > end) { ++ wpa_printf(MSG_INFO, "IWEVGENIE overflow"); ++ return; ++ } ++ ++ tmp = os_realloc(res->ie, res->ie_len + gend - gpos); ++ if (tmp == NULL) ++ return; ++ os_memcpy(tmp + res->ie_len, gpos, gend - gpos); ++ res->ie = tmp; ++ res->ie_len += gend - gpos; ++} ++ ++ ++static void wext_get_scan_custom(struct iw_event *iwe, ++ struct wext_scan_data *res, char *custom, ++ char *end) ++{ ++ size_t clen; ++ u8 *tmp; ++ ++ clen = iwe->u.data.length; ++ if (custom + clen > end) ++ return; ++ ++ if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) { ++ char *spos; ++ int bytes; ++ spos = custom + 7; ++ bytes = custom + clen - spos; ++ if (bytes & 1 || bytes == 0) ++ return; ++ bytes /= 2; ++ tmp = os_realloc(res->ie, res->ie_len + bytes); ++ if (tmp == NULL) ++ return; ++ res->ie = tmp; ++ if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0) ++ return; ++ res->ie_len += bytes; ++ } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) { ++ char *spos; ++ int bytes; ++ spos = custom + 7; ++ bytes = custom + clen - spos; ++ if (bytes & 1 || bytes == 0) ++ return; ++ bytes /= 2; ++ tmp = os_realloc(res->ie, res->ie_len + bytes); ++ if (tmp == NULL) ++ return; ++ res->ie = tmp; ++ if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0) ++ return; ++ res->ie_len += bytes; ++ } else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) { ++ char *spos; ++ int bytes; ++ u8 bin[8]; ++ spos = custom + 4; ++ bytes = custom + clen - spos; ++ if (bytes != 16) { ++ wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes); ++ return; ++ } ++ bytes /= 2; ++ if (hexstr2bin(spos, bin, bytes) < 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: Invalid TSF value"); ++ return; ++ } ++ res->res.tsf += WPA_GET_BE64(bin); ++ } ++} ++ ++ ++static int wext_19_iw_point(struct wpa_driver_wext_data *drv, u16 cmd) ++{ ++ return drv->we_version_compiled > 18 && ++ (cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE || ++ cmd == IWEVGENIE || cmd == IWEVCUSTOM); ++} ++ ++ ++static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res, ++ struct wext_scan_data *data) ++{ ++ struct wpa_scan_res **tmp; ++ struct wpa_scan_res *r; ++ size_t extra_len; ++ u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL; ++ ++ /* Figure out whether we need to fake any IEs */ ++ pos = data->ie; ++ end = pos + data->ie_len; ++ while (pos && pos + 1 < end) { ++ if (pos + 2 + pos[1] > end) ++ break; ++ if (pos[0] == WLAN_EID_SSID) ++ ssid_ie = pos; ++ else if (pos[0] == WLAN_EID_SUPP_RATES) ++ rate_ie = pos; ++ else if (pos[0] == WLAN_EID_EXT_SUPP_RATES) ++ rate_ie = pos; ++ pos += 2 + pos[1]; ++ } ++ ++ extra_len = 0; ++ if (ssid_ie == NULL) ++ extra_len += 2 + data->ssid_len; ++ if (rate_ie == NULL && data->maxrate) ++ extra_len += 3; ++ ++ r = os_zalloc(sizeof(*r) + extra_len + data->ie_len); ++ if (r == NULL) ++ return; ++ os_memcpy(r, &data->res, sizeof(*r)); ++ r->ie_len = extra_len + data->ie_len; ++ pos = (u8 *) (r + 1); ++ if (ssid_ie == NULL) { ++ /* ++ * Generate a fake SSID IE since the driver did not report ++ * a full IE list. ++ */ ++ *pos++ = WLAN_EID_SSID; ++ *pos++ = data->ssid_len; ++ os_memcpy(pos, data->ssid, data->ssid_len); ++ pos += data->ssid_len; ++ } ++ if (rate_ie == NULL && data->maxrate) { ++ /* ++ * Generate a fake Supported Rates IE since the driver did not ++ * report a full IE list. ++ */ ++ *pos++ = WLAN_EID_SUPP_RATES; ++ *pos++ = 1; ++ *pos++ = data->maxrate; ++ } ++ if (data->ie) ++ os_memcpy(pos, data->ie, data->ie_len); ++ ++ tmp = os_realloc_array(res->res, res->num + 1, ++ sizeof(struct wpa_scan_res *)); ++ if (tmp == NULL) { ++ os_free(r); ++ return; ++ } ++ tmp[res->num++] = r; ++ res->res = tmp; ++} ++ ++ ++/** ++ * wpa_driver_wext_get_scan_results - Fetch the latest scan results ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * Returns: Scan results on success, -1 on failure ++ */ ++struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ size_t len; ++ int first; ++ u8 *res_buf; ++ struct iw_event iwe_buf, *iwe = &iwe_buf; ++ char *pos, *end, *custom; ++ struct wpa_scan_results *res; ++ struct wext_scan_data data; ++ ++ res_buf = wpa_driver_wext_giwscan(drv, &len); ++ if (res_buf == NULL) ++ return NULL; ++ ++ first = 1; ++ ++ res = os_zalloc(sizeof(*res)); ++ if (res == NULL) { ++ os_free(res_buf); ++ return NULL; ++ } ++ ++ pos = (char *) res_buf; ++ end = (char *) res_buf + len; ++ os_memset(&data, 0, sizeof(data)); ++ ++ while (pos + IW_EV_LCP_LEN <= end) { ++ /* Event data may be unaligned, so make a local, aligned copy ++ * before processing. */ ++ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); ++ if (iwe->len <= IW_EV_LCP_LEN) ++ break; ++ ++ custom = pos + IW_EV_POINT_LEN; ++ if (wext_19_iw_point(drv, iwe->cmd)) { ++ /* WE-19 removed the pointer from struct iw_point */ ++ char *dpos = (char *) &iwe_buf.u.data.length; ++ int dlen = dpos - (char *) &iwe_buf; ++ os_memcpy(dpos, pos + IW_EV_LCP_LEN, ++ sizeof(struct iw_event) - dlen); ++ } else { ++ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); ++ custom += IW_EV_POINT_OFF; ++ } ++ ++ switch (iwe->cmd) { ++ case SIOCGIWAP: ++ if (!first) ++ wpa_driver_wext_add_scan_entry(res, &data); ++ first = 0; ++ os_free(data.ie); ++ os_memset(&data, 0, sizeof(data)); ++ os_memcpy(data.res.bssid, ++ iwe->u.ap_addr.sa_data, ETH_ALEN); ++ break; ++ case SIOCGIWMODE: ++ wext_get_scan_mode(iwe, &data); ++ break; ++ case SIOCGIWESSID: ++ wext_get_scan_ssid(iwe, &data, custom, end); ++ break; ++ case SIOCGIWFREQ: ++ wext_get_scan_freq(iwe, &data); ++ break; ++ case IWEVQUAL: ++ wext_get_scan_qual(drv, iwe, &data); ++ break; ++ case SIOCGIWENCODE: ++ wext_get_scan_encode(iwe, &data); ++ break; ++ case SIOCGIWRATE: ++ wext_get_scan_rate(iwe, &data, pos, end); ++ break; ++ case IWEVGENIE: ++ wext_get_scan_iwevgenie(iwe, &data, custom, end); ++ break; ++ case IWEVCUSTOM: ++ wext_get_scan_custom(iwe, &data, custom, end); ++ break; ++ } ++ ++ pos += iwe->len; ++ } ++ os_free(res_buf); ++ res_buf = NULL; ++ if (!first) ++ wpa_driver_wext_add_scan_entry(res, &data); ++ os_free(data.ie); ++ ++ wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)", ++ (unsigned long) len, (unsigned long) res->num); ++ ++ return res; ++} ++ ++ ++static int wpa_driver_wext_get_range(void *priv) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iw_range *range; ++ struct iwreq iwr; ++ int minlen; ++ size_t buflen; ++ ++ /* ++ * Use larger buffer than struct iw_range in order to allow the ++ * structure to grow in the future. ++ */ ++ buflen = sizeof(struct iw_range) + 500; ++ range = os_zalloc(buflen); ++ if (range == NULL) ++ return -1; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.data.pointer = (caddr_t) range; ++ iwr.u.data.length = buflen; ++ ++ minlen = ((char *) &range->enc_capa) - (char *) range + ++ sizeof(range->enc_capa); ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s", ++ strerror(errno)); ++ os_free(range); ++ return -1; ++ } else if (iwr.u.data.length >= minlen && ++ range->we_version_compiled >= 18) { ++ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " ++ "WE(source)=%d enc_capa=0x%x", ++ range->we_version_compiled, ++ range->we_version_source, ++ range->enc_capa); ++ drv->has_capability = 1; ++ drv->we_version_compiled = range->we_version_compiled; ++ if (range->enc_capa & IW_ENC_CAPA_WPA) { ++ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA | ++ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; ++ } ++ if (range->enc_capa & IW_ENC_CAPA_WPA2) { ++ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | ++ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; ++ } ++ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | ++ WPA_DRIVER_CAPA_ENC_WEP104; ++ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP128; ++ if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP) ++ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; ++ if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP) ++ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; ++ if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE) ++ drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE; ++ drv->capa.auth = WPA_DRIVER_AUTH_OPEN | ++ WPA_DRIVER_AUTH_SHARED | ++ WPA_DRIVER_AUTH_LEAP; ++ drv->capa.max_scan_ssids = 1; ++ ++ wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x " ++ "flags 0x%llx", ++ drv->capa.key_mgmt, drv->capa.enc, ++ (unsigned long long) drv->capa.flags); ++ } else { ++ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - " ++ "assuming WPA is not supported"); ++ } ++ ++ drv->max_level = range->max_qual.level; ++ ++ os_free(range); ++ return 0; ++} ++ ++ ++static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv, ++ const u8 *psk) ++{ ++ struct iw_encode_ext *ext; ++ struct iwreq iwr; ++ int ret; ++ ++ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); ++ ++ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) ++ return 0; ++ ++ if (!psk) ++ return 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ ++ ext = os_zalloc(sizeof(*ext) + PMK_LEN); ++ if (ext == NULL) ++ return -1; ++ ++ iwr.u.encoding.pointer = (caddr_t) ext; ++ iwr.u.encoding.length = sizeof(*ext) + PMK_LEN; ++ ext->key_len = PMK_LEN; ++ os_memcpy(&ext->key, psk, ext->key_len); ++ ext->alg = IW_ENCODE_ALG_PMK; ++ ++ ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr); ++ if (ret < 0) ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODEEXT] PMK: %s", ++ strerror(errno)); ++ os_free(ext); ++ ++ return ret; ++} ++ ++ ++static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg, ++ const u8 *addr, int key_idx, ++ int set_tx, const u8 *seq, ++ size_t seq_len, ++ const u8 *key, size_t key_len) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ struct iw_encode_ext *ext; ++ ++ if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) { ++ wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu", ++ __FUNCTION__, (unsigned long) seq_len); ++ return -1; ++ } ++ ++ ext = os_zalloc(sizeof(*ext) + key_len); ++ if (ext == NULL) ++ return -1; ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.encoding.flags = key_idx + 1; ++ iwr.u.encoding.flags |= IW_ENCODE_TEMP; ++ if (alg == WPA_ALG_NONE) ++ iwr.u.encoding.flags |= IW_ENCODE_DISABLED; ++ iwr.u.encoding.pointer = (caddr_t) ext; ++ iwr.u.encoding.length = sizeof(*ext) + key_len; ++ ++ if (addr == NULL || is_broadcast_ether_addr(addr)) ++ ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY; ++ if (set_tx) ++ ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY; ++ ++ ext->addr.sa_family = ARPHRD_ETHER; ++ if (addr) ++ os_memcpy(ext->addr.sa_data, addr, ETH_ALEN); ++ else ++ os_memset(ext->addr.sa_data, 0xff, ETH_ALEN); ++ if (key && key_len) { ++ os_memcpy(ext + 1, key, key_len); ++ ext->key_len = key_len; ++ } ++ switch (alg) { ++ case WPA_ALG_NONE: ++ ext->alg = IW_ENCODE_ALG_NONE; ++ break; ++ case WPA_ALG_WEP: ++ ext->alg = IW_ENCODE_ALG_WEP; ++ break; ++ case WPA_ALG_TKIP: ++ ext->alg = IW_ENCODE_ALG_TKIP; ++ break; ++ case WPA_ALG_CCMP: ++ ext->alg = IW_ENCODE_ALG_CCMP; ++ break; ++ case WPA_ALG_PMK: ++ ext->alg = IW_ENCODE_ALG_PMK; ++ break; ++#ifdef CONFIG_IEEE80211W ++ case WPA_ALG_IGTK: ++ ext->alg = IW_ENCODE_ALG_AES_CMAC; ++ break; ++#endif /* CONFIG_IEEE80211W */ ++ default: ++ wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d", ++ __FUNCTION__, alg); ++ os_free(ext); ++ return -1; ++ } ++ ++ if (seq && seq_len) { ++ ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID; ++ os_memcpy(ext->rx_seq, seq, seq_len); ++ } ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) { ++ ret = errno == EOPNOTSUPP ? -2 : -1; ++ if (errno == ENODEV) { ++ /* ++ * ndiswrapper seems to be returning incorrect error ++ * code.. */ ++ ret = -2; ++ } ++ ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODEEXT]: %s", ++ strerror(errno)); ++ } ++ ++ os_free(ext); ++ return ret; ++} ++ ++ ++/** ++ * wpa_driver_wext_set_key - Configure encryption key ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @priv: Private driver interface data ++ * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, ++ * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key. ++ * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for ++ * broadcast/default keys ++ * @key_idx: key index (0..3), usually 0 for unicast keys ++ * @set_tx: Configure this key as the default Tx key (only used when ++ * driver does not support separate unicast/individual key ++ * @seq: Sequence number/packet number, seq_len octets, the next ++ * packet number to be used for in replay protection; configured ++ * for Rx keys (in most cases, this is only used with broadcast ++ * keys and set to zero for unicast keys) ++ * @seq_len: Length of the seq, depends on the algorithm: ++ * TKIP: 6 octets, CCMP: 6 octets ++ * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, ++ * 8-byte Rx Mic Key ++ * @key_len: Length of the key buffer in octets (WEP: 5 or 13, ++ * TKIP: 32, CCMP: 16) ++ * Returns: 0 on success, -1 on failure ++ * ++ * This function uses SIOCSIWENCODEEXT by default, but tries to use ++ * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key. ++ */ ++int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg, ++ const u8 *addr, int key_idx, ++ int set_tx, const u8 *seq, size_t seq_len, ++ const u8 *key, size_t key_len) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ ++ wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu " ++ "key_len=%lu", ++ __FUNCTION__, alg, key_idx, set_tx, ++ (unsigned long) seq_len, (unsigned long) key_len); ++ ++ ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx, ++ seq, seq_len, key, key_len); ++ if (ret == 0) ++ return 0; ++ ++ if (ret == -2 && ++ (alg == WPA_ALG_NONE || alg == WPA_ALG_WEP)) { ++ wpa_printf(MSG_DEBUG, "Driver did not support " ++ "SIOCSIWENCODEEXT, trying SIOCSIWENCODE"); ++ ret = 0; ++ } else { ++ wpa_printf(MSG_DEBUG, "Driver did not support " ++ "SIOCSIWENCODEEXT"); ++ return ret; ++ } ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.encoding.flags = key_idx + 1; ++ iwr.u.encoding.flags |= IW_ENCODE_TEMP; ++ if (alg == WPA_ALG_NONE) ++ iwr.u.encoding.flags |= IW_ENCODE_DISABLED; ++ iwr.u.encoding.pointer = (caddr_t) key; ++ iwr.u.encoding.length = key_len; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODE]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ if (set_tx && alg != WPA_ALG_NONE) { ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.encoding.flags = key_idx + 1; ++ iwr.u.encoding.flags |= IW_ENCODE_TEMP; ++ iwr.u.encoding.pointer = (caddr_t) NULL; ++ iwr.u.encoding.length = 0; ++ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, ++ "ioctl[SIOCSIWENCODE] (set_tx): %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ } ++ ++ return ret; ++} ++ ++ ++static int wpa_driver_wext_set_countermeasures(void *priv, ++ int enabled) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); ++ return wpa_driver_wext_set_auth_param(drv, ++ IW_AUTH_TKIP_COUNTERMEASURES, ++ enabled); ++} ++ ++ ++static int wpa_driver_wext_set_drop_unencrypted(void *priv, ++ int enabled) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); ++ drv->use_crypt = enabled; ++ return wpa_driver_wext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED, ++ enabled); ++} ++ ++ ++static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv, ++ const u8 *addr, int cmd, int reason_code) ++{ ++ struct iwreq iwr; ++ struct iw_mlme mlme; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ os_memset(&mlme, 0, sizeof(mlme)); ++ mlme.cmd = cmd; ++ mlme.reason_code = reason_code; ++ mlme.addr.sa_family = ARPHRD_ETHER; ++ os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN); ++ iwr.u.data.pointer = (caddr_t) &mlme; ++ iwr.u.data.length = sizeof(mlme); ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMLME]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) ++{ ++ struct iwreq iwr; ++ const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; ++ u8 ssid[SSID_MAX_LEN]; ++ int i; ++ ++ /* ++ * Only force-disconnect when the card is in infrastructure mode, ++ * otherwise the driver might interpret the cleared BSSID and random ++ * SSID as an attempt to create a new ad-hoc network. ++ */ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWMODE]: %s", ++ strerror(errno)); ++ iwr.u.mode = IW_MODE_INFRA; ++ } ++ ++ if (iwr.u.mode == IW_MODE_INFRA) { ++ /* Clear the BSSID selection */ ++ if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: Failed to clear BSSID " ++ "selection on disconnect"); ++ } ++ ++ if (drv->cfg80211) { ++ /* ++ * cfg80211 supports SIOCSIWMLME commands, so there is ++ * no need for the random SSID hack, but clear the ++ * SSID. ++ */ ++ if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: Failed to clear " ++ "SSID on disconnect"); ++ } ++ return; ++ } ++ ++ /* ++ * Set a random SSID to make sure the driver will not be trying ++ * to associate with something even if it does not understand ++ * SIOCSIWMLME commands (or tries to associate automatically ++ * after deauth/disassoc). ++ */ ++ for (i = 0; i < SSID_MAX_LEN; i++) ++ ssid[i] = rand() & 0xFF; ++ if (wpa_driver_wext_set_ssid(drv, ssid, SSID_MAX_LEN) < 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus " ++ "SSID to disconnect"); ++ } ++ } ++} ++ ++ ++static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr, ++ int reason_code) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ int ret; ++ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); ++ ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code); ++ wpa_driver_wext_disconnect(drv); ++ return ret; ++} ++ ++ ++static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie, ++ size_t ie_len) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.data.pointer = (caddr_t) ie; ++ iwr.u.data.length = ie_len; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWGENIE]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++int wpa_driver_wext_cipher2wext(int cipher) ++{ ++ switch (cipher) { ++ case WPA_CIPHER_NONE: ++ return IW_AUTH_CIPHER_NONE; ++ case WPA_CIPHER_WEP40: ++ return IW_AUTH_CIPHER_WEP40; ++ case WPA_CIPHER_TKIP: ++ return IW_AUTH_CIPHER_TKIP; ++ case WPA_CIPHER_CCMP: ++ return IW_AUTH_CIPHER_CCMP; ++ case WPA_CIPHER_WEP104: ++ return IW_AUTH_CIPHER_WEP104; ++ default: ++ return 0; ++ } ++} ++ ++ ++int wpa_driver_wext_keymgmt2wext(int keymgmt) ++{ ++ switch (keymgmt) { ++ case WPA_KEY_MGMT_IEEE8021X: ++ case WPA_KEY_MGMT_IEEE8021X_NO_WPA: ++ return IW_AUTH_KEY_MGMT_802_1X; ++ case WPA_KEY_MGMT_PSK: ++ return IW_AUTH_KEY_MGMT_PSK; ++ default: ++ return 0; ++ } ++} ++ ++ ++static int ++wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv, ++ struct wpa_driver_associate_params *params) ++{ ++ struct iwreq iwr; ++ int ret = 0; ++ ++ wpa_printf(MSG_DEBUG, "WEXT: Driver did not support " ++ "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE"); ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ /* Just changing mode, not actual keys */ ++ iwr.u.encoding.flags = 0; ++ iwr.u.encoding.pointer = (caddr_t) NULL; ++ iwr.u.encoding.length = 0; ++ ++ /* ++ * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two ++ * different things. Here they are used to indicate Open System vs. ++ * Shared Key authentication algorithm. However, some drivers may use ++ * them to select between open/restricted WEP encrypted (open = allow ++ * both unencrypted and encrypted frames; restricted = only allow ++ * encrypted frames). ++ */ ++ ++ if (!drv->use_crypt) { ++ iwr.u.encoding.flags |= IW_ENCODE_DISABLED; ++ } else { ++ if (params->auth_alg & WPA_AUTH_ALG_OPEN) ++ iwr.u.encoding.flags |= IW_ENCODE_OPEN; ++ if (params->auth_alg & WPA_AUTH_ALG_SHARED) ++ iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED; ++ } ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODE]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++int wpa_driver_wext_associate(void *priv, ++ struct wpa_driver_associate_params *params) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ int ret = 0; ++ int allow_unencrypted_eapol; ++ int value; ++ ++ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); ++ ++ if (drv->cfg80211) { ++ /* ++ * Stop cfg80211 from trying to associate before we are done ++ * with all parameters. ++ */ ++ if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) { ++ wpa_printf(MSG_DEBUG, ++ "WEXT: Failed to clear SSID to stop pending cfg80211 association attempts (if any)"); ++ /* continue anyway */ ++ } ++ } ++ ++ if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted) ++ < 0) ++ ret = -1; ++ if (wpa_driver_wext_set_auth_alg(drv, params->auth_alg) < 0) ++ ret = -1; ++ if (wpa_driver_wext_set_mode(drv, params->mode) < 0) ++ ret = -1; ++ ++ /* ++ * If the driver did not support SIOCSIWAUTH, fallback to ++ * SIOCSIWENCODE here. ++ */ ++ if (drv->auth_alg_fallback && ++ wpa_driver_wext_auth_alg_fallback(drv, params) < 0) ++ ret = -1; ++ ++ if (!params->bssid && ++ wpa_driver_wext_set_bssid(drv, NULL) < 0) ++ ret = -1; ++ ++ /* TODO: should consider getting wpa version and cipher/key_mgmt suites ++ * from configuration, not from here, where only the selected suite is ++ * available */ ++ if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len) ++ < 0) ++ ret = -1; ++ if (params->wpa_proto & WPA_PROTO_RSN) ++ value = IW_AUTH_WPA_VERSION_WPA2; ++ else if (params->wpa_proto & WPA_PROTO_WPA) ++ value = IW_AUTH_WPA_VERSION_WPA; ++ else ++ value = IW_AUTH_WPA_VERSION_DISABLED; ++ if (wpa_driver_wext_set_auth_param(drv, ++ IW_AUTH_WPA_VERSION, value) < 0) ++ ret = -1; ++ value = wpa_driver_wext_cipher2wext(params->pairwise_suite); ++ if (wpa_driver_wext_set_auth_param(drv, ++ IW_AUTH_CIPHER_PAIRWISE, value) < 0) ++ ret = -1; ++ value = wpa_driver_wext_cipher2wext(params->group_suite); ++ if (wpa_driver_wext_set_auth_param(drv, ++ IW_AUTH_CIPHER_GROUP, value) < 0) ++ ret = -1; ++ value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite); ++ if (wpa_driver_wext_set_auth_param(drv, ++ IW_AUTH_KEY_MGMT, value) < 0) ++ ret = -1; ++ value = params->key_mgmt_suite != WPA_KEY_MGMT_NONE || ++ params->pairwise_suite != WPA_CIPHER_NONE || ++ params->group_suite != WPA_CIPHER_NONE || ++ (params->wpa_proto & (WPA_PROTO_RSN | WPA_PROTO_WPA)); ++ if (wpa_driver_wext_set_auth_param(drv, ++ IW_AUTH_PRIVACY_INVOKED, value) < 0) ++ ret = -1; ++ ++ /* Allow unencrypted EAPOL messages even if pairwise keys are set when ++ * not using WPA. IEEE 802.1X specifies that these frames are not ++ * encrypted, but WPA encrypts them when pairwise keys are in use. */ ++ if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || ++ params->key_mgmt_suite == WPA_KEY_MGMT_PSK) ++ allow_unencrypted_eapol = 0; ++ else ++ allow_unencrypted_eapol = 1; ++ ++ if (wpa_driver_wext_set_psk(drv, params->psk) < 0) ++ ret = -1; ++ if (wpa_driver_wext_set_auth_param(drv, ++ IW_AUTH_RX_UNENCRYPTED_EAPOL, ++ allow_unencrypted_eapol) < 0) ++ ret = -1; ++#ifdef CONFIG_IEEE80211W ++ switch (params->mgmt_frame_protection) { ++ case NO_MGMT_FRAME_PROTECTION: ++ value = IW_AUTH_MFP_DISABLED; ++ break; ++ case MGMT_FRAME_PROTECTION_OPTIONAL: ++ value = IW_AUTH_MFP_OPTIONAL; ++ break; ++ case MGMT_FRAME_PROTECTION_REQUIRED: ++ value = IW_AUTH_MFP_REQUIRED; ++ break; ++ }; ++ if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0) ++ ret = -1; ++#endif /* CONFIG_IEEE80211W */ ++ if (params->freq.freq && ++ wpa_driver_wext_set_freq(drv, params->freq.freq) < 0) ++ ret = -1; ++ if (!drv->cfg80211 && ++ wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0) ++ ret = -1; ++ if (params->bssid && ++ wpa_driver_wext_set_bssid(drv, params->bssid) < 0) ++ ret = -1; ++ if (drv->cfg80211 && ++ wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0) ++ ret = -1; ++ ++ return ret; ++} ++ ++ ++static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ int algs = 0, res; ++ ++ if (auth_alg & WPA_AUTH_ALG_OPEN) ++ algs |= IW_AUTH_ALG_OPEN_SYSTEM; ++ if (auth_alg & WPA_AUTH_ALG_SHARED) ++ algs |= IW_AUTH_ALG_SHARED_KEY; ++ if (auth_alg & WPA_AUTH_ALG_LEAP) ++ algs |= IW_AUTH_ALG_LEAP; ++ if (algs == 0) { ++ /* at least one algorithm should be set */ ++ algs = IW_AUTH_ALG_OPEN_SYSTEM; ++ } ++ ++ res = wpa_driver_wext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG, ++ algs); ++ drv->auth_alg_fallback = res == -2; ++ return res; ++} ++ ++ ++/** ++ * wpa_driver_wext_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS ++ * Returns: 0 on success, -1 on failure ++ */ ++int wpa_driver_wext_set_mode(void *priv, int mode) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = -1; ++ unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.mode = new_mode; ++ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) { ++ ret = 0; ++ goto done; ++ } ++ ++ if (errno != EBUSY) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMODE]: %s", ++ strerror(errno)); ++ goto done; ++ } ++ ++ /* mac80211 doesn't allow mode changes while the device is up, so if ++ * the device isn't in the mode we're about to change to, take device ++ * down, try to set the mode again, and bring it back up. ++ */ ++ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWMODE]: %s", ++ strerror(errno)); ++ goto done; ++ } ++ ++ if (iwr.u.mode == new_mode) { ++ ret = 0; ++ goto done; ++ } ++ ++ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) { ++ /* Try to set the mode again while the interface is down */ ++ iwr.u.mode = new_mode; ++ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMODE]: %s", ++ strerror(errno)); ++ else ++ ret = 0; ++ ++ (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1); ++ } ++ ++done: ++ return ret; ++} ++ ++ ++static int wpa_driver_wext_pmksa(struct wpa_driver_wext_data *drv, ++ u32 cmd, const u8 *bssid, const u8 *pmkid) ++{ ++ struct iwreq iwr; ++ struct iw_pmksa pmksa; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ os_memset(&pmksa, 0, sizeof(pmksa)); ++ pmksa.cmd = cmd; ++ pmksa.bssid.sa_family = ARPHRD_ETHER; ++ if (bssid) ++ os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN); ++ if (pmkid) ++ os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN); ++ iwr.u.data.pointer = (caddr_t) &pmksa; ++ iwr.u.data.length = sizeof(pmksa); ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) { ++ if (errno != EOPNOTSUPP) ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPMKSA]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++static int wpa_driver_wext_add_pmkid(void *priv, const u8 *bssid, ++ const u8 *pmkid) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ return wpa_driver_wext_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid); ++} ++ ++ ++static int wpa_driver_wext_remove_pmkid(void *priv, const u8 *bssid, ++ const u8 *pmkid) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ return wpa_driver_wext_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid); ++} ++ ++ ++static int wpa_driver_wext_flush_pmkid(void *priv) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ return wpa_driver_wext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL); ++} ++ ++ ++int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ if (!drv->has_capability) ++ return -1; ++ os_memcpy(capa, &drv->capa, sizeof(*capa)); ++ return 0; ++} ++ ++ ++int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv, ++ const char *ifname) ++{ ++ if (ifname == NULL) { ++ drv->ifindex2 = -1; ++ return 0; ++ } ++ ++ drv->ifindex2 = if_nametoindex(ifname); ++ if (drv->ifindex2 <= 0) ++ return -1; ++ ++ wpa_printf(MSG_DEBUG, "Added alternative ifindex %d (%s) for " ++ "wireless events", drv->ifindex2, ifname); ++ ++ return 0; ++} ++ ++ ++int wpa_driver_wext_set_operstate(void *priv, int state) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ ++ wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", ++ __func__, drv->operstate, state, state ? "UP" : "DORMANT"); ++ drv->operstate = state; ++ return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1, ++ state ? IF_OPER_UP : IF_OPER_DORMANT); ++} ++ ++ ++int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv) ++{ ++ return drv->we_version_compiled; ++} ++ ++ ++static const char * wext_get_radio_name(void *priv) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ return drv->phyname; ++} ++ ++ ++static int wpa_driver_wext_signal_poll(void *priv, struct wpa_signal_info *si) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iw_statistics stats; ++ struct iwreq iwr; ++ ++ os_memset(si, 0, sizeof(*si)); ++ si->current_signal = -9999; ++ si->current_noise = 9999; ++ si->chanwidth = CHAN_WIDTH_UNKNOWN; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.data.pointer = (caddr_t) &stats; ++ iwr.u.data.length = sizeof(stats); ++ iwr.u.data.flags = 1; ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "WEXT: SIOCGIWSTATS: %s", ++ strerror(errno)); ++ return -1; ++ } ++ ++ si->current_signal = stats.qual.level - ++ ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0); ++ si->current_noise = stats.qual.noise - ++ ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0); ++ return 0; ++} ++ ++ ++static int wpa_driver_wext_status(void *priv, char *buf, size_t buflen) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ int res; ++ char *pos, *end; ++ unsigned char addr[ETH_ALEN]; ++ ++ pos = buf; ++ end = buf + buflen; ++ ++ if (linux_get_ifhwaddr(drv->ioctl_sock, drv->ifname, addr)) ++ return -1; ++ ++ res = os_snprintf(pos, end - pos, ++ "ifindex=%d\n" ++ "ifname=%s\n" ++ "addr=" MACSTR "\n", ++ drv->ifindex, ++ drv->ifname, ++ MAC2STR(addr)); ++ if (os_snprintf_error(end - pos, res)) ++ return pos - buf; ++ pos += res; ++ ++ return pos - buf; ++} ++ ++const struct wpa_driver_ops wpa_driver_wext_ops = { ++ .name = "wext", ++ .desc = "Linux wireless extensions (generic)", ++ .get_bssid = wpa_driver_wext_get_bssid, ++ .get_ssid = wpa_driver_wext_get_ssid, ++ .set_key = wpa_driver_wext_set_key, ++ .set_countermeasures = wpa_driver_wext_set_countermeasures, ++ .scan2 = wpa_driver_wext_scan, ++ .get_scan_results2 = wpa_driver_wext_get_scan_results, ++ .deauthenticate = wpa_driver_wext_deauthenticate, ++ .associate = wpa_driver_wext_associate, ++ .init = wpa_driver_wext_init, ++ .deinit = wpa_driver_wext_deinit, ++ .add_pmkid = wpa_driver_wext_add_pmkid, ++ .remove_pmkid = wpa_driver_wext_remove_pmkid, ++ .flush_pmkid = wpa_driver_wext_flush_pmkid, ++ .get_capa = wpa_driver_wext_get_capa, ++ .set_operstate = wpa_driver_wext_set_operstate, ++ .get_radio_name = wext_get_radio_name, ++ .signal_poll = wpa_driver_wext_signal_poll, ++ .status = wpa_driver_wext_status, ++}; diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c index a98af9a..d7d9c5b 100644 --- a/src/drivers/drivers.c @@ -3468,8 +9883,8 @@ index a98af9a..d7d9c5b 100644 +#ifdef CONFIG_DRIVER_RTW +extern struct wpa_driver_ops wpa_driver_rtw_ops; /* driver_rtw.c */ +#endif /* CONFIG_DRIVER_RTW */ - - + + const struct wpa_driver_ops *const wpa_drivers[] = @@ -82,5 +85,8 @@ const struct wpa_driver_ops *const wpa_drivers[] = #ifdef CONFIG_DRIVER_NONE @@ -3480,6 +9895,98 @@ index a98af9a..d7d9c5b 100644 +#endif /* CONFIG_DRIVER_RTW */ NULL }; +diff --git a/src/drivers/drivers.c.orig b/src/drivers/drivers.c.orig +new file mode 100644 +index 0000000..a98af9a +--- /dev/null ++++ b/src/drivers/drivers.c.orig +@@ -0,0 +1,86 @@ ++/* ++ * Driver interface list ++ * Copyright (c) 2004-2005, Jouni Malinen ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ */ ++ ++#include "utils/includes.h" ++#include "utils/common.h" ++#include "driver.h" ++ ++#ifdef CONFIG_DRIVER_WEXT ++extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */ ++#endif /* CONFIG_DRIVER_WEXT */ ++#ifdef CONFIG_DRIVER_NL80211 ++extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */ ++#endif /* CONFIG_DRIVER_NL80211 */ ++#ifdef CONFIG_DRIVER_HOSTAP ++extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */ ++#endif /* CONFIG_DRIVER_HOSTAP */ ++#ifdef CONFIG_DRIVER_BSD ++extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */ ++#endif /* CONFIG_DRIVER_BSD */ ++#ifdef CONFIG_DRIVER_OPENBSD ++extern struct wpa_driver_ops wpa_driver_openbsd_ops; /* driver_openbsd.c */ ++#endif /* CONFIG_DRIVER_OPENBSD */ ++#ifdef CONFIG_DRIVER_NDIS ++extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */ ++#endif /* CONFIG_DRIVER_NDIS */ ++#ifdef CONFIG_DRIVER_WIRED ++extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */ ++#endif /* CONFIG_DRIVER_WIRED */ ++#ifdef CONFIG_DRIVER_MACSEC_QCA ++ /* driver_macsec_qca.c */ ++extern struct wpa_driver_ops wpa_driver_macsec_qca_ops; ++#endif /* CONFIG_DRIVER_MACSEC_QCA */ ++#ifdef CONFIG_DRIVER_ROBOSWITCH ++/* driver_roboswitch.c */ ++extern struct wpa_driver_ops wpa_driver_roboswitch_ops; ++#endif /* CONFIG_DRIVER_ROBOSWITCH */ ++#ifdef CONFIG_DRIVER_ATHEROS ++extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */ ++#endif /* CONFIG_DRIVER_ATHEROS */ ++#ifdef CONFIG_DRIVER_NONE ++extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */ ++#endif /* CONFIG_DRIVER_NONE */ ++ ++ ++const struct wpa_driver_ops *const wpa_drivers[] = ++{ ++#ifdef CONFIG_DRIVER_NL80211 ++ &wpa_driver_nl80211_ops, ++#endif /* CONFIG_DRIVER_NL80211 */ ++#ifdef CONFIG_DRIVER_WEXT ++ &wpa_driver_wext_ops, ++#endif /* CONFIG_DRIVER_WEXT */ ++#ifdef CONFIG_DRIVER_HOSTAP ++ &wpa_driver_hostap_ops, ++#endif /* CONFIG_DRIVER_HOSTAP */ ++#ifdef CONFIG_DRIVER_BSD ++ &wpa_driver_bsd_ops, ++#endif /* CONFIG_DRIVER_BSD */ ++#ifdef CONFIG_DRIVER_OPENBSD ++ &wpa_driver_openbsd_ops, ++#endif /* CONFIG_DRIVER_OPENBSD */ ++#ifdef CONFIG_DRIVER_NDIS ++ &wpa_driver_ndis_ops, ++#endif /* CONFIG_DRIVER_NDIS */ ++#ifdef CONFIG_DRIVER_WIRED ++ &wpa_driver_wired_ops, ++#endif /* CONFIG_DRIVER_WIRED */ ++#ifdef CONFIG_DRIVER_MACSEC_QCA ++ &wpa_driver_macsec_qca_ops, ++#endif /* CONFIG_DRIVER_MACSEC_QCA */ ++#ifdef CONFIG_DRIVER_ROBOSWITCH ++ &wpa_driver_roboswitch_ops, ++#endif /* CONFIG_DRIVER_ROBOSWITCH */ ++#ifdef CONFIG_DRIVER_ATHEROS ++ &wpa_driver_atheros_ops, ++#endif /* CONFIG_DRIVER_ATHEROS */ ++#ifdef CONFIG_DRIVER_NONE ++ &wpa_driver_none_ops, ++#endif /* CONFIG_DRIVER_NONE */ ++ NULL ++}; diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak index 3dd43c7..3e44fcb 100644 --- a/src/drivers/drivers.mak @@ -3493,12 +10000,12 @@ index 3dd43c7..3e44fcb 100644 +NEED_AP_MLME=y +endif endif - + ifdef CONFIG_DRIVER_OPENBSD @@ -84,6 +88,17 @@ DRV_CFLAGS += -DCONFIG_DRIVER_OPENBSD DRV_OBJS += ../src/drivers/driver_openbsd.o endif - + +ifdef CONFIG_DRIVER_RTW +#CFLAGS += -DCONFIG_DRIVER_RTL +#OBJS += driver_rtl.o @@ -3513,6 +10020,212 @@ index 3dd43c7..3e44fcb 100644 ifdef CONFIG_DRIVER_NONE DRV_CFLAGS += -DCONFIG_DRIVER_NONE DRV_OBJS += ../src/drivers/driver_none.o +diff --git a/src/drivers/drivers.mak.orig b/src/drivers/drivers.mak.orig +new file mode 100644 +index 0000000..3dd43c7 +--- /dev/null ++++ b/src/drivers/drivers.mak.orig +@@ -0,0 +1,200 @@ ++##### CLEAR VARS ++ ++DRV_CFLAGS = ++DRV_WPA_CFLAGS = ++DRV_AP_CFLAGS = ++DRV_OBJS = ++DRV_WPA_OBJS = ++DRV_AP_OBJS = ++DRV_LIBS = ++DRV_WPA_LIBS = ++DRV_AP_LIBS = ++ ++##### COMMON DRIVERS ++ ++ifdef CONFIG_DRIVER_WIRED ++DRV_CFLAGS += -DCONFIG_DRIVER_WIRED ++DRV_OBJS += ../src/drivers/driver_wired.o ++endif ++ ++ifdef CONFIG_DRIVER_MACSEC_QCA ++DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_QCA ++DRV_OBJS += ../src/drivers/driver_macsec_qca.o ++endif ++ ++ifdef CONFIG_DRIVER_NL80211 ++DRV_CFLAGS += -DCONFIG_DRIVER_NL80211 ++DRV_OBJS += ../src/drivers/driver_nl80211.o ++DRV_OBJS += ../src/drivers/driver_nl80211_capa.o ++DRV_OBJS += ../src/drivers/driver_nl80211_event.o ++DRV_OBJS += ../src/drivers/driver_nl80211_monitor.o ++DRV_OBJS += ../src/drivers/driver_nl80211_scan.o ++DRV_OBJS += ../src/utils/radiotap.o ++NEED_SME=y ++NEED_AP_MLME=y ++NEED_NETLINK=y ++NEED_LINUX_IOCTL=y ++NEED_RFKILL=y ++ ++ifdef CONFIG_LIBNL32 ++ DRV_LIBS += -lnl-3 ++ DRV_LIBS += -lnl-genl-3 ++ DRV_CFLAGS += -DCONFIG_LIBNL20 ++ ifdef LIBNL_INC ++ DRV_CFLAGS += -I$(LIBNL_INC) ++ else ++ PKG_CONFIG ?= pkg-config ++ DRV_CFLAGS += $(shell $(PKG_CONFIG) --cflags libnl-3.0) ++ endif ++ifdef CONFIG_LIBNL3_ROUTE ++ DRV_LIBS += -lnl-route-3 ++ DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE ++endif ++else ++ ifdef CONFIG_LIBNL_TINY ++ DRV_LIBS += -lnl-tiny ++ else ++ ifndef CONFIG_OSX ++ DRV_LIBS += -lnl ++ endif ++ endif ++ ++ ifdef CONFIG_LIBNL20 ++ DRV_LIBS += -lnl-genl ++ DRV_CFLAGS += -DCONFIG_LIBNL20 ++ endif ++endif ++endif ++ ++ifdef CONFIG_DRIVER_BSD ++ifndef CONFIG_L2_PACKET ++CONFIG_L2_PACKET=freebsd ++endif ++DRV_CFLAGS += -DCONFIG_DRIVER_BSD ++DRV_OBJS += ../src/drivers/driver_bsd.o ++CONFIG_L2_FREEBSD=y ++CONFIG_DNET_PCAP=y ++endif ++ ++ifdef CONFIG_DRIVER_OPENBSD ++ifndef CONFIG_L2_PACKET ++CONFIG_L2_PACKET=freebsd ++endif ++DRV_CFLAGS += -DCONFIG_DRIVER_OPENBSD ++DRV_OBJS += ../src/drivers/driver_openbsd.o ++endif ++ ++ifdef CONFIG_DRIVER_NONE ++DRV_CFLAGS += -DCONFIG_DRIVER_NONE ++DRV_OBJS += ../src/drivers/driver_none.o ++endif ++ ++##### PURE AP DRIVERS ++ ++ifdef CONFIG_DRIVER_HOSTAP ++DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP ++DRV_AP_OBJS += ../src/drivers/driver_hostap.o ++CONFIG_WIRELESS_EXTENSION=y ++NEED_AP_MLME=y ++NEED_NETLINK=y ++NEED_LINUX_IOCTL=y ++endif ++ ++ifdef CONFIG_DRIVER_ATHEROS ++DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS ++DRV_AP_OBJS += ../src/drivers/driver_atheros.o ++CONFIG_L2_PACKET=linux ++NEED_NETLINK=y ++NEED_LINUX_IOCTL=y ++ifdef ATH_GCM_SUPPORT ++CFLAGS += -DATH_GCM_SUPPORT ++endif ++endif ++ ++##### PURE CLIENT DRIVERS ++ ++ifdef CONFIG_DRIVER_WEXT ++DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT ++CONFIG_WIRELESS_EXTENSION=y ++NEED_NETLINK=y ++NEED_LINUX_IOCTL=y ++NEED_RFKILL=y ++endif ++ ++ifdef CONFIG_DRIVER_NDIS ++DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS ++DRV_WPA_OBJS += ../src/drivers/driver_ndis.o ++ifdef CONFIG_NDIS_EVENTS_INTEGRATED ++DRV_WPA_OBJS += ../src/drivers/driver_ndis_.o ++endif ++ifndef CONFIG_L2_PACKET ++CONFIG_L2_PACKET=pcap ++endif ++CONFIG_WINPCAP=y ++ifdef CONFIG_USE_NDISUIO ++DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO ++endif ++endif ++ ++ifdef CONFIG_DRIVER_ROBOSWITCH ++DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH ++DRV_WPA_OBJS += ../src/drivers/driver_roboswitch.o ++endif ++ ++ifdef CONFIG_WIRELESS_EXTENSION ++DRV_WPA_CFLAGS += -DCONFIG_WIRELESS_EXTENSION ++DRV_WPA_OBJS += ../src/drivers/driver_wext.o ++NEED_RFKILL=y ++endif ++ ++ifdef NEED_NETLINK ++DRV_OBJS += ../src/drivers/netlink.o ++endif ++ ++ifdef NEED_LINUX_IOCTL ++DRV_OBJS += ../src/drivers/linux_ioctl.o ++endif ++ ++ifdef NEED_RFKILL ++DRV_OBJS += ../src/drivers/rfkill.o ++endif ++ ++ifdef CONFIG_VLAN_NETLINK ++ifdef CONFIG_FULL_DYNAMIC_VLAN ++ifdef CONFIG_LIBNL32 ++ DRV_LIBS += -lnl-3 ++ DRV_LIBS += -lnl-genl-3 ++ DRV_LIBS += -lnl-route-3 ++ DRV_CFLAGS += -DCONFIG_LIBNL20 ++else ++ ifdef CONFIG_LIBNL_TINY ++ DRV_LIBS += -lnl-tiny ++ else ++ DRV_LIBS += -lnl ++ endif ++ ++ ifdef CONFIG_LIBNL20 ++ DRV_LIBS += -lnl-genl ++ DRV_LIBS += -lnl-route ++ DRV_CFLAGS += -DCONFIG_LIBNL20 ++ endif ++endif ++endif ++endif ++ ++##### COMMON VARS ++DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS) ++DRV_WPA_CFLAGS += $(DRV_CFLAGS) ++DRV_AP_CFLAGS += $(DRV_CFLAGS) ++ ++DRV_BOTH_LIBS := $(DRV_LIBS) $(DRV_WPA_LIBS) $(DRV_AP_LIBS) ++DRV_WPA_LIBS += $(DRV_LIBS) ++DRV_AP_LIBS += $(DRV_LIBS) ++ ++DRV_BOTH_OBJS := $(DRV_OBJS) $(DRV_WPA_OBJS) $(DRV_AP_OBJS) ++DRV_WPA_OBJS += $(DRV_OBJS) ++DRV_AP_OBJS += $(DRV_OBJS) ++ ++DRV_BOTH_LDFLAGS := $(DRV_LDFLAGS) $(DRV_WPA_LDFLAGS) $(DRV_AP_LDFLAGS) ++DRV_WPA_LDFLAGS += $(DRV_LDFLAGS) ++DRV_AP_LDFLAGS += $(DRV_LDFLAGS) diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c index 7ac99c7..1f7697c 100644 --- a/src/eap_peer/eap_wsc.c @@ -3531,6 +10244,610 @@ index 7ac99c7..1f7697c 100644 } return r; } +diff --git a/src/eap_peer/eap_wsc.c.orig b/src/eap_peer/eap_wsc.c.orig +new file mode 100644 +index 0000000..7ac99c7 +--- /dev/null ++++ b/src/eap_peer/eap_wsc.c.orig +@@ -0,0 +1,598 @@ ++/* ++ * EAP-WSC peer for Wi-Fi Protected Setup ++ * Copyright (c) 2007-2009, 2012, Jouni Malinen ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ */ ++ ++#include "includes.h" ++ ++#include "common.h" ++#include "uuid.h" ++#include "eap_i.h" ++#include "eap_common/eap_wsc_common.h" ++#include "wps/wps.h" ++#include "wps/wps_defs.h" ++ ++ ++struct eap_wsc_data { ++ enum { WAIT_START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; ++ int registrar; ++ struct wpabuf *in_buf; ++ struct wpabuf *out_buf; ++ enum wsc_op_code in_op_code, out_op_code; ++ size_t out_used; ++ size_t fragment_size; ++ struct wps_data *wps; ++ struct wps_context *wps_ctx; ++}; ++ ++ ++static const char * eap_wsc_state_txt(int state) ++{ ++ switch (state) { ++ case WAIT_START: ++ return "WAIT_START"; ++ case MESG: ++ return "MESG"; ++ case FRAG_ACK: ++ return "FRAG_ACK"; ++ case WAIT_FRAG_ACK: ++ return "WAIT_FRAG_ACK"; ++ case DONE: ++ return "DONE"; ++ case FAIL: ++ return "FAIL"; ++ default: ++ return "?"; ++ } ++} ++ ++ ++static void eap_wsc_state(struct eap_wsc_data *data, int state) ++{ ++ wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s", ++ eap_wsc_state_txt(data->state), ++ eap_wsc_state_txt(state)); ++ data->state = state; ++} ++ ++ ++static int eap_wsc_new_ap_settings(struct wps_credential *cred, ++ const char *params) ++{ ++ const char *pos, *end; ++ size_t len; ++ ++ os_memset(cred, 0, sizeof(*cred)); ++ ++ pos = os_strstr(params, "new_ssid="); ++ if (pos == NULL) ++ return 0; ++ pos += 9; ++ end = os_strchr(pos, ' '); ++ if (end == NULL) ++ len = os_strlen(pos); ++ else ++ len = end - pos; ++ if ((len & 1) || len > 2 * sizeof(cred->ssid) || ++ hexstr2bin(pos, cred->ssid, len / 2)) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_ssid"); ++ return -1; ++ } ++ cred->ssid_len = len / 2; ++ ++ pos = os_strstr(params, "new_auth="); ++ if (pos == NULL) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_auth"); ++ return -1; ++ } ++ if (os_strncmp(pos + 9, "OPEN", 4) == 0) ++ cred->auth_type = WPS_AUTH_OPEN; ++ else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0) ++ cred->auth_type = WPS_AUTH_WPAPSK; ++ else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0) ++ cred->auth_type = WPS_AUTH_WPA2PSK; ++ else { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_auth"); ++ return -1; ++ } ++ ++ pos = os_strstr(params, "new_encr="); ++ if (pos == NULL) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_encr"); ++ return -1; ++ } ++ if (os_strncmp(pos + 9, "NONE", 4) == 0) ++ cred->encr_type = WPS_ENCR_NONE; ++#ifdef CONFIG_TESTING_OPTIONS ++ else if (os_strncmp(pos + 9, "WEP", 3) == 0) ++ cred->encr_type = WPS_ENCR_WEP; ++#endif /* CONFIG_TESTING_OPTIONS */ ++ else if (os_strncmp(pos + 9, "TKIP", 4) == 0) ++ cred->encr_type = WPS_ENCR_TKIP; ++ else if (os_strncmp(pos + 9, "CCMP", 4) == 0) ++ cred->encr_type = WPS_ENCR_AES; ++ else { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_encr"); ++ return -1; ++ } ++ ++ pos = os_strstr(params, "new_key="); ++ if (pos == NULL) ++ return 0; ++ pos += 8; ++ end = os_strchr(pos, ' '); ++ if (end == NULL) ++ len = os_strlen(pos); ++ else ++ len = end - pos; ++ if ((len & 1) || len > 2 * sizeof(cred->key) || ++ hexstr2bin(pos, cred->key, len / 2)) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_key"); ++ return -1; ++ } ++ cred->key_len = len / 2; ++ ++ return 1; ++} ++ ++ ++static void * eap_wsc_init(struct eap_sm *sm) ++{ ++ struct eap_wsc_data *data; ++ const u8 *identity; ++ size_t identity_len; ++ int registrar; ++ struct wps_config cfg; ++ const char *pos, *end; ++ const char *phase1; ++ struct wps_context *wps; ++ struct wps_credential new_ap_settings; ++ int res; ++ int nfc = 0; ++ u8 pkhash[WPS_OOB_PUBKEY_HASH_LEN]; ++ ++ wps = sm->wps; ++ if (wps == NULL) { ++ wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available"); ++ return NULL; ++ } ++ ++ identity = eap_get_config_identity(sm, &identity_len); ++ ++ if (identity && identity_len == WSC_ID_REGISTRAR_LEN && ++ os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) ++ registrar = 1; /* Supplicant is Registrar */ ++ else if (identity && identity_len == WSC_ID_ENROLLEE_LEN && ++ os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) ++ registrar = 0; /* Supplicant is Enrollee */ ++ else { ++ wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity", ++ identity, identity_len); ++ return NULL; ++ } ++ ++ data = os_zalloc(sizeof(*data)); ++ if (data == NULL) ++ return NULL; ++ data->state = registrar ? MESG : WAIT_START; ++ data->registrar = registrar; ++ data->wps_ctx = wps; ++ ++ os_memset(&cfg, 0, sizeof(cfg)); ++ cfg.wps = wps; ++ cfg.registrar = registrar; ++ ++ phase1 = eap_get_config_phase1(sm); ++ if (phase1 == NULL) { ++ wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not " ++ "set"); ++ os_free(data); ++ return NULL; ++ } ++ ++ pos = os_strstr(phase1, "pin="); ++ if (pos) { ++ pos += 4; ++ cfg.pin = (const u8 *) pos; ++ while (*pos != '\0' && *pos != ' ') ++ pos++; ++ cfg.pin_len = pos - (const char *) cfg.pin; ++ if (cfg.pin_len == 6 && ++ os_strncmp((const char *) cfg.pin, "nfc-pw", 6) == 0) { ++ cfg.pin = NULL; ++ cfg.pin_len = 0; ++ nfc = 1; ++ } ++ } else { ++ pos = os_strstr(phase1, "pbc=1"); ++ if (pos) ++ cfg.pbc = 1; ++ } ++ ++ pos = os_strstr(phase1, "dev_pw_id="); ++ if (pos) { ++ u16 id = atoi(pos + 10); ++ if (id == DEV_PW_NFC_CONNECTION_HANDOVER) ++ nfc = 1; ++ if (cfg.pin || id == DEV_PW_NFC_CONNECTION_HANDOVER) ++ cfg.dev_pw_id = id; ++ } ++ ++ if (cfg.pin == NULL && !cfg.pbc && !nfc) { ++ wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 " ++ "configuration data"); ++ os_free(data); ++ return NULL; ++ } ++ ++ pos = os_strstr(phase1, " pkhash="); ++ if (pos) { ++ size_t len; ++ pos += 8; ++ end = os_strchr(pos, ' '); ++ if (end) ++ len = end - pos; ++ else ++ len = os_strlen(pos); ++ if (len != 2 * WPS_OOB_PUBKEY_HASH_LEN || ++ hexstr2bin(pos, pkhash, WPS_OOB_PUBKEY_HASH_LEN)) { ++ wpa_printf(MSG_INFO, "EAP-WSC: Invalid pkhash"); ++ os_free(data); ++ return NULL; ++ } ++ cfg.peer_pubkey_hash = pkhash; ++ } ++ ++ res = eap_wsc_new_ap_settings(&new_ap_settings, phase1); ++ if (res < 0) { ++ os_free(data); ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to parse new AP " ++ "settings"); ++ return NULL; ++ } ++ if (res == 1) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for " ++ "WPS"); ++ cfg.new_ap_settings = &new_ap_settings; ++ } ++ ++ data->wps = wps_init(&cfg); ++ if (data->wps == NULL) { ++ os_free(data); ++ wpa_printf(MSG_DEBUG, "EAP-WSC: wps_init failed"); ++ return NULL; ++ } ++ res = eap_get_config_fragment_size(sm); ++ if (res > 0) ++ data->fragment_size = res; ++ else ++ data->fragment_size = WSC_FRAGMENT_SIZE; ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment size limit %u", ++ (unsigned int) data->fragment_size); ++ ++ if (registrar && cfg.pin) { ++ wps_registrar_add_pin(data->wps_ctx->registrar, NULL, NULL, ++ cfg.pin, cfg.pin_len, 0); ++ } ++ ++ /* Use reduced client timeout for WPS to avoid long wait */ ++ if (sm->ClientTimeout > 30) ++ sm->ClientTimeout = 30; ++ ++ return data; ++} ++ ++ ++static void eap_wsc_deinit(struct eap_sm *sm, void *priv) ++{ ++ struct eap_wsc_data *data = priv; ++ wpabuf_free(data->in_buf); ++ wpabuf_free(data->out_buf); ++ wps_deinit(data->wps); ++ os_free(data->wps_ctx->network_key); ++ data->wps_ctx->network_key = NULL; ++ os_free(data); ++} ++ ++ ++static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, ++ struct eap_method_ret *ret, u8 id) ++{ ++ struct wpabuf *resp; ++ u8 flags; ++ size_t send_len, plen; ++ ++ ret->ignore = FALSE; ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response"); ++ ret->allowNotifications = TRUE; ++ ++ flags = 0; ++ send_len = wpabuf_len(data->out_buf) - data->out_used; ++ if (2 + send_len > data->fragment_size) { ++ send_len = data->fragment_size - 2; ++ flags |= WSC_FLAGS_MF; ++ if (data->out_used == 0) { ++ flags |= WSC_FLAGS_LF; ++ send_len -= 2; ++ } ++ } ++ plen = 2 + send_len; ++ if (flags & WSC_FLAGS_LF) ++ plen += 2; ++ resp = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen, ++ EAP_CODE_RESPONSE, id); ++ if (resp == NULL) ++ return NULL; ++ ++ wpabuf_put_u8(resp, data->out_op_code); /* Op-Code */ ++ wpabuf_put_u8(resp, flags); /* Flags */ ++ if (flags & WSC_FLAGS_LF) ++ wpabuf_put_be16(resp, wpabuf_len(data->out_buf)); ++ ++ wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, ++ send_len); ++ data->out_used += send_len; ++ ++ ret->methodState = METHOD_MAY_CONT; ++ ret->decision = DECISION_FAIL; ++ ++ if (data->out_used == wpabuf_len(data->out_buf)) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " ++ "(message sent completely)", ++ (unsigned long) send_len); ++ wpabuf_free(data->out_buf); ++ data->out_buf = NULL; ++ data->out_used = 0; ++ if ((data->state == FAIL && data->out_op_code == WSC_ACK) || ++ data->out_op_code == WSC_NACK || ++ data->out_op_code == WSC_Done) { ++ eap_wsc_state(data, FAIL); ++ ret->methodState = METHOD_DONE; ++ } else ++ eap_wsc_state(data, MESG); ++ } else { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " ++ "(%lu more to send)", (unsigned long) send_len, ++ (unsigned long) wpabuf_len(data->out_buf) - ++ data->out_used); ++ eap_wsc_state(data, WAIT_FRAG_ACK); ++ } ++ ++ return resp; ++} ++ ++ ++static int eap_wsc_process_cont(struct eap_wsc_data *data, ++ const u8 *buf, size_t len, u8 op_code) ++{ ++ /* Process continuation of a pending message */ ++ if (op_code != data->in_op_code) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in " ++ "fragment (expected %d)", ++ op_code, data->in_op_code); ++ return -1; ++ } ++ ++ if (len > wpabuf_tailroom(data->in_buf)) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); ++ eap_wsc_state(data, FAIL); ++ return -1; ++ } ++ ++ wpabuf_put_data(data->in_buf, buf, len); ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting " ++ "for %lu bytes more", (unsigned long) len, ++ (unsigned long) wpabuf_tailroom(data->in_buf)); ++ ++ return 0; ++} ++ ++ ++static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data, ++ struct eap_method_ret *ret, ++ u8 id, u8 flags, u8 op_code, ++ u16 message_length, ++ const u8 *buf, size_t len) ++{ ++ /* Process a fragment that is not the last one of the message */ ++ if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a " ++ "fragmented packet"); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ ++ if (data->in_buf == NULL) { ++ /* First fragment of the message */ ++ data->in_buf = wpabuf_alloc(message_length); ++ if (data->in_buf == NULL) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for " ++ "message"); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ data->in_op_code = op_code; ++ wpabuf_put_data(data->in_buf, buf, len); ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in first " ++ "fragment, waiting for %lu bytes more", ++ (unsigned long) len, ++ (unsigned long) wpabuf_tailroom(data->in_buf)); ++ } ++ ++ return eap_wsc_build_frag_ack(id, EAP_CODE_RESPONSE); ++} ++ ++ ++static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv, ++ struct eap_method_ret *ret, ++ const struct wpabuf *reqData) ++{ ++ struct eap_wsc_data *data = priv; ++ const u8 *start, *pos, *end; ++ size_t len; ++ u8 op_code, flags, id; ++ u16 message_length = 0; ++ enum wps_process_res res; ++ struct wpabuf tmpbuf; ++ struct wpabuf *r; ++ ++ pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData, ++ &len); ++ if (pos == NULL || len < 2) { ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ ++ id = eap_get_id(reqData); ++ ++ start = pos; ++ end = start + len; ++ ++ op_code = *pos++; ++ flags = *pos++; ++ if (flags & WSC_FLAGS_LF) { ++ if (end - pos < 2) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow"); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ message_length = WPA_GET_BE16(pos); ++ pos += 2; ++ ++ if (message_length < end - pos || message_length > 50000) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message " ++ "Length"); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ } ++ ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d " ++ "Flags 0x%x Message Length %d", ++ op_code, flags, message_length); ++ ++ if (data->state == WAIT_FRAG_ACK) { ++ if (op_code != WSC_FRAG_ACK) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " ++ "in WAIT_FRAG_ACK state", op_code); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); ++ eap_wsc_state(data, MESG); ++ return eap_wsc_build_msg(data, ret, id); ++ } ++ ++ if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG && ++ op_code != WSC_Done && op_code != WSC_Start) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", ++ op_code); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ ++ if (data->state == WAIT_START) { ++ if (op_code != WSC_Start) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " ++ "in WAIT_START state", op_code); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Received start"); ++ eap_wsc_state(data, MESG); ++ /* Start message has empty payload, skip processing */ ++ goto send_msg; ++ } else if (op_code == WSC_Start) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", ++ op_code); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ ++ if (data->in_buf && ++ eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ ++ if (flags & WSC_FLAGS_MF) { ++ return eap_wsc_process_fragment(data, ret, id, flags, op_code, ++ message_length, pos, ++ end - pos); ++ } ++ ++ if (data->in_buf == NULL) { ++ /* Wrap unfragmented messages as wpabuf without extra copy */ ++ wpabuf_set(&tmpbuf, pos, end - pos); ++ data->in_buf = &tmpbuf; ++ } ++ ++ res = wps_process_msg(data->wps, op_code, data->in_buf); ++ switch (res) { ++ case WPS_DONE: ++ wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " ++ "successfully - wait for EAP failure"); ++ eap_wsc_state(data, FAIL); ++ break; ++ case WPS_CONTINUE: ++ eap_wsc_state(data, MESG); ++ break; ++ case WPS_FAILURE: ++ case WPS_PENDING: ++ wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); ++ eap_wsc_state(data, FAIL); ++ break; ++ } ++ ++ if (data->in_buf != &tmpbuf) ++ wpabuf_free(data->in_buf); ++ data->in_buf = NULL; ++ ++send_msg: ++ if (data->out_buf == NULL) { ++ data->out_buf = wps_get_msg(data->wps, &data->out_op_code); ++ if (data->out_buf == NULL) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive " ++ "message from WPS"); ++ eap_wsc_state(data, FAIL); ++ ret->methodState = METHOD_DONE; ++ ret->decision = DECISION_FAIL; ++ return NULL; ++ } ++ data->out_used = 0; ++ } ++ ++ eap_wsc_state(data, MESG); ++ r = eap_wsc_build_msg(data, ret, id); ++ if (data->state == FAIL && ret->methodState == METHOD_DONE) { ++ /* Use reduced client timeout for WPS to avoid long wait */ ++ if (sm->ClientTimeout > 2) ++ sm->ClientTimeout = 2; ++ } ++ return r; ++} ++ ++ ++int eap_peer_wsc_register(void) ++{ ++ struct eap_method *eap; ++ int ret; ++ ++ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, ++ EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, ++ "WSC"); ++ if (eap == NULL) ++ return -1; ++ ++ eap->init = eap_wsc_init; ++ eap->deinit = eap_wsc_deinit; ++ eap->process = eap_wsc_process; ++ ++ ret = eap_peer_method_register(eap); ++ if (ret) ++ eap_peer_method_free(eap); ++ return ret; ++} diff --git a/src/wps/wps.c b/src/wps/wps.c index fbaf85a..10a82e1 100644 --- a/src/wps/wps.c @@ -3538,12 +10855,12 @@ index fbaf85a..10a82e1 100644 @@ -321,11 +321,15 @@ int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr, if (wps_parse_msg(msg, &attr) < 0) return 0; - + + return is_selected_pin_registrar(&attr); +// Marked by Albert 2011/11/17 +// Some APs won't carry the AuthorizedMACs in the probe response. +// So, skip this check will speed up the process to find the current AP out for WPS handshake. -+/* ++/* if (!attr.version2 && ver1_compat) { /* * Version 1.0 AP - AuthorizedMACs not used, so revert back to @@ -3551,15 +10868,683 @@ index fbaf85a..10a82e1 100644 - */ return is_selected_pin_registrar(&attr); } - + @@ -342,6 +346,7 @@ int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr, } - + return 0; +*/ } - - + + +diff --git a/src/wps/wps.c.orig b/src/wps/wps.c.orig +new file mode 100644 +index 0000000..fbaf85a +--- /dev/null ++++ b/src/wps/wps.c.orig +@@ -0,0 +1,662 @@ ++/* ++ * Wi-Fi Protected Setup ++ * Copyright (c) 2007-2009, Jouni Malinen ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ */ ++ ++#include "includes.h" ++ ++#include "common.h" ++#include "crypto/dh_group5.h" ++#include "common/ieee802_11_defs.h" ++#include "wps_i.h" ++#include "wps_dev_attr.h" ++ ++ ++#ifdef CONFIG_WPS_TESTING ++int wps_version_number = 0x20; ++int wps_testing_dummy_cred = 0; ++int wps_corrupt_pkhash = 0; ++#endif /* CONFIG_WPS_TESTING */ ++ ++ ++/** ++ * wps_init - Initialize WPS Registration protocol data ++ * @cfg: WPS configuration ++ * Returns: Pointer to allocated data or %NULL on failure ++ * ++ * This function is used to initialize WPS data for a registration protocol ++ * instance (i.e., each run of registration protocol as a Registrar of ++ * Enrollee. The caller is responsible for freeing this data after the ++ * registration run has been completed by calling wps_deinit(). ++ */ ++struct wps_data * wps_init(const struct wps_config *cfg) ++{ ++ struct wps_data *data = os_zalloc(sizeof(*data)); ++ if (data == NULL) ++ return NULL; ++ data->wps = cfg->wps; ++ data->registrar = cfg->registrar; ++ if (cfg->registrar) { ++ os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN); ++ } else { ++ os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN); ++ os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN); ++ } ++ if (cfg->pin) { ++ data->dev_pw_id = cfg->dev_pw_id; ++ data->dev_password = os_malloc(cfg->pin_len); ++ if (data->dev_password == NULL) { ++ os_free(data); ++ return NULL; ++ } ++ os_memcpy(data->dev_password, cfg->pin, cfg->pin_len); ++ data->dev_password_len = cfg->pin_len; ++ wpa_hexdump_key(MSG_DEBUG, "WPS: AP PIN dev_password", ++ data->dev_password, data->dev_password_len); ++ } ++ ++#ifdef CONFIG_WPS_NFC ++ if (cfg->pin == NULL && ++ cfg->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) ++ data->dev_pw_id = cfg->dev_pw_id; ++ ++ if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) { ++ /* Keep AP PIN as alternative Device Password */ ++ data->alt_dev_pw_id = data->dev_pw_id; ++ data->alt_dev_password = data->dev_password; ++ data->alt_dev_password_len = data->dev_password_len; ++ ++ data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id; ++ data->dev_password = ++ os_malloc(wpabuf_len(cfg->wps->ap_nfc_dev_pw)); ++ if (data->dev_password == NULL) { ++ os_free(data); ++ return NULL; ++ } ++ os_memcpy(data->dev_password, ++ wpabuf_head(cfg->wps->ap_nfc_dev_pw), ++ wpabuf_len(cfg->wps->ap_nfc_dev_pw)); ++ data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw); ++ wpa_hexdump_key(MSG_DEBUG, "WPS: NFC dev_password", ++ data->dev_password, data->dev_password_len); ++ } ++#endif /* CONFIG_WPS_NFC */ ++ ++ data->pbc = cfg->pbc; ++ if (cfg->pbc) { ++ /* Use special PIN '00000000' for PBC */ ++ data->dev_pw_id = DEV_PW_PUSHBUTTON; ++ bin_clear_free(data->dev_password, data->dev_password_len); ++ data->dev_password = (u8 *) os_strdup("00000000"); ++ if (data->dev_password == NULL) { ++ os_free(data); ++ return NULL; ++ } ++ data->dev_password_len = 8; ++ } ++ ++ data->state = data->registrar ? RECV_M1 : SEND_M1; ++ ++ if (cfg->assoc_wps_ie) { ++ struct wps_parse_attr attr; ++ wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq", ++ cfg->assoc_wps_ie); ++ if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) { ++ wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE " ++ "from (Re)AssocReq"); ++ } else if (attr.request_type == NULL) { ++ wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute " ++ "in (Re)AssocReq WPS IE"); ++ } else { ++ wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE " ++ "in (Re)AssocReq WPS IE): %d", ++ *attr.request_type); ++ data->request_type = *attr.request_type; ++ } ++ } ++ ++ if (cfg->new_ap_settings) { ++ data->new_ap_settings = ++ os_malloc(sizeof(*data->new_ap_settings)); ++ if (data->new_ap_settings == NULL) { ++ bin_clear_free(data->dev_password, ++ data->dev_password_len); ++ os_free(data); ++ return NULL; ++ } ++ os_memcpy(data->new_ap_settings, cfg->new_ap_settings, ++ sizeof(*data->new_ap_settings)); ++ } ++ ++ if (cfg->peer_addr) ++ os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN); ++ if (cfg->p2p_dev_addr) ++ os_memcpy(data->p2p_dev_addr, cfg->p2p_dev_addr, ETH_ALEN); ++ ++ data->use_psk_key = cfg->use_psk_key; ++ data->pbc_in_m1 = cfg->pbc_in_m1; ++ ++ if (cfg->peer_pubkey_hash) { ++ os_memcpy(data->peer_pubkey_hash, cfg->peer_pubkey_hash, ++ WPS_OOB_PUBKEY_HASH_LEN); ++ data->peer_pubkey_hash_set = 1; ++ } ++ ++ return data; ++} ++ ++ ++/** ++ * wps_deinit - Deinitialize WPS Registration protocol data ++ * @data: WPS Registration protocol data from wps_init() ++ */ ++void wps_deinit(struct wps_data *data) ++{ ++#ifdef CONFIG_WPS_NFC ++ if (data->registrar && data->nfc_pw_token) ++ wps_registrar_remove_nfc_pw_token(data->wps->registrar, ++ data->nfc_pw_token); ++#endif /* CONFIG_WPS_NFC */ ++ ++ if (data->wps_pin_revealed) { ++ wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and " ++ "negotiation failed"); ++ if (data->registrar) ++ wps_registrar_invalidate_pin(data->wps->registrar, ++ data->uuid_e); ++ } else if (data->registrar) ++ wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e); ++ ++ wpabuf_free(data->dh_privkey); ++ wpabuf_free(data->dh_pubkey_e); ++ wpabuf_free(data->dh_pubkey_r); ++ wpabuf_free(data->last_msg); ++ bin_clear_free(data->dev_password, data->dev_password_len); ++ bin_clear_free(data->alt_dev_password, data->alt_dev_password_len); ++ bin_clear_free(data->new_psk, data->new_psk_len); ++ wps_device_data_free(&data->peer_dev); ++ bin_clear_free(data->new_ap_settings, sizeof(*data->new_ap_settings)); ++ dh5_free(data->dh_ctx); ++ os_free(data); ++} ++ ++ ++/** ++ * wps_process_msg - Process a WPS message ++ * @wps: WPS Registration protocol data from wps_init() ++ * @op_code: Message OP Code ++ * @msg: Message data ++ * Returns: Processing result ++ * ++ * This function is used to process WPS messages with OP Codes WSC_ACK, ++ * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is ++ * responsible for reassembling the messages before calling this function. ++ * Response to this message is built by calling wps_get_msg(). ++ */ ++enum wps_process_res wps_process_msg(struct wps_data *wps, ++ enum wsc_op_code op_code, ++ const struct wpabuf *msg) ++{ ++ if (wps->registrar) ++ return wps_registrar_process_msg(wps, op_code, msg); ++ else ++ return wps_enrollee_process_msg(wps, op_code, msg); ++} ++ ++ ++/** ++ * wps_get_msg - Build a WPS message ++ * @wps: WPS Registration protocol data from wps_init() ++ * @op_code: Buffer for returning message OP Code ++ * Returns: The generated WPS message or %NULL on failure ++ * ++ * This function is used to build a response to a message processed by calling ++ * wps_process_msg(). The caller is responsible for freeing the buffer. ++ */ ++struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code) ++{ ++ if (wps->registrar) ++ return wps_registrar_get_msg(wps, op_code); ++ else ++ return wps_enrollee_get_msg(wps, op_code); ++} ++ ++ ++/** ++ * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC ++ * @msg: WPS IE contents from Beacon or Probe Response frame ++ * Returns: 1 if PBC Registrar is active, 0 if not ++ */ ++int wps_is_selected_pbc_registrar(const struct wpabuf *msg) ++{ ++ struct wps_parse_attr attr; ++ ++ /* ++ * In theory, this could also verify that attr.sel_reg_config_methods ++ * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations ++ * do not set Selected Registrar Config Methods attribute properly, so ++ * it is safer to just use Device Password ID here. ++ */ ++ ++ if (wps_parse_msg(msg, &attr) < 0 || ++ !attr.selected_registrar || *attr.selected_registrar == 0 || ++ !attr.dev_password_id || ++ WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON) ++ return 0; ++ ++#ifdef CONFIG_WPS_STRICT ++ if (!attr.sel_reg_config_methods || ++ !(WPA_GET_BE16(attr.sel_reg_config_methods) & ++ WPS_CONFIG_PUSHBUTTON)) ++ return 0; ++#endif /* CONFIG_WPS_STRICT */ ++ ++ return 1; ++} ++ ++ ++static int is_selected_pin_registrar(struct wps_parse_attr *attr) ++{ ++ /* ++ * In theory, this could also verify that attr.sel_reg_config_methods ++ * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD, ++ * but some deployed AP implementations do not set Selected Registrar ++ * Config Methods attribute properly, so it is safer to just use ++ * Device Password ID here. ++ */ ++ ++ if (!attr->selected_registrar || *attr->selected_registrar == 0) ++ return 0; ++ ++ if (attr->dev_password_id != NULL && ++ WPA_GET_BE16(attr->dev_password_id) == DEV_PW_PUSHBUTTON) ++ return 0; ++ ++#ifdef CONFIG_WPS_STRICT ++ if (!attr->sel_reg_config_methods || ++ !(WPA_GET_BE16(attr->sel_reg_config_methods) & ++ (WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD))) ++ return 0; ++#endif /* CONFIG_WPS_STRICT */ ++ ++ return 1; ++} ++ ++ ++/** ++ * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN ++ * @msg: WPS IE contents from Beacon or Probe Response frame ++ * Returns: 1 if PIN Registrar is active, 0 if not ++ */ ++int wps_is_selected_pin_registrar(const struct wpabuf *msg) ++{ ++ struct wps_parse_attr attr; ++ ++ if (wps_parse_msg(msg, &attr) < 0) ++ return 0; ++ ++ return is_selected_pin_registrar(&attr); ++} ++ ++ ++/** ++ * wps_is_addr_authorized - Check whether WPS IE authorizes MAC address ++ * @msg: WPS IE contents from Beacon or Probe Response frame ++ * @addr: MAC address to search for ++ * @ver1_compat: Whether to use version 1 compatibility mode ++ * Returns: 2 if the specified address is explicit authorized, 1 if address is ++ * authorized (broadcast), 0 if not ++ */ ++int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr, ++ int ver1_compat) ++{ ++ struct wps_parse_attr attr; ++ unsigned int i; ++ const u8 *pos; ++ const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ++ ++ if (wps_parse_msg(msg, &attr) < 0) ++ return 0; ++ ++ if (!attr.version2 && ver1_compat) { ++ /* ++ * Version 1.0 AP - AuthorizedMACs not used, so revert back to ++ * old mechanism of using SelectedRegistrar. ++ */ ++ return is_selected_pin_registrar(&attr); ++ } ++ ++ if (!attr.authorized_macs) ++ return 0; ++ ++ pos = attr.authorized_macs; ++ for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) { ++ if (os_memcmp(pos, addr, ETH_ALEN) == 0) ++ return 2; ++ if (os_memcmp(pos, bcast, ETH_ALEN) == 0) ++ return 1; ++ pos += ETH_ALEN; ++ } ++ ++ return 0; ++} ++ ++ ++/** ++ * wps_ap_priority_compar - Prioritize WPS IE from two APs ++ * @wps_a: WPS IE contents from Beacon or Probe Response frame ++ * @wps_b: WPS IE contents from Beacon or Probe Response frame ++ * Returns: 1 if wps_b is considered more likely selection for WPS ++ * provisioning, -1 if wps_a is considered more like, or 0 if no preference ++ */ ++int wps_ap_priority_compar(const struct wpabuf *wps_a, ++ const struct wpabuf *wps_b) ++{ ++ struct wps_parse_attr attr; ++ int sel_a, sel_b; ++ ++ if (wps_a == NULL || wps_parse_msg(wps_a, &attr) < 0) ++ return 1; ++ sel_a = attr.selected_registrar && *attr.selected_registrar != 0; ++ ++ if (wps_b == NULL || wps_parse_msg(wps_b, &attr) < 0) ++ return -1; ++ sel_b = attr.selected_registrar && *attr.selected_registrar != 0; ++ ++ if (sel_a && !sel_b) ++ return -1; ++ if (!sel_a && sel_b) ++ return 1; ++ ++ return 0; ++} ++ ++ ++/** ++ * wps_get_uuid_e - Get UUID-E from WPS IE ++ * @msg: WPS IE contents from Beacon or Probe Response frame ++ * Returns: Pointer to UUID-E or %NULL if not included ++ * ++ * The returned pointer is to the msg contents and it remains valid only as ++ * long as the msg buffer is valid. ++ */ ++const u8 * wps_get_uuid_e(const struct wpabuf *msg) ++{ ++ struct wps_parse_attr attr; ++ ++ if (wps_parse_msg(msg, &attr) < 0) ++ return NULL; ++ return attr.uuid_e; ++} ++ ++ ++/** ++ * wps_is_20 - Check whether WPS attributes claim support for WPS 2.0 ++ */ ++int wps_is_20(const struct wpabuf *msg) ++{ ++ struct wps_parse_attr attr; ++ ++ if (msg == NULL || wps_parse_msg(msg, &attr) < 0) ++ return 0; ++ return attr.version2 != NULL; ++} ++ ++ ++/** ++ * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request ++ * @req_type: Value for Request Type attribute ++ * Returns: WPS IE or %NULL on failure ++ * ++ * The caller is responsible for freeing the buffer. ++ */ ++struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type) ++{ ++ struct wpabuf *ie; ++ u8 *len; ++ ++ wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " ++ "Request"); ++ ie = wpabuf_alloc(100); ++ if (ie == NULL) ++ return NULL; ++ ++ wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); ++ len = wpabuf_put(ie, 1); ++ wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); ++ ++ if (wps_build_version(ie) || ++ wps_build_req_type(ie, req_type) || ++ wps_build_wfa_ext(ie, 0, NULL, 0)) { ++ wpabuf_free(ie); ++ return NULL; ++ } ++ ++ *len = wpabuf_len(ie) - 2; ++ ++ return ie; ++} ++ ++ ++/** ++ * wps_build_assoc_resp_ie - Build WPS IE for (Re)Association Response ++ * Returns: WPS IE or %NULL on failure ++ * ++ * The caller is responsible for freeing the buffer. ++ */ ++struct wpabuf * wps_build_assoc_resp_ie(void) ++{ ++ struct wpabuf *ie; ++ u8 *len; ++ ++ wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " ++ "Response"); ++ ie = wpabuf_alloc(100); ++ if (ie == NULL) ++ return NULL; ++ ++ wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); ++ len = wpabuf_put(ie, 1); ++ wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); ++ ++ if (wps_build_version(ie) || ++ wps_build_resp_type(ie, WPS_RESP_AP) || ++ wps_build_wfa_ext(ie, 0, NULL, 0)) { ++ wpabuf_free(ie); ++ return NULL; ++ } ++ ++ *len = wpabuf_len(ie) - 2; ++ ++ return ie; ++} ++ ++ ++/** ++ * wps_build_probe_req_ie - Build WPS IE for Probe Request ++ * @pw_id: Password ID (DEV_PW_PUSHBUTTON for active PBC and DEV_PW_DEFAULT for ++ * most other use cases) ++ * @dev: Device attributes ++ * @uuid: Own UUID ++ * @req_type: Value for Request Type attribute ++ * @num_req_dev_types: Number of requested device types ++ * @req_dev_types: Requested device types (8 * num_req_dev_types octets) or ++ * %NULL if none ++ * Returns: WPS IE or %NULL on failure ++ * ++ * The caller is responsible for freeing the buffer. ++ */ ++struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev, ++ const u8 *uuid, ++ enum wps_request_type req_type, ++ unsigned int num_req_dev_types, ++ const u8 *req_dev_types) ++{ ++ struct wpabuf *ie; ++ ++ wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request"); ++ ++ ie = wpabuf_alloc(500); ++ if (ie == NULL) ++ return NULL; ++ ++ if (wps_build_version(ie) || ++ wps_build_req_type(ie, req_type) || ++ 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, 0) || ++ wps_build_assoc_state(NULL, ie) || ++ wps_build_config_error(ie, WPS_CFG_NO_ERROR) || ++ wps_build_dev_password_id(ie, pw_id) || ++ wps_build_manufacturer(dev, ie) || ++ wps_build_model_name(dev, ie) || ++ wps_build_model_number(dev, ie) || ++ wps_build_dev_name(dev, ie) || ++ wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) || ++ wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types) ++ || ++ wps_build_secondary_dev_type(dev, ie) ++ ) { ++ wpabuf_free(ie); ++ return NULL; ++ } ++ ++ return wps_ie_encapsulate(ie); ++} ++ ++ ++void wps_free_pending_msgs(struct upnp_pending_message *msgs) ++{ ++ struct upnp_pending_message *p, *prev; ++ p = msgs; ++ while (p) { ++ prev = p; ++ p = p->next; ++ wpabuf_free(prev->msg); ++ os_free(prev); ++ } ++} ++ ++ ++int wps_attr_text(struct wpabuf *data, char *buf, char *end) ++{ ++ struct wps_parse_attr attr; ++ char *pos = buf; ++ int ret; ++ ++ if (wps_parse_msg(data, &attr) < 0) ++ return -1; ++ ++ if (attr.wps_state) { ++ if (*attr.wps_state == WPS_STATE_NOT_CONFIGURED) ++ ret = os_snprintf(pos, end - pos, ++ "wps_state=unconfigured\n"); ++ else if (*attr.wps_state == WPS_STATE_CONFIGURED) ++ ret = os_snprintf(pos, end - pos, ++ "wps_state=configured\n"); ++ else ++ ret = 0; ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ if (attr.ap_setup_locked && *attr.ap_setup_locked) { ++ ret = os_snprintf(pos, end - pos, ++ "wps_ap_setup_locked=1\n"); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ if (attr.selected_registrar && *attr.selected_registrar) { ++ ret = os_snprintf(pos, end - pos, ++ "wps_selected_registrar=1\n"); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ if (attr.dev_password_id) { ++ ret = os_snprintf(pos, end - pos, ++ "wps_device_password_id=%u\n", ++ WPA_GET_BE16(attr.dev_password_id)); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ if (attr.sel_reg_config_methods) { ++ ret = os_snprintf(pos, end - pos, ++ "wps_selected_registrar_config_methods=" ++ "0x%04x\n", ++ WPA_GET_BE16(attr.sel_reg_config_methods)); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ if (attr.primary_dev_type) { ++ char devtype[WPS_DEV_TYPE_BUFSIZE]; ++ ret = os_snprintf(pos, end - pos, ++ "wps_primary_device_type=%s\n", ++ wps_dev_type_bin2str(attr.primary_dev_type, ++ devtype, ++ sizeof(devtype))); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ if (attr.dev_name) { ++ char *str = os_malloc(attr.dev_name_len + 1); ++ size_t i; ++ if (str == NULL) ++ return pos - buf; ++ for (i = 0; i < attr.dev_name_len; i++) { ++ if (attr.dev_name[i] == 0 || ++ is_ctrl_char(attr.dev_name[i])) ++ str[i] = '_'; ++ else ++ str[i] = attr.dev_name[i]; ++ } ++ str[i] = '\0'; ++ ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str); ++ os_free(str); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ if (attr.config_methods) { ++ ret = os_snprintf(pos, end - pos, ++ "wps_config_methods=0x%04x\n", ++ WPA_GET_BE16(attr.config_methods)); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ 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_registrar.c b/src/wps/wps_registrar.c index 4ca3a42..f74b036 100644 --- a/src/wps/wps_registrar.c diff --git a/packages/extras-buildpkgs/hostapd/debian/patches/0002-Check-for-NULL-qsort-base-pointers.patch b/packages/extras-buildpkgs/hostapd/debian/patches/0002-Check-for-NULL-qsort-base-pointers.patch index 801deba726..fde7359056 100644 --- a/packages/extras-buildpkgs/hostapd/debian/patches/0002-Check-for-NULL-qsort-base-pointers.patch +++ b/packages/extras-buildpkgs/hostapd/debian/patches/0002-Check-for-NULL-qsort-base-pointers.patch @@ -20,13 +20,13 @@ index 9c744de..8e7bcc7 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -208,7 +208,8 @@ static int hostapd_config_read_maclist(const char *fname, - + fclose(f); - + - qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp); + if (*acl) + qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp); - + return 0; } diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c @@ -36,7 +36,7 @@ index fb8ebdf..bfde0af 100644 @@ -2177,8 +2177,10 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_WPS */ - + - qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *), - compar); + if (scan_res->res) { @@ -44,8 +44,8 @@ index fb8ebdf..bfde0af 100644 + sizeof(struct wpa_scan_res *), compar); + } dump_scan_res(scan_res); - + wpa_bss_update_start(wpa_s); --- +-- 2.9.3 diff --git a/packages/extras-buildpkgs/hostapd/debian/patches/2018-1/0006-Extend-ieee80211_freq_to_channel_ext-to-cover-channe.patch b/packages/extras-buildpkgs/hostapd/debian/patches/0006-Extend-ieee80211_freq_to_channel_ext-to-cover-channe.patch similarity index 100% rename from packages/extras-buildpkgs/hostapd/debian/patches/2018-1/0006-Extend-ieee80211_freq_to_channel_ext-to-cover-channe.patch rename to packages/extras-buildpkgs/hostapd/debian/patches/0006-Extend-ieee80211_freq_to_channel_ext-to-cover-channe.patch diff --git a/packages/extras-buildpkgs/hostapd/debian/patches/300-noscan.patch b/packages/extras-buildpkgs/hostapd/debian/patches/300-noscan.patch index 8ff98d059a..2b6c1c48b6 100644 --- a/packages/extras-buildpkgs/hostapd/debian/patches/300-noscan.patch +++ b/packages/extras-buildpkgs/hostapd/debian/patches/300-noscan.patch @@ -30,13 +30,15 @@ diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index 16887acdf..75012df30 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c -@@ -474,6 +474,6 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface) +@@ -474,7 +474,8 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface) int ret; - -- if (!iface->conf->secondary_channel) -+ if (!iface->conf->secondary_channel || iface->conf->noscan) - return 0; /* HT40 not used */ - + + /* Check that HT40 is used and PRI / SEC switch is allowed */ +- if (!iface->conf->secondary_channel || iface->conf->no_pri_sec_switch) ++ if (!iface->conf->secondary_channel || iface->conf->no_pri_sec_switch || ++ iface->conf->noscan) + return 0; + hostapd_set_state(iface, HAPD_IFACE_HT_SCAN); diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c index 5eb1060a2..552bcc9bc 100644 diff --git a/packages/extras-buildpkgs/hostapd/debian/patches/hostapd-Allow-HT40-on-ch-165-169..patch b/packages/extras-buildpkgs/hostapd/debian/patches/hostapd-Allow-HT40-on-ch-165-169..patch deleted file mode 100644 index f12259c836..0000000000 --- a/packages/extras-buildpkgs/hostapd/debian/patches/hostapd-Allow-HT40-on-ch-165-169..patch +++ /dev/null @@ -1,38 +0,0 @@ -From patchwork Wed Jan 3 18:53:53 2018 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: hostapd: Allow HT40 on ch 165, 169. -X-Patchwork-Submitter: Ben Greear -X-Patchwork-Id: 855186 -Message-Id: <1515005633-26836-1-git-send-email-greearb@candelatech.com> -To: hostap@lists.infradead.org -Cc: Ben Greear -Date: Wed, 3 Jan 2018 10:53:53 -0800 -From: greearb@candelatech.com -List-Id: - -From: Ben Greear - -India supports CH 169 and 173 now. Enable HT40 across -CH 165 and 169. I think that CH 173 must remain HT20 -only. - -Signed-off-by: Ben Greear ---- - src/common/hw_features_common.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c -index 4486124..263958d 100644 ---- a/src/common/hw_features_common.c -+++ b/src/common/hw_features_common.c -@@ -89,7 +89,7 @@ int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan, - { - int ok, j, first; - int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140, -- 149, 157, 184, 192 }; -+ 149, 157, 165, 184, 192 }; - size_t k; - - if (pri_chan == sec_chan || !sec_chan) diff --git a/packages/extras-buildpkgs/hostapd/debian/patches/session-ticket.patch b/packages/extras-buildpkgs/hostapd/debian/patches/session-ticket.patch index 27ffaa6b9d..bfc87c34a3 100644 --- a/packages/extras-buildpkgs/hostapd/debian/patches/session-ticket.patch +++ b/packages/extras-buildpkgs/hostapd/debian/patches/session-ticket.patch @@ -1,21 +1,12 @@ -From: Jeremy Nickurak -Subject: Disable the session ticket TLS extension. -Bug-ubuntu: https://bugs.launchpad.net/ubuntu/+source/wpasupplicant/+bug/969343 -Bug: http://w1.fi/bugz/show_bug.cgi?id=447 - ---- - src/crypto/tls_openssl.c | 1 + - 1 file changed, 1 insertion(+) - -Index: b/src/crypto/tls_openssl.c -=================================================================== +diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c +index 23ac64b48..cc8d159e0 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c -@@ -1060,6 +1060,7 @@ struct tls_connection * tls_connection_i +@@ -1354,6 +1354,7 @@ struct tls_connection * tls_connection_init(void *ssl_ctx) #ifdef SSL_OP_NO_COMPRESSION options |= SSL_OP_NO_COMPRESSION; #endif /* SSL_OP_NO_COMPRESSION */ + options |= SSL_OP_NO_TICKET; SSL_set_options(conn->ssl, options); - + conn->ssl_in = BIO_new(BIO_s_mem()); diff --git a/packages/extras-buildpkgs/hostapd/debian/patches/wpa-cli-Make-ping-pong-work-more-reliably..patch b/packages/extras-buildpkgs/hostapd/debian/patches/wpa-cli-Make-ping-pong-work-more-reliably..patch deleted file mode 100644 index 65c69c2c68..0000000000 --- a/packages/extras-buildpkgs/hostapd/debian/patches/wpa-cli-Make-ping-pong-work-more-reliably..patch +++ /dev/null @@ -1,44 +0,0 @@ -From patchwork Mon Dec 4 17:18:26 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: wpa-cli: Make ping/pong work more reliably. -X-Patchwork-Submitter: Ben Greear -X-Patchwork-Id: 844334 -Message-Id: <1512407906-6986-1-git-send-email-greearb@candelatech.com> -To: hostap@lists.infradead.org -Cc: Ben Greear -Date: Mon, 4 Dec 2017 09:18:26 -0800 -From: greearb@candelatech.com -List-Id: - -From: Ben Greear - -In 2013 or so, IFNAME=foo was prepended to at least the -Unix socket communication from wpa_supplicant to wpa_cli. - -This broke the (fragile) logic that made ping/pong work more -often when the supplicant is busy sending logging info to -the wpa_cli. - -Adding check for IFNAME=foo makes this work better. - -Signed-off-by: Ben Greear ---- - src/common/wpa_ctrl.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c -index 623c2a7..1f1c9c4 100644 ---- a/src/common/wpa_ctrl.c -+++ b/src/common/wpa_ctrl.c -@@ -540,7 +540,8 @@ retry_send: - res = recv(ctrl->s, reply, *reply_len, 0); - if (res < 0) - return res; -- if (res > 0 && reply[0] == '<') { -+ if ((res > 0 && reply[0] == '<') || -+ (res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) { - /* This is an unsolicited message from - * wpa_supplicant, not the reply to the - * request. Use msg_cb to report this to the