wpa_supplicant-2.2/0000775000175000017500000000000012343617166012217 5ustar jmjmwpa_supplicant-2.2/wpa_supplicant/0000775000175000017500000000000012343617166015250 5ustar jmjmwpa_supplicant-2.2/wpa_supplicant/wpas_glue.c0000664000175000017500000006223412343617166017411 0ustar jmjm/* * WPA Supplicant - Glue code to setup EAPOL and RSN modules * Copyright (c) 2003-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 "eapol_supp/eapol_supp_sm.h" #include "rsn_supp/wpa.h" #include "eloop.h" #include "config.h" #include "l2_packet/l2_packet.h" #include "common/wpa_common.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "rsn_supp/pmksa_cache.h" #include "sme.h" #include "common/ieee802_11_defs.h" #include "common/wpa_ctrl.h" #include "wpas_glue.h" #include "wps_supplicant.h" #include "bss.h" #include "scan.h" #include "notify.h" #include "wpas_kay.h" #ifndef CONFIG_NO_CONFIG_BLOBS #if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) static void wpa_supplicant_set_config_blob(void *ctx, struct wpa_config_blob *blob) { struct wpa_supplicant *wpa_s = ctx; wpa_config_set_blob(wpa_s->conf, blob); if (wpa_s->conf->update_config) { int ret = wpa_config_write(wpa_s->confname, wpa_s->conf); if (ret) { wpa_printf(MSG_DEBUG, "Failed to update config after " "blob set"); } } } static const struct wpa_config_blob * wpa_supplicant_get_config_blob(void *ctx, const char *name) { struct wpa_supplicant *wpa_s = ctx; return wpa_config_get_blob(wpa_s->conf, name); } #endif /* defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) */ #endif /* CONFIG_NO_CONFIG_BLOBS */ #if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type, const void *data, u16 data_len, size_t *msg_len, void **data_pos) { struct ieee802_1x_hdr *hdr; *msg_len = sizeof(*hdr) + data_len; hdr = os_malloc(*msg_len); if (hdr == NULL) return NULL; hdr->version = wpa_s->conf->eapol_version; hdr->type = type; hdr->length = host_to_be16(data_len); if (data) os_memcpy(hdr + 1, data, data_len); else os_memset(hdr + 1, 0, data_len); if (data_pos) *data_pos = hdr + 1; return (u8 *) hdr; } /** * wpa_ether_send - Send Ethernet frame * @wpa_s: Pointer to wpa_supplicant data * @dest: Destination MAC address * @proto: Ethertype in host byte order * @buf: Frame payload starting from IEEE 802.1X header * @len: Frame payload length * Returns: >=0 on success, <0 on failure */ static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, u16 proto, const u8 *buf, size_t len) { if (wpa_s->l2) { return l2_packet_send(wpa_s->l2, dest, proto, buf, len); } return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len); } #endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */ #ifdef IEEE8021X_EAPOL /** * wpa_supplicant_eapol_send - Send IEEE 802.1X EAPOL packet to Authenticator * @ctx: Pointer to wpa_supplicant data (wpa_s) * @type: IEEE 802.1X packet type (IEEE802_1X_TYPE_*) * @buf: EAPOL payload (after IEEE 802.1X header) * @len: EAPOL payload length * Returns: >=0 on success, <0 on failure * * This function adds Ethernet and IEEE 802.1X header and sends the EAPOL frame * to the current Authenticator. */ static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf, size_t len) { struct wpa_supplicant *wpa_s = ctx; u8 *msg, *dst, bssid[ETH_ALEN]; size_t msglen; int res; /* TODO: could add l2_packet_sendmsg that allows fragments to avoid * extra copy here */ if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) { /* Current SSID is not using IEEE 802.1X/EAP, so drop possible * EAPOL frames (mainly, EAPOL-Start) from EAPOL state * machines. */ wpa_printf(MSG_DEBUG, "WPA: drop TX EAPOL in non-IEEE 802.1X " "mode (type=%d len=%lu)", type, (unsigned long) len); return -1; } if (pmksa_cache_get_current(wpa_s->wpa) && type == IEEE802_1X_TYPE_EAPOL_START) { /* Trying to use PMKSA caching - do not send EAPOL-Start frames * since they will trigger full EAPOL authentication. */ wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send " "EAPOL-Start"); return -1; } if (is_zero_ether_addr(wpa_s->bssid)) { wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an " "EAPOL frame"); if (wpa_drv_get_bssid(wpa_s, bssid) == 0 && !is_zero_ether_addr(bssid)) { dst = bssid; wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR " from the driver as the EAPOL destination", MAC2STR(dst)); } else { dst = wpa_s->last_eapol_src; wpa_printf(MSG_DEBUG, "Using the source address of the" " last received EAPOL frame " MACSTR " as " "the EAPOL destination", MAC2STR(dst)); } } else { /* BSSID was already set (from (Re)Assoc event, so use it as * the EAPOL destination. */ dst = wpa_s->bssid; } msg = wpa_alloc_eapol(wpa_s, type, buf, len, &msglen, NULL); if (msg == NULL) return -1; wpa_printf(MSG_DEBUG, "TX EAPOL: dst=" MACSTR, MAC2STR(dst)); wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", msg, msglen); res = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, msg, msglen); os_free(msg); return res; } /** * wpa_eapol_set_wep_key - set WEP key for the driver * @ctx: Pointer to wpa_supplicant data (wpa_s) * @unicast: 1 = individual unicast key, 0 = broadcast key * @keyidx: WEP key index (0..3) * @key: Pointer to key data * @keylen: Key length in bytes * Returns: 0 on success or < 0 on error. */ static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx, const u8 *key, size_t keylen) { struct wpa_supplicant *wpa_s = ctx; if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { int cipher = (keylen == 5) ? WPA_CIPHER_WEP40 : WPA_CIPHER_WEP104; if (unicast) wpa_s->pairwise_cipher = cipher; else wpa_s->group_cipher = cipher; } return wpa_drv_set_key(wpa_s, WPA_ALG_WEP, unicast ? wpa_s->bssid : NULL, keyidx, unicast, NULL, 0, key, keylen); } static void wpa_supplicant_aborted_cached(void *ctx) { struct wpa_supplicant *wpa_s = ctx; wpa_sm_aborted_cached(wpa_s->wpa); } static const char * result_str(enum eapol_supp_result result) { switch (result) { case EAPOL_SUPP_RESULT_FAILURE: return "FAILURE"; case EAPOL_SUPP_RESULT_SUCCESS: return "SUCCESS"; case EAPOL_SUPP_RESULT_EXPECTED_FAILURE: return "EXPECTED_FAILURE"; } return "?"; } static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, enum eapol_supp_result result, void *ctx) { struct wpa_supplicant *wpa_s = ctx; int res, pmk_len; u8 pmk[PMK_LEN]; wpa_printf(MSG_DEBUG, "EAPOL authentication completed - result=%s", result_str(result)); if (wpas_wps_eapol_cb(wpa_s) > 0) return; wpa_s->eap_expected_failure = result == EAPOL_SUPP_RESULT_EXPECTED_FAILURE; if (result != EAPOL_SUPP_RESULT_SUCCESS) { /* * Make sure we do not get stuck here waiting for long EAPOL * timeout if the AP does not disconnect in case of * authentication failure. */ wpa_supplicant_req_auth_timeout(wpa_s, 2, 0); } else { ieee802_1x_notify_create_actor(wpa_s, wpa_s->last_eapol_src); } if (result != EAPOL_SUPP_RESULT_SUCCESS || !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) return; if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) return; wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way " "handshake"); pmk_len = PMK_LEN; if (wpa_key_mgmt_ft(wpa_s->key_mgmt)) { #ifdef CONFIG_IEEE80211R u8 buf[2 * PMK_LEN]; wpa_printf(MSG_DEBUG, "RSN: Use FT XXKey as PMK for " "driver-based 4-way hs and FT"); res = eapol_sm_get_key(eapol, buf, 2 * PMK_LEN); if (res == 0) { os_memcpy(pmk, buf + PMK_LEN, PMK_LEN); os_memset(buf, 0, sizeof(buf)); } #else /* CONFIG_IEEE80211R */ res = -1; #endif /* CONFIG_IEEE80211R */ } else { res = eapol_sm_get_key(eapol, pmk, PMK_LEN); if (res) { /* * EAP-LEAP is an exception from other EAP methods: it * uses only 16-byte PMK. */ res = eapol_sm_get_key(eapol, pmk, 16); pmk_len = 16; } } if (res) { wpa_printf(MSG_DEBUG, "Failed to get PMK from EAPOL state " "machines"); return; } wpa_hexdump_key(MSG_DEBUG, "RSN: Configure PMK for driver-based 4-way " "handshake", pmk, pmk_len); if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk, pmk_len)) { wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver"); } wpa_supplicant_cancel_scan(wpa_s); wpa_supplicant_cancel_auth_timeout(wpa_s); wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); } static void wpa_supplicant_notify_eapol_done(void *ctx) { struct wpa_supplicant *wpa_s = ctx; wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete"); if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE); } else { wpa_supplicant_cancel_auth_timeout(wpa_s); wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); } } #endif /* IEEE8021X_EAPOL */ #ifndef CONFIG_NO_WPA static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s) { int ret = 0; struct wpa_bss *curr = NULL, *bss; struct wpa_ssid *ssid = wpa_s->current_ssid; const u8 *ie; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) != 0) continue; if (ssid == NULL || ((bss->ssid_len == ssid->ssid_len && os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) == 0) || ssid->ssid_len == 0)) { curr = bss; break; } } if (curr) { ie = wpa_bss_get_vendor_ie(curr, WPA_IE_VENDOR_TYPE); if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0)) ret = -1; ie = wpa_bss_get_ie(curr, WLAN_EID_RSN); if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0)) ret = -1; } else { ret = -1; } return ret; } static int wpa_supplicant_get_beacon_ie(void *ctx) { struct wpa_supplicant *wpa_s = ctx; if (wpa_get_beacon_ie(wpa_s) == 0) { return 0; } /* No WPA/RSN IE found in the cached scan results. Try to get updated * scan results from the driver. */ if (wpa_supplicant_update_scan_results(wpa_s) < 0) return -1; return wpa_get_beacon_ie(wpa_s); } static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type, const void *data, u16 data_len, size_t *msg_len, void **data_pos) { return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos); } static int _wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto, const u8 *buf, size_t len) { return wpa_ether_send(wpa_s, dest, proto, buf, len); } static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s) { wpa_supplicant_cancel_auth_timeout(wpa_s); } static void _wpa_supplicant_set_state(void *wpa_s, enum wpa_states state) { wpa_supplicant_set_state(wpa_s, state); } /** * wpa_supplicant_get_state - Get the connection state * @wpa_s: Pointer to wpa_supplicant data * Returns: The current connection state (WPA_*) */ static enum wpa_states wpa_supplicant_get_state(struct wpa_supplicant *wpa_s) { return wpa_s->wpa_state; } static enum wpa_states _wpa_supplicant_get_state(void *wpa_s) { return wpa_supplicant_get_state(wpa_s); } static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code) { wpa_supplicant_deauthenticate(wpa_s, reason_code); /* Schedule a scan to make sure we continue looking for networks */ wpa_supplicant_req_scan(wpa_s, 5, 0); } static void * wpa_supplicant_get_network_ctx(void *wpa_s) { return wpa_supplicant_get_ssid(wpa_s); } static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid) { struct wpa_supplicant *wpa_s = ctx; return wpa_drv_get_bssid(wpa_s, bssid); } static int wpa_supplicant_set_key(void *_wpa_s, 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_supplicant *wpa_s = _wpa_s; if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) { /* Clear the MIC error counter when setting a new PTK. */ wpa_s->mic_errors_seen = 0; } #ifdef CONFIG_TESTING_GET_GTK if (key_idx > 0 && addr && is_broadcast_ether_addr(addr) && alg != WPA_ALG_NONE && key_len <= sizeof(wpa_s->last_gtk)) { os_memcpy(wpa_s->last_gtk, key, key_len); wpa_s->last_gtk_len = key_len; } #endif /* CONFIG_TESTING_GET_GTK */ return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len, key, key_len); } static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr, int protection_type, int key_type) { return wpa_drv_mlme_setprotection(wpa_s, addr, protection_type, key_type); } static int wpa_supplicant_add_pmkid(void *wpa_s, const u8 *bssid, const u8 *pmkid) { return wpa_drv_add_pmkid(wpa_s, bssid, pmkid); } static int wpa_supplicant_remove_pmkid(void *wpa_s, const u8 *bssid, const u8 *pmkid) { return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid); } #ifdef CONFIG_IEEE80211R static int wpa_supplicant_update_ft_ies(void *ctx, const u8 *md, const u8 *ies, size_t ies_len) { struct wpa_supplicant *wpa_s = ctx; if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) return sme_update_ft_ies(wpa_s, md, ies, ies_len); return wpa_drv_update_ft_ies(wpa_s, md, ies, ies_len); } static int wpa_supplicant_send_ft_action(void *ctx, u8 action, const u8 *target_ap, const u8 *ies, size_t ies_len) { struct wpa_supplicant *wpa_s = ctx; return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len); } static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap) { struct wpa_supplicant *wpa_s = ctx; struct wpa_driver_auth_params params; struct wpa_bss *bss; bss = wpa_bss_get_bssid(wpa_s, target_ap); if (bss == NULL) return -1; os_memset(¶ms, 0, sizeof(params)); params.bssid = target_ap; params.freq = bss->freq; params.ssid = bss->ssid; params.ssid_len = bss->ssid_len; params.auth_alg = WPA_AUTH_ALG_FT; params.local_state_change = 1; return wpa_drv_authenticate(wpa_s, ¶ms); } #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_TDLS static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported, int *tdls_ext_setup) { struct wpa_supplicant *wpa_s = ctx; *tdls_supported = 0; *tdls_ext_setup = 0; if (!wpa_s->drv_capa_known) return -1; if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) *tdls_supported = 1; if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP) *tdls_ext_setup = 1; return 0; } static int wpa_supplicant_send_tdls_mgmt(void *ctx, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, const u8 *buf, size_t len) { struct wpa_supplicant *wpa_s = ctx; return wpa_drv_send_tdls_mgmt(wpa_s, dst, action_code, dialog_token, status_code, peer_capab, buf, len); } static int wpa_supplicant_tdls_oper(void *ctx, int oper, const u8 *peer) { struct wpa_supplicant *wpa_s = ctx; return wpa_drv_tdls_oper(wpa_s, oper, peer); } static int wpa_supplicant_tdls_peer_addset( void *ctx, const u8 *peer, int add, u16 aid, u16 capability, const u8 *supp_rates, size_t supp_rates_len, const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len, const u8 *supp_channels, size_t supp_channels_len, const u8 *supp_oper_classes, size_t supp_oper_classes_len) { struct wpa_supplicant *wpa_s = ctx; struct hostapd_sta_add_params params; os_memset(¶ms, 0, sizeof(params)); params.addr = peer; params.aid = aid; params.capability = capability; params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED; /* * TDLS Setup frames do not contain WMM IEs, hence need to depend on * qosinfo to check if the peer is WMM capable. */ if (qosinfo) params.flags |= WPA_STA_WMM; params.ht_capabilities = ht_capab; params.vht_capabilities = vht_capab; params.qosinfo = qosinfo; params.listen_interval = 0; params.supp_rates = supp_rates; params.supp_rates_len = supp_rates_len; params.set = !add; params.ext_capab = ext_capab; params.ext_capab_len = ext_capab_len; params.supp_channels = supp_channels; params.supp_channels_len = supp_channels_len; params.supp_oper_classes = supp_oper_classes; params.supp_oper_classes_len = supp_oper_classes_len; return wpa_drv_sta_add(wpa_s, ¶ms); } #endif /* CONFIG_TDLS */ #endif /* CONFIG_NO_WPA */ enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field) { if (os_strcmp(field, "IDENTITY") == 0) return WPA_CTRL_REQ_EAP_IDENTITY; else if (os_strcmp(field, "PASSWORD") == 0) return WPA_CTRL_REQ_EAP_PASSWORD; else if (os_strcmp(field, "NEW_PASSWORD") == 0) return WPA_CTRL_REQ_EAP_NEW_PASSWORD; else if (os_strcmp(field, "PIN") == 0) return WPA_CTRL_REQ_EAP_PIN; else if (os_strcmp(field, "OTP") == 0) return WPA_CTRL_REQ_EAP_OTP; else if (os_strcmp(field, "PASSPHRASE") == 0) return WPA_CTRL_REQ_EAP_PASSPHRASE; else if (os_strcmp(field, "SIM") == 0) return WPA_CTRL_REQ_SIM; return WPA_CTRL_REQ_UNKNOWN; } const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field, const char *default_txt, const char **txt) { const char *ret = NULL; *txt = default_txt; switch (field) { case WPA_CTRL_REQ_EAP_IDENTITY: *txt = "Identity"; ret = "IDENTITY"; break; case WPA_CTRL_REQ_EAP_PASSWORD: *txt = "Password"; ret = "PASSWORD"; break; case WPA_CTRL_REQ_EAP_NEW_PASSWORD: *txt = "New Password"; ret = "NEW_PASSWORD"; break; case WPA_CTRL_REQ_EAP_PIN: *txt = "PIN"; ret = "PIN"; break; case WPA_CTRL_REQ_EAP_OTP: ret = "OTP"; break; case WPA_CTRL_REQ_EAP_PASSPHRASE: *txt = "Private key passphrase"; ret = "PASSPHRASE"; break; case WPA_CTRL_REQ_SIM: ret = "SIM"; break; default: break; } /* txt needs to be something */ if (*txt == NULL) { wpa_printf(MSG_WARNING, "No message for request %d", field); ret = NULL; } return ret; } #ifdef IEEE8021X_EAPOL #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) static void wpa_supplicant_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field, const char *default_txt) { struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *ssid = wpa_s->current_ssid; const char *field_name, *txt = NULL; char *buf; size_t buflen; int len; if (ssid == NULL) return; wpas_notify_network_request(wpa_s, ssid, field, default_txt); field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt, &txt); if (field_name == NULL) { wpa_printf(MSG_WARNING, "Unhandled EAP param %d needed", field); return; } wpas_notify_eap_status(wpa_s, "eap parameter needed", field_name); buflen = 100 + os_strlen(txt) + ssid->ssid_len; buf = os_malloc(buflen); if (buf == NULL) return; len = os_snprintf(buf, buflen, WPA_CTRL_REQ "%s-%d:%s needed for SSID ", field_name, ssid->id, txt); if (len < 0 || (size_t) len >= buflen) { os_free(buf); return; } if (ssid->ssid && buflen > len + ssid->ssid_len) { os_memcpy(buf + len, ssid->ssid, ssid->ssid_len); len += ssid->ssid_len; buf[len] = '\0'; } buf[buflen - 1] = '\0'; wpa_msg(wpa_s, MSG_INFO, "%s", buf); os_free(buf); } #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ #define wpa_supplicant_eap_param_needed NULL #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ static void wpa_supplicant_port_cb(void *ctx, int authorized) { struct wpa_supplicant *wpa_s = ctx; #ifdef CONFIG_AP if (wpa_s->ap_iface) { wpa_printf(MSG_DEBUG, "AP mode active - skip EAPOL Supplicant " "port status: %s", authorized ? "Authorized" : "Unauthorized"); return; } #endif /* CONFIG_AP */ wpa_printf(MSG_DEBUG, "EAPOL: Supplicant port status: %s", authorized ? "Authorized" : "Unauthorized"); wpa_drv_set_supp_port(wpa_s, authorized); } static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject, const char *cert_hash, const struct wpabuf *cert) { struct wpa_supplicant *wpa_s = ctx; wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert); } static void wpa_supplicant_status_cb(void *ctx, const char *status, const char *parameter) { struct wpa_supplicant *wpa_s = ctx; wpas_notify_eap_status(wpa_s, status, parameter); } static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len) { struct wpa_supplicant *wpa_s = ctx; char *str; int res; wpa_hexdump_ascii(MSG_DEBUG, "EAP method updated anonymous_identity", id, len); if (wpa_s->current_ssid == NULL) return; if (id == NULL) { if (wpa_config_set(wpa_s->current_ssid, "anonymous_identity", "NULL", 0) < 0) return; } else { str = os_malloc(len * 2 + 1); if (str == NULL) return; wpa_snprintf_hex(str, len * 2 + 1, id, len); res = wpa_config_set(wpa_s->current_ssid, "anonymous_identity", str, 0); os_free(str); if (res < 0) return; } if (wpa_s->conf->update_config) { res = wpa_config_write(wpa_s->confname, wpa_s->conf); if (res) { wpa_printf(MSG_DEBUG, "Failed to update config after " "anonymous_id update"); } } } #endif /* IEEE8021X_EAPOL */ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) { #ifdef IEEE8021X_EAPOL struct eapol_ctx *ctx; ctx = os_zalloc(sizeof(*ctx)); if (ctx == NULL) { wpa_printf(MSG_ERROR, "Failed to allocate EAPOL context."); return -1; } ctx->ctx = wpa_s; ctx->msg_ctx = wpa_s; ctx->eapol_send_ctx = wpa_s; ctx->preauth = 0; ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done; ctx->eapol_send = wpa_supplicant_eapol_send; ctx->set_wep_key = wpa_eapol_set_wep_key; #ifndef CONFIG_NO_CONFIG_BLOBS ctx->set_config_blob = wpa_supplicant_set_config_blob; ctx->get_config_blob = wpa_supplicant_get_config_blob; #endif /* CONFIG_NO_CONFIG_BLOBS */ ctx->aborted_cached = wpa_supplicant_aborted_cached; ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path; ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path; ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path; ctx->wps = wpa_s->wps; ctx->eap_param_needed = wpa_supplicant_eap_param_needed; ctx->port_cb = wpa_supplicant_port_cb; ctx->cb = wpa_supplicant_eapol_cb; ctx->cert_cb = wpa_supplicant_cert_cb; ctx->status_cb = wpa_supplicant_status_cb; ctx->set_anon_id = wpa_supplicant_set_anon_id; ctx->cb_ctx = wpa_s; wpa_s->eapol = eapol_sm_init(ctx); if (wpa_s->eapol == NULL) { os_free(ctx); wpa_printf(MSG_ERROR, "Failed to initialize EAPOL state " "machines."); return -1; } #endif /* IEEE8021X_EAPOL */ return 0; } #ifndef CONFIG_NO_WPA static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek, const u8 *kck, const u8 *replay_ctr) { struct wpa_supplicant *wpa_s = ctx; wpa_drv_set_rekey_info(wpa_s, kek, kck, replay_ctr); } #endif /* CONFIG_NO_WPA */ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) { #ifndef CONFIG_NO_WPA struct wpa_sm_ctx *ctx; ctx = os_zalloc(sizeof(*ctx)); if (ctx == NULL) { wpa_printf(MSG_ERROR, "Failed to allocate WPA context."); return -1; } ctx->ctx = wpa_s; ctx->msg_ctx = wpa_s; ctx->set_state = _wpa_supplicant_set_state; ctx->get_state = _wpa_supplicant_get_state; ctx->deauthenticate = _wpa_supplicant_deauthenticate; ctx->set_key = wpa_supplicant_set_key; ctx->get_network_ctx = wpa_supplicant_get_network_ctx; ctx->get_bssid = wpa_supplicant_get_bssid; ctx->ether_send = _wpa_ether_send; ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie; ctx->alloc_eapol = _wpa_alloc_eapol; ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout; ctx->add_pmkid = wpa_supplicant_add_pmkid; ctx->remove_pmkid = wpa_supplicant_remove_pmkid; #ifndef CONFIG_NO_CONFIG_BLOBS ctx->set_config_blob = wpa_supplicant_set_config_blob; ctx->get_config_blob = wpa_supplicant_get_config_blob; #endif /* CONFIG_NO_CONFIG_BLOBS */ ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection; #ifdef CONFIG_IEEE80211R ctx->update_ft_ies = wpa_supplicant_update_ft_ies; ctx->send_ft_action = wpa_supplicant_send_ft_action; ctx->mark_authenticated = wpa_supplicant_mark_authenticated; #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_TDLS ctx->tdls_get_capa = wpa_supplicant_tdls_get_capa; ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt; ctx->tdls_oper = wpa_supplicant_tdls_oper; ctx->tdls_peer_addset = wpa_supplicant_tdls_peer_addset; #endif /* CONFIG_TDLS */ ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload; wpa_s->wpa = wpa_sm_init(ctx); if (wpa_s->wpa == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize WPA state " "machine"); return -1; } #endif /* CONFIG_NO_WPA */ return 0; } void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct rsn_supp_config conf; if (ssid) { os_memset(&conf, 0, sizeof(conf)); conf.network_ctx = ssid; conf.peerkey_enabled = ssid->peerkey; conf.allowed_pairwise_cipher = ssid->pairwise_cipher; #ifdef IEEE8021X_EAPOL conf.proactive_key_caching = ssid->proactive_key_caching < 0 ? wpa_s->conf->okc : ssid->proactive_key_caching; conf.eap_workaround = ssid->eap_workaround; conf.eap_conf_ctx = &ssid->eap; #endif /* IEEE8021X_EAPOL */ conf.ssid = ssid->ssid; conf.ssid_len = ssid->ssid_len; conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey; #ifdef CONFIG_P2P if (ssid->p2p_group && wpa_s->current_bss && !wpa_s->p2p_disable_ip_addr_req) { struct wpabuf *p2p; p2p = wpa_bss_get_vendor_ie_multi(wpa_s->current_bss, P2P_IE_VENDOR_TYPE); if (p2p) { u8 group_capab; group_capab = p2p_get_group_capab(p2p); if (group_capab & P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION) conf.p2p = 1; wpabuf_free(p2p); } } #endif /* CONFIG_P2P */ } wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL); } wpa_supplicant-2.2/wpa_supplicant/main_winsvc.c0000664000175000017500000002622512343617166017740 0ustar jmjm/* * WPA Supplicant / main() function for Win32 service * Copyright (c) 2003-2006, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. * * The root of wpa_supplicant configuration in registry is * HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant. This level includes global * parameters and a 'interfaces' subkey with all the interface configuration * (adapter to confname mapping). Each such mapping is a subkey that has * 'adapter' and 'config' values. * * This program can be run either as a normal command line application, e.g., * for debugging, with 'wpasvc.exe app' or as a Windows service. Service need * to be registered with 'wpasvc.exe reg '. After * this, it can be started like any other Windows service (e.g., 'net start * wpasvc') or it can be configured to start automatically through the Services * tool in administrative tasks. The service can be unregistered with * 'wpasvc.exe unreg'. */ #include "includes.h" #include #include "common.h" #include "wpa_supplicant_i.h" #include "eloop.h" #ifndef WPASVC_NAME #define WPASVC_NAME TEXT("wpasvc") #endif #ifndef WPASVC_DISPLAY_NAME #define WPASVC_DISPLAY_NAME TEXT("wpa_supplicant service") #endif #ifndef WPASVC_DESCRIPTION #define WPASVC_DESCRIPTION \ TEXT("Provides IEEE 802.1X and WPA/WPA2 supplicant functionality") #endif static HANDLE kill_svc; static SERVICE_STATUS_HANDLE svc_status_handle; static SERVICE_STATUS svc_status; #ifndef WPA_KEY_ROOT #define WPA_KEY_ROOT HKEY_LOCAL_MACHINE #endif #ifndef WPA_KEY_PREFIX #define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant") #endif #ifdef UNICODE #define TSTR "%S" #else /* UNICODE */ #define TSTR "%s" #endif /* UNICODE */ static int read_interface(struct wpa_global *global, HKEY _hk, const TCHAR *name) { HKEY hk; #define TBUFLEN 255 TCHAR adapter[TBUFLEN], config[TBUFLEN], ctrl_interface[TBUFLEN]; DWORD buflen, val; LONG ret; struct wpa_interface iface; int skip_on_error = 0; ret = RegOpenKeyEx(_hk, name, 0, KEY_QUERY_VALUE, &hk); if (ret != ERROR_SUCCESS) { printf("Could not open wpa_supplicant interface key\n"); return -1; } os_memset(&iface, 0, sizeof(iface)); iface.driver = "ndis"; buflen = sizeof(ctrl_interface); ret = RegQueryValueEx(hk, TEXT("ctrl_interface"), NULL, NULL, (LPBYTE) ctrl_interface, &buflen); if (ret == ERROR_SUCCESS) { ctrl_interface[TBUFLEN - 1] = TEXT('\0'); wpa_unicode2ascii_inplace(ctrl_interface); printf("ctrl_interface[len=%d] '%s'\n", (int) buflen, (char *) ctrl_interface); iface.ctrl_interface = (char *) ctrl_interface; } buflen = sizeof(adapter); ret = RegQueryValueEx(hk, TEXT("adapter"), NULL, NULL, (LPBYTE) adapter, &buflen); if (ret == ERROR_SUCCESS) { adapter[TBUFLEN - 1] = TEXT('\0'); wpa_unicode2ascii_inplace(adapter); printf("adapter[len=%d] '%s'\n", (int) buflen, (char *) adapter); iface.ifname = (char *) adapter; } buflen = sizeof(config); ret = RegQueryValueEx(hk, TEXT("config"), NULL, NULL, (LPBYTE) config, &buflen); if (ret == ERROR_SUCCESS) { config[sizeof(config) - 1] = '\0'; wpa_unicode2ascii_inplace(config); printf("config[len=%d] '%s'\n", (int) buflen, (char *) config); iface.confname = (char *) config; } buflen = sizeof(val); ret = RegQueryValueEx(hk, TEXT("skip_on_error"), NULL, NULL, (LPBYTE) &val, &buflen); if (ret == ERROR_SUCCESS && buflen == sizeof(val)) skip_on_error = val; RegCloseKey(hk); if (wpa_supplicant_add_iface(global, &iface) == NULL) { if (skip_on_error) wpa_printf(MSG_DEBUG, "Skipped interface '%s' due to " "initialization failure", iface.ifname); else return -1; } return 0; } static int wpa_supplicant_thread(void) { int exitcode; struct wpa_params params; struct wpa_global *global; HKEY hk, ihk; DWORD val, buflen, i; LONG ret; if (os_program_init()) return -1; os_memset(¶ms, 0, sizeof(params)); params.wpa_debug_level = MSG_INFO; ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX, 0, KEY_QUERY_VALUE, &hk); if (ret != ERROR_SUCCESS) { printf("Could not open wpa_supplicant registry key\n"); return -1; } buflen = sizeof(val); ret = RegQueryValueEx(hk, TEXT("debug_level"), NULL, NULL, (LPBYTE) &val, &buflen); if (ret == ERROR_SUCCESS && buflen == sizeof(val)) { params.wpa_debug_level = val; } buflen = sizeof(val); ret = RegQueryValueEx(hk, TEXT("debug_show_keys"), NULL, NULL, (LPBYTE) &val, &buflen); if (ret == ERROR_SUCCESS && buflen == sizeof(val)) { params.wpa_debug_show_keys = val; } buflen = sizeof(val); ret = RegQueryValueEx(hk, TEXT("debug_timestamp"), NULL, NULL, (LPBYTE) &val, &buflen); if (ret == ERROR_SUCCESS && buflen == sizeof(val)) { params.wpa_debug_timestamp = val; } buflen = sizeof(val); ret = RegQueryValueEx(hk, TEXT("debug_use_file"), NULL, NULL, (LPBYTE) &val, &buflen); if (ret == ERROR_SUCCESS && buflen == sizeof(val) && val) { params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt"; } exitcode = 0; global = wpa_supplicant_init(¶ms); if (global == NULL) { printf("Failed to initialize wpa_supplicant\n"); exitcode = -1; } ret = RegOpenKeyEx(hk, TEXT("interfaces"), 0, KEY_ENUMERATE_SUB_KEYS, &ihk); RegCloseKey(hk); if (ret != ERROR_SUCCESS) { printf("Could not open wpa_supplicant interfaces registry " "key\n"); return -1; } for (i = 0; ; i++) { TCHAR name[255]; DWORD namelen; namelen = 255; ret = RegEnumKeyEx(ihk, i, name, &namelen, NULL, NULL, NULL, NULL); if (ret == ERROR_NO_MORE_ITEMS) break; if (ret != ERROR_SUCCESS) { printf("RegEnumKeyEx failed: 0x%x\n", (unsigned int) ret); break; } if (namelen >= 255) namelen = 255 - 1; name[namelen] = '\0'; wpa_printf(MSG_DEBUG, "interface %d: %s\n", (int) i, name); if (read_interface(global, ihk, name) < 0) exitcode = -1; } RegCloseKey(ihk); if (exitcode == 0) exitcode = wpa_supplicant_run(global); wpa_supplicant_deinit(global); os_program_deinit(); return exitcode; } static DWORD svc_thread(LPDWORD param) { int ret = wpa_supplicant_thread(); svc_status.dwCurrentState = SERVICE_STOPPED; svc_status.dwWaitHint = 0; if (!SetServiceStatus(svc_status_handle, &svc_status)) { printf("SetServiceStatus() failed: %d\n", (int) GetLastError()); } return ret; } static int register_service(const TCHAR *exe) { SC_HANDLE svc, scm; SERVICE_DESCRIPTION sd; printf("Registering service: " TSTR "\n", WPASVC_NAME); scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE); if (!scm) { printf("OpenSCManager failed: %d\n", (int) GetLastError()); return -1; } svc = CreateService(scm, WPASVC_NAME, WPASVC_DISPLAY_NAME, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, exe, NULL, NULL, NULL, NULL, NULL); if (!svc) { printf("CreateService failed: %d\n\n", (int) GetLastError()); CloseServiceHandle(scm); return -1; } os_memset(&sd, 0, sizeof(sd)); sd.lpDescription = WPASVC_DESCRIPTION; if (!ChangeServiceConfig2(svc, SERVICE_CONFIG_DESCRIPTION, &sd)) { printf("ChangeServiceConfig2 failed: %d\n", (int) GetLastError()); /* This is not a fatal error, so continue anyway. */ } CloseServiceHandle(svc); CloseServiceHandle(scm); printf("Service registered successfully.\n"); return 0; } static int unregister_service(void) { SC_HANDLE svc, scm; SERVICE_STATUS status; printf("Unregistering service: " TSTR "\n", WPASVC_NAME); scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE); if (!scm) { printf("OpenSCManager failed: %d\n", (int) GetLastError()); return -1; } svc = OpenService(scm, WPASVC_NAME, SERVICE_ALL_ACCESS | DELETE); if (!svc) { printf("OpenService failed: %d\n\n", (int) GetLastError()); CloseServiceHandle(scm); return -1; } if (QueryServiceStatus(svc, &status)) { if (status.dwCurrentState != SERVICE_STOPPED) { printf("Service currently active - stopping " "service...\n"); if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) { printf("ControlService failed: %d\n", (int) GetLastError()); } Sleep(500); } } if (DeleteService(svc)) { printf("Service unregistered successfully.\n"); } else { printf("DeleteService failed: %d\n", (int) GetLastError()); } CloseServiceHandle(svc); CloseServiceHandle(scm); return 0; } static void WINAPI service_ctrl_handler(DWORD control_code) { switch (control_code) { case SERVICE_CONTROL_INTERROGATE: break; case SERVICE_CONTROL_SHUTDOWN: case SERVICE_CONTROL_STOP: svc_status.dwCurrentState = SERVICE_STOP_PENDING; svc_status.dwWaitHint = 2000; eloop_terminate(); SetEvent(kill_svc); break; } if (!SetServiceStatus(svc_status_handle, &svc_status)) { printf("SetServiceStatus() failed: %d\n", (int) GetLastError()); } } static void WINAPI service_start(DWORD argc, LPTSTR *argv) { DWORD id; svc_status_handle = RegisterServiceCtrlHandler(WPASVC_NAME, service_ctrl_handler); if (svc_status_handle == (SERVICE_STATUS_HANDLE) 0) { printf("RegisterServiceCtrlHandler failed: %d\n", (int) GetLastError()); return; } os_memset(&svc_status, 0, sizeof(svc_status)); svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; svc_status.dwCurrentState = SERVICE_START_PENDING; svc_status.dwWaitHint = 1000; if (!SetServiceStatus(svc_status_handle, &svc_status)) { printf("SetServiceStatus() failed: %d\n", (int) GetLastError()); return; } kill_svc = CreateEvent(0, TRUE, FALSE, 0); if (!kill_svc) { printf("CreateEvent failed: %d\n", (int) GetLastError()); return; } if (CreateThread(0, 0, (LPTHREAD_START_ROUTINE) svc_thread, 0, 0, &id) == 0) { printf("CreateThread failed: %d\n", (int) GetLastError()); return; } if (svc_status.dwCurrentState == SERVICE_START_PENDING) { svc_status.dwCurrentState = SERVICE_RUNNING; svc_status.dwWaitHint = 0; svc_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; } if (!SetServiceStatus(svc_status_handle, &svc_status)) { printf("SetServiceStatus() failed: %d\n", (int) GetLastError()); return; } /* wait until service gets killed */ WaitForSingleObject(kill_svc, INFINITE); } int main(int argc, char *argv[]) { SERVICE_TABLE_ENTRY dt[] = { { WPASVC_NAME, service_start }, { NULL, NULL } }; if (argc > 1) { if (os_strcmp(argv[1], "reg") == 0) { TCHAR *path; int ret; if (argc < 3) { path = os_malloc(MAX_PATH * sizeof(TCHAR)); if (path == NULL) return -1; if (!GetModuleFileName(NULL, path, MAX_PATH)) { printf("GetModuleFileName failed: " "%d\n", (int) GetLastError()); os_free(path); return -1; } } else { path = wpa_strdup_tchar(argv[2]); if (path == NULL) return -1; } ret = register_service(path); os_free(path); return ret; } else if (os_strcmp(argv[1], "unreg") == 0) { return unregister_service(); } else if (os_strcmp(argv[1], "app") == 0) { return wpa_supplicant_thread(); } } if (!StartServiceCtrlDispatcher(dt)) { printf("StartServiceCtrlDispatcher failed: %d\n", (int) GetLastError()); } return 0; } wpa_supplicant-2.2/wpa_supplicant/win_if_list.c0000664000175000017500000000735212343617166017731 0ustar jmjm/* * win_if_list - Display network interfaces with description (for Windows) * Copyright (c) 2004-2006, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. * * This small tool is for the Windows build to provide an easy way of fetching * a list of available network interfaces. */ #include "includes.h" #include #ifdef CONFIG_USE_NDISUIO #include #include #else /* CONFIG_USE_NDISUIO */ #include "pcap.h" #include #endif /* CONFIG_USE_NDISUIO */ #ifdef CONFIG_USE_NDISUIO /* from nuiouser.h */ #define FSCTL_NDISUIO_BASE FILE_DEVICE_NETWORK #define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \ CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access) #define IOCTL_NDISUIO_QUERY_BINDING \ _NDISUIO_CTL_CODE(0x203, METHOD_BUFFERED, \ FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_NDISUIO_BIND_WAIT \ _NDISUIO_CTL_CODE(0x204, METHOD_BUFFERED, \ FILE_READ_ACCESS | FILE_WRITE_ACCESS) typedef struct _NDISUIO_QUERY_BINDING { ULONG BindingIndex; ULONG DeviceNameOffset; ULONG DeviceNameLength; ULONG DeviceDescrOffset; ULONG DeviceDescrLength; } NDISUIO_QUERY_BINDING, *PNDISUIO_QUERY_BINDING; static HANDLE ndisuio_open(void) { DWORD written; HANDLE h; h = CreateFile(TEXT("\\\\.\\\\Ndisuio"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE); if (h == INVALID_HANDLE_VALUE) return h; #ifndef _WIN32_WCE if (!DeviceIoControl(h, IOCTL_NDISUIO_BIND_WAIT, NULL, 0, NULL, 0, &written, NULL)) { printf("IOCTL_NDISUIO_BIND_WAIT failed: %d", (int) GetLastError()); CloseHandle(h); return INVALID_HANDLE_VALUE; } #endif /* _WIN32_WCE */ return h; } static void ndisuio_query_bindings(HANDLE ndisuio) { NDISUIO_QUERY_BINDING *b; size_t blen = sizeof(*b) + 1024; int i, error; DWORD written; char name[256], desc[256]; WCHAR *pos; size_t j, len; b = malloc(blen); if (b == NULL) return; for (i = 0; ; i++) { memset(b, 0, blen); b->BindingIndex = i; if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_QUERY_BINDING, b, sizeof(NDISUIO_QUERY_BINDING), b, (DWORD) blen, &written, NULL)) { error = (int) GetLastError(); if (error == ERROR_NO_MORE_ITEMS) break; printf("IOCTL_NDISUIO_QUERY_BINDING failed: %d", error); break; } pos = (WCHAR *) ((char *) b + b->DeviceNameOffset); len = b->DeviceNameLength; if (len >= sizeof(name)) len = sizeof(name) - 1; for (j = 0; j < len; j++) name[j] = (char) pos[j]; name[len] = '\0'; pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset); len = b->DeviceDescrLength; if (len >= sizeof(desc)) len = sizeof(desc) - 1; for (j = 0; j < len; j++) desc[j] = (char) pos[j]; desc[len] = '\0'; printf("ifname: %s\ndescription: %s\n\n", name, desc); } free(b); } static void ndisuio_enum_bindings(void) { HANDLE ndisuio = ndisuio_open(); if (ndisuio == INVALID_HANDLE_VALUE) return; ndisuio_query_bindings(ndisuio); CloseHandle(ndisuio); } #else /* CONFIG_USE_NDISUIO */ static void show_dev(pcap_if_t *dev) { printf("ifname: %s\ndescription: %s\n\n", dev->name, dev->description); } static void pcap_enum_devs(void) { pcap_if_t *devs, *dev; char err[PCAP_ERRBUF_SIZE + 1]; if (pcap_findalldevs(&devs, err) < 0) { fprintf(stderr, "Error - pcap_findalldevs: %s\n", err); return; } for (dev = devs; dev; dev = dev->next) { show_dev(dev); } pcap_freealldevs(devs); } #endif /* CONFIG_USE_NDISUIO */ int main(int argc, char *argv[]) { #ifdef CONFIG_USE_NDISUIO ndisuio_enum_bindings(); #else /* CONFIG_USE_NDISUIO */ pcap_enum_devs(); #endif /* CONFIG_USE_NDISUIO */ return 0; } wpa_supplicant-2.2/wpa_supplicant/bgscan_learn.c0000664000175000017500000003471012343617166020037 0ustar jmjm/* * WPA Supplicant - background scan and roaming module: learn * Copyright (c) 2009-2010, 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 "eloop.h" #include "list.h" #include "common/ieee802_11_defs.h" #include "drivers/driver.h" #include "config_ssid.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "scan.h" #include "bgscan.h" struct bgscan_learn_bss { struct dl_list list; u8 bssid[ETH_ALEN]; int freq; u8 *neigh; /* num_neigh * ETH_ALEN buffer */ size_t num_neigh; }; struct bgscan_learn_data { struct wpa_supplicant *wpa_s; const struct wpa_ssid *ssid; int scan_interval; int signal_threshold; int short_interval; /* use if signal < threshold */ int long_interval; /* use if signal > threshold */ struct os_reltime last_bgscan; char *fname; struct dl_list bss; int *supp_freqs; int probe_idx; }; static void bss_free(struct bgscan_learn_bss *bss) { os_free(bss->neigh); os_free(bss); } static int bssid_in_array(u8 *array, size_t array_len, const u8 *bssid) { size_t i; if (array == NULL || array_len == 0) return 0; for (i = 0; i < array_len; i++) { if (os_memcmp(array + i * ETH_ALEN, bssid, ETH_ALEN) == 0) return 1; } return 0; } static void bgscan_learn_add_neighbor(struct bgscan_learn_bss *bss, const u8 *bssid) { u8 *n; if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) return; if (bssid_in_array(bss->neigh, bss->num_neigh, bssid)) return; n = os_realloc_array(bss->neigh, bss->num_neigh + 1, ETH_ALEN); if (n == NULL) return; os_memcpy(n + bss->num_neigh * ETH_ALEN, bssid, ETH_ALEN); bss->neigh = n; bss->num_neigh++; } static struct bgscan_learn_bss * bgscan_learn_get_bss( struct bgscan_learn_data *data, const u8 *bssid) { struct bgscan_learn_bss *bss; dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) { if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) return bss; } return NULL; } static int bgscan_learn_load(struct bgscan_learn_data *data) { FILE *f; char buf[128]; struct bgscan_learn_bss *bss; if (data->fname == NULL) return 0; f = fopen(data->fname, "r"); if (f == NULL) return 0; wpa_printf(MSG_DEBUG, "bgscan learn: Loading data from %s", data->fname); if (fgets(buf, sizeof(buf), f) == NULL || os_strncmp(buf, "wpa_supplicant-bgscan-learn\n", 28) != 0) { wpa_printf(MSG_INFO, "bgscan learn: Invalid data file %s", data->fname); fclose(f); return -1; } while (fgets(buf, sizeof(buf), f)) { if (os_strncmp(buf, "BSS ", 4) == 0) { bss = os_zalloc(sizeof(*bss)); if (!bss) continue; if (hwaddr_aton(buf + 4, bss->bssid) < 0) { bss_free(bss); continue; } bss->freq = atoi(buf + 4 + 18); dl_list_add(&data->bss, &bss->list); wpa_printf(MSG_DEBUG, "bgscan learn: Loaded BSS " "entry: " MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq); } if (os_strncmp(buf, "NEIGHBOR ", 9) == 0) { u8 addr[ETH_ALEN]; if (hwaddr_aton(buf + 9, addr) < 0) continue; bss = bgscan_learn_get_bss(data, addr); if (bss == NULL) continue; if (hwaddr_aton(buf + 9 + 18, addr) < 0) continue; bgscan_learn_add_neighbor(bss, addr); } } fclose(f); return 0; } static void bgscan_learn_save(struct bgscan_learn_data *data) { FILE *f; struct bgscan_learn_bss *bss; if (data->fname == NULL) return; wpa_printf(MSG_DEBUG, "bgscan learn: Saving data to %s", data->fname); f = fopen(data->fname, "w"); if (f == NULL) return; fprintf(f, "wpa_supplicant-bgscan-learn\n"); dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) { fprintf(f, "BSS " MACSTR " %d\n", MAC2STR(bss->bssid), bss->freq); } dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) { size_t i; for (i = 0; i < bss->num_neigh; i++) { fprintf(f, "NEIGHBOR " MACSTR " " MACSTR "\n", MAC2STR(bss->bssid), MAC2STR(bss->neigh + i * ETH_ALEN)); } } fclose(f); } static int in_array(int *array, int val) { int i; if (array == NULL) return 0; for (i = 0; array[i]; i++) { if (array[i] == val) return 1; } return 0; } static int * bgscan_learn_get_freqs(struct bgscan_learn_data *data, size_t *count) { struct bgscan_learn_bss *bss; int *freqs = NULL, *n; *count = 0; dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) { if (in_array(freqs, bss->freq)) continue; n = os_realloc_array(freqs, *count + 2, sizeof(int)); if (n == NULL) return freqs; freqs = n; freqs[*count] = bss->freq; (*count)++; freqs[*count] = 0; } return freqs; } static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data, int *freqs, size_t count) { int idx, *n; if (data->supp_freqs == NULL) return freqs; idx = data->probe_idx; do { if (!in_array(freqs, data->supp_freqs[idx])) { wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq " "%u", data->supp_freqs[idx]); data->probe_idx = idx + 1; if (data->supp_freqs[data->probe_idx] == 0) data->probe_idx = 0; n = os_realloc_array(freqs, count + 2, sizeof(int)); if (n == NULL) return freqs; freqs = n; freqs[count] = data->supp_freqs[idx]; count++; freqs[count] = 0; break; } idx++; if (data->supp_freqs[idx] == 0) idx = 0; } while (idx != data->probe_idx); return freqs; } static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx) { struct bgscan_learn_data *data = eloop_ctx; struct wpa_supplicant *wpa_s = data->wpa_s; struct wpa_driver_scan_params params; int *freqs = NULL; size_t count, i; char msg[100], *pos; os_memset(¶ms, 0, sizeof(params)); params.num_ssids = 1; params.ssids[0].ssid = data->ssid->ssid; params.ssids[0].ssid_len = data->ssid->ssid_len; if (data->ssid->scan_freq) params.freqs = data->ssid->scan_freq; else { freqs = bgscan_learn_get_freqs(data, &count); wpa_printf(MSG_DEBUG, "bgscan learn: BSSes in this ESS have " "been seen on %u channels", (unsigned int) count); freqs = bgscan_learn_get_probe_freq(data, freqs, count); msg[0] = '\0'; pos = msg; for (i = 0; freqs && freqs[i]; i++) { int ret; ret = os_snprintf(pos, msg + sizeof(msg) - pos, " %d", freqs[i]); if (ret < 0 || ret >= msg + sizeof(msg) - pos) break; pos += ret; } pos[0] = '\0'; wpa_printf(MSG_DEBUG, "bgscan learn: Scanning frequencies:%s", msg); params.freqs = freqs; } wpa_printf(MSG_DEBUG, "bgscan learn: Request a background scan"); if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) { wpa_printf(MSG_DEBUG, "bgscan learn: Failed to trigger scan"); eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout, data, NULL); } else os_get_reltime(&data->last_bgscan); os_free(freqs); } static int bgscan_learn_get_params(struct bgscan_learn_data *data, const char *params) { const char *pos; if (params == NULL) return 0; data->short_interval = atoi(params); pos = os_strchr(params, ':'); if (pos == NULL) return 0; pos++; data->signal_threshold = atoi(pos); pos = os_strchr(pos, ':'); if (pos == NULL) { wpa_printf(MSG_ERROR, "bgscan learn: Missing scan interval " "for high signal"); return -1; } pos++; data->long_interval = atoi(pos); pos = os_strchr(pos, ':'); if (pos) { pos++; data->fname = os_strdup(pos); } return 0; } static int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s) { struct hostapd_hw_modes *modes; int i, j, *freqs = NULL, *n; size_t count = 0; modes = wpa_s->hw.modes; if (modes == NULL) return NULL; for (i = 0; i < wpa_s->hw.num_modes; i++) { for (j = 0; j < modes[i].num_channels; j++) { if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED) continue; /* some hw modes (e.g. 11b & 11g) contain same freqs */ if (in_array(freqs, modes[i].channels[j].freq)) continue; n = os_realloc_array(freqs, count + 2, sizeof(int)); if (n == NULL) continue; freqs = n; freqs[count] = modes[i].channels[j].freq; count++; freqs[count] = 0; } } return freqs; } static void * bgscan_learn_init(struct wpa_supplicant *wpa_s, const char *params, const struct wpa_ssid *ssid) { struct bgscan_learn_data *data; data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; dl_list_init(&data->bss); data->wpa_s = wpa_s; data->ssid = ssid; if (bgscan_learn_get_params(data, params) < 0) { os_free(data->fname); os_free(data); return NULL; } if (data->short_interval <= 0) data->short_interval = 30; if (data->long_interval <= 0) data->long_interval = 30; if (bgscan_learn_load(data) < 0) { os_free(data->fname); os_free(data); return NULL; } wpa_printf(MSG_DEBUG, "bgscan learn: Signal strength threshold %d " "Short bgscan interval %d Long bgscan interval %d", data->signal_threshold, data->short_interval, data->long_interval); if (data->signal_threshold && wpa_drv_signal_monitor(wpa_s, data->signal_threshold, 4) < 0) { wpa_printf(MSG_ERROR, "bgscan learn: Failed to enable " "signal strength monitoring"); } data->supp_freqs = bgscan_learn_get_supp_freqs(wpa_s); data->scan_interval = data->short_interval; if (data->signal_threshold) { /* Poll for signal info to set initial scan interval */ struct wpa_signal_info siginfo; if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 && siginfo.current_signal >= data->signal_threshold) data->scan_interval = data->long_interval; } eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout, data, NULL); /* * This function is called immediately after an association, so it is * reasonable to assume that a scan was completed recently. This makes * us skip an immediate new scan in cases where the current signal * level is below the bgscan threshold. */ os_get_reltime(&data->last_bgscan); return data; } static void bgscan_learn_deinit(void *priv) { struct bgscan_learn_data *data = priv; struct bgscan_learn_bss *bss, *n; bgscan_learn_save(data); eloop_cancel_timeout(bgscan_learn_timeout, data, NULL); if (data->signal_threshold) wpa_drv_signal_monitor(data->wpa_s, 0, 0); os_free(data->fname); dl_list_for_each_safe(bss, n, &data->bss, struct bgscan_learn_bss, list) { dl_list_del(&bss->list); bss_free(bss); } os_free(data->supp_freqs); os_free(data); } static int bgscan_learn_bss_match(struct bgscan_learn_data *data, struct wpa_scan_res *bss) { const u8 *ie; ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); if (ie == NULL) return 0; if (data->ssid->ssid_len != ie[1] || os_memcmp(data->ssid->ssid, ie + 2, ie[1]) != 0) return 0; /* SSID mismatch */ return 1; } static int bgscan_learn_notify_scan(void *priv, struct wpa_scan_results *scan_res) { struct bgscan_learn_data *data = priv; size_t i, j; #define MAX_BSS 50 u8 bssid[MAX_BSS * ETH_ALEN]; size_t num_bssid = 0; wpa_printf(MSG_DEBUG, "bgscan learn: scan result notification"); eloop_cancel_timeout(bgscan_learn_timeout, data, NULL); eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout, data, NULL); for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *res = scan_res->res[i]; if (!bgscan_learn_bss_match(data, res)) continue; if (num_bssid < MAX_BSS) { os_memcpy(bssid + num_bssid * ETH_ALEN, res->bssid, ETH_ALEN); num_bssid++; } } wpa_printf(MSG_DEBUG, "bgscan learn: %u matching BSSes in scan " "results", (unsigned int) num_bssid); for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *res = scan_res->res[i]; struct bgscan_learn_bss *bss; if (!bgscan_learn_bss_match(data, res)) continue; bss = bgscan_learn_get_bss(data, res->bssid); if (bss && bss->freq != res->freq) { wpa_printf(MSG_DEBUG, "bgscan learn: Update BSS " MACSTR " freq %d -> %d", MAC2STR(res->bssid), bss->freq, res->freq); bss->freq = res->freq; } else if (!bss) { wpa_printf(MSG_DEBUG, "bgscan learn: Add BSS " MACSTR " freq=%d", MAC2STR(res->bssid), res->freq); bss = os_zalloc(sizeof(*bss)); if (!bss) continue; os_memcpy(bss->bssid, res->bssid, ETH_ALEN); bss->freq = res->freq; dl_list_add(&data->bss, &bss->list); } for (j = 0; j < num_bssid; j++) { u8 *addr = bssid + j * ETH_ALEN; bgscan_learn_add_neighbor(bss, addr); } } /* * A more advanced bgscan could process scan results internally, select * the BSS and request roam if needed. This sample uses the existing * BSS/ESS selection routine. Change this to return 1 if selection is * done inside the bgscan module. */ return 0; } static void bgscan_learn_notify_beacon_loss(void *priv) { wpa_printf(MSG_DEBUG, "bgscan learn: beacon loss"); /* TODO: speed up background scanning */ } static void bgscan_learn_notify_signal_change(void *priv, int above, int current_signal, int current_noise, int current_txrate) { struct bgscan_learn_data *data = priv; int scan = 0; struct os_reltime now; if (data->short_interval == data->long_interval || data->signal_threshold == 0) return; wpa_printf(MSG_DEBUG, "bgscan learn: signal level changed " "(above=%d current_signal=%d current_noise=%d " "current_txrate=%d)", above, current_signal, current_noise, current_txrate); if (data->scan_interval == data->long_interval && !above) { wpa_printf(MSG_DEBUG, "bgscan learn: Start using short bgscan " "interval"); data->scan_interval = data->short_interval; os_get_reltime(&now); if (now.sec > data->last_bgscan.sec + 1) scan = 1; } else if (data->scan_interval == data->short_interval && above) { wpa_printf(MSG_DEBUG, "bgscan learn: Start using long bgscan " "interval"); data->scan_interval = data->long_interval; eloop_cancel_timeout(bgscan_learn_timeout, data, NULL); eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout, data, NULL); } else if (!above) { /* * Signal dropped further 4 dB. Request a new scan if we have * not yet scanned in a while. */ os_get_reltime(&now); if (now.sec > data->last_bgscan.sec + 10) scan = 1; } if (scan) { wpa_printf(MSG_DEBUG, "bgscan learn: Trigger immediate scan"); eloop_cancel_timeout(bgscan_learn_timeout, data, NULL); eloop_register_timeout(0, 0, bgscan_learn_timeout, data, NULL); } } const struct bgscan_ops bgscan_learn_ops = { .name = "learn", .init = bgscan_learn_init, .deinit = bgscan_learn_deinit, .notify_scan = bgscan_learn_notify_scan, .notify_beacon_loss = bgscan_learn_notify_beacon_loss, .notify_signal_change = bgscan_learn_notify_signal_change, }; wpa_supplicant-2.2/wpa_supplicant/ibss_rsn.h0000664000175000017500000000325512343617166017250 0ustar jmjm/* * wpa_supplicant - IBSS RSN * Copyright (c) 2009, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef IBSS_RSN_H #define IBSS_RSN_H struct ibss_rsn; /* not authenticated */ #define IBSS_RSN_AUTH_NOT_AUTHENTICATED 0x00 /* remote peer sent an EAPOL message */ #define IBSS_RSN_AUTH_EAPOL_BY_PEER 0x01 /* we sent an AUTH message with seq 1 */ #define IBSS_RSN_AUTH_BY_US 0x02 /* we sent an EAPOL message */ #define IBSS_RSN_AUTH_EAPOL_BY_US 0x04 /* PTK derived as supplicant */ #define IBSS_RSN_SET_PTK_SUPP 0x08 /* PTK derived as authenticator */ #define IBSS_RSN_SET_PTK_AUTH 0x10 /* PTK completion reported */ #define IBSS_RSN_REPORTED_PTK 0x20 struct ibss_rsn_peer { struct ibss_rsn_peer *next; struct ibss_rsn *ibss_rsn; u8 addr[ETH_ALEN]; struct wpa_sm *supp; enum wpa_states supp_state; u8 supp_ie[80]; size_t supp_ie_len; struct wpa_state_machine *auth; int authentication_status; struct os_reltime own_auth_tx; }; struct ibss_rsn { struct wpa_supplicant *wpa_s; struct wpa_authenticator *auth_group; struct ibss_rsn_peer *peers; u8 psk[PMK_LEN]; }; struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s); void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn); int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr); void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac); int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, const u8 *buf, size_t len); void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk); void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame, size_t len); #endif /* IBSS_RSN_H */ wpa_supplicant-2.2/wpa_supplicant/README-HS200000664000175000017500000004611312343617166016607 0ustar jmjmwpa_supplicant and Hotspot 2.0 ============================== This document describe how the IEEE 802.11u Interworking and Wi-Fi Hotspot 2.0 (Release 1) implementation in wpa_supplicant can be configured and how an external component on the client e.g., management GUI or Wi-Fi framework) is used to manage this functionality. Introduction to Wi-Fi Hotspot 2.0 --------------------------------- Hotspot 2.0 is the name of the Wi-Fi Alliance specification that is used in the Wi-Fi CERTIFIED Passpoint program. More information about this is available in this white paper: http://www.wi-fi.org/knowledge-center/white-papers/wi-fi-certified-passpoint%E2%84%A2-new-program-wi-fi-alliance%C2%AE-enable-seamless The Hotspot 2.0 specification is also available from WFA: https://www.wi-fi.org/knowledge-center/published-specifications The core Interworking functionality (network selection, GAS/ANQP) were standardized in IEEE Std 802.11u-2011 which is now part of the IEEE Std 802.11-2012. wpa_supplicant network selection -------------------------------- Interworking support added option for configuring credentials that can work with multiple networks as an alternative to configuration of network blocks (e.g., per-SSID parameters). When requested to perform network selection, wpa_supplicant picks the highest priority enabled network block or credential. If a credential is picked (based on ANQP information from APs), a temporary network block is created automatically for the matching network. This temporary network block is used similarly to the network blocks that can be configured by the user, but it is not stored into the configuration file and is meant to be used only for temporary period of time since a new one can be created whenever needed based on ANQP information and the credential. By default, wpa_supplicant is not using automatic network selection unless requested explicitly with the interworking_select command. This can be changed with the auto_interworking=1 parameter to perform network selection automatically whenever trying to find a network for connection and none of the enabled network blocks match with the scan results. This case works similarly to "interworking_select auto", i.e., wpa_supplicant will internally determine which network or credential is going to be used based on configured priorities, scan results, and ANQP information. wpa_supplicant configuration ---------------------------- Interworking and Hotspot 2.0 functionality are optional components that need to be enabled in the wpa_supplicant build configuration (.config). This is done by adding following parameters into that file: CONFIG_INTERWORKING=y CONFIG_HS20=y It should be noted that this functionality requires a driver that supports GAS/ANQP operations. This uses the same design as P2P, i.e., Action frame processing and building in user space within wpa_supplicant. The Linux nl80211 driver interface provides the needed functionality for this. There are number of run-time configuration parameters (e.g., in wpa_supplicant.conf when using the configuration file) that can be used to control Hotspot 2.0 operations. # Enable Interworking interworking=1 # Enable Hotspot 2.0 hs20=1 # Parameters for controlling scanning # Homogenous ESS identifier # If this is set, scans will be used to request response only from BSSes # belonging to the specified Homogeneous ESS. This is used only if interworking # is enabled. #hessid=00:11:22:33:44:55 # Access Network Type # When Interworking is enabled, scans can be limited to APs that advertise the # specified Access Network Type (0..15; with 15 indicating wildcard match). # This value controls the Access Network Type value in Probe Request frames. #access_network_type=15 # Automatic network selection behavior # 0 = do not automatically go through Interworking network selection # (i.e., require explicit interworking_select command for this; default) # 1 = perform Interworking network selection if one or more # credentials have been configured and scan did not find a # matching network block #auto_interworking=0 Credentials can be pre-configured for automatic network selection: # credential block # # Each credential used for automatic network selection is configured as a set # of parameters that are compared to the information advertised by the APs when # interworking_select and interworking_connect commands are used. # # credential fields: # # temporary: Whether this credential is temporary and not to be saved # # priority: Priority group # By default, all networks and credentials get the same priority group # (0). This field can be used to give higher priority for credentials # (and similarly in struct wpa_ssid for network blocks) to change the # Interworking automatic networking selection behavior. The matching # network (based on either an enabled network block or a credential) # with the highest priority value will be selected. # # pcsc: Use PC/SC and SIM/USIM card # # realm: Home Realm for Interworking # # username: Username for Interworking network selection # # password: Password for Interworking network selection # # ca_cert: CA certificate for Interworking network selection # # client_cert: File path to client certificate file (PEM/DER) # This field is used with Interworking networking selection for a case # where client certificate/private key is used for authentication # (EAP-TLS). Full path to the file should be used since working # directory may change when wpa_supplicant is run in the background. # # Alternatively, a named configuration blob can be used by setting # this to blob://blob_name. # # private_key: File path to client private key file (PEM/DER/PFX) # When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be # commented out. Both the private key and certificate will be read # from the PKCS#12 file in this case. Full path to the file should be # used since working directory may change when wpa_supplicant is run # in the background. # # Windows certificate store can be used by leaving client_cert out and # configuring private_key in one of the following formats: # # cert://substring_to_match # # hash://certificate_thumbprint_in_hex # # For example: private_key="hash://63093aa9c47f56ae88334c7b65a4" # # Note that when running wpa_supplicant as an application, the user # certificate store (My user account) is used, whereas computer store # (Computer account) is used when running wpasvc as a service. # # Alternatively, a named configuration blob can be used by setting # this to blob://blob_name. # # private_key_passwd: Password for private key file # # imsi: IMSI in | | '-' | format # # milenage: Milenage parameters for SIM/USIM simulator in :: # format # # domain_suffix_match: Constraint for server domain name # If set, this FQDN is used as a suffix match requirement for the AAA # server certificate in SubjectAltName dNSName element(s). If a # matching dNSName is found, this constraint is met. If no dNSName # values are present, this constraint is matched against SubjetName CN # using same suffix match comparison. Suffix match here means that the # host/domain name is compared one label at a time starting from the # top-level domain and all the labels in @domain_suffix_match shall be # included in the certificate. The certificate may include additional # sub-level labels in addition to the required labels. # # For example, domain_suffix_match=example.com would match # test.example.com but would not match test-example.com. # # domain: Home service provider FQDN(s) # This is used to compare against the Domain Name List to figure out # whether the AP is operated by the Home SP. Multiple domain entries can # be used to configure alternative FQDNs that will be considered home # networks. # # roaming_consortium: Roaming Consortium OI # If roaming_consortium_len is non-zero, this field contains the # Roaming Consortium OI that can be used to determine which access # points support authentication with this credential. This is an # alternative to the use of the realm parameter. When using Roaming # Consortium to match the network, the EAP parameters need to be # pre-configured with the credential since the NAI Realm information # may not be available or fetched. # # eap: Pre-configured EAP method # This optional field can be used to specify which EAP method will be # used with this credential. If not set, the EAP method is selected # automatically based on ANQP information (e.g., NAI Realm). # # phase1: Pre-configure Phase 1 (outer authentication) parameters # This optional field is used with like the 'eap' parameter. # # phase2: Pre-configure Phase 2 (inner authentication) parameters # This optional field is used with like the 'eap' parameter. # # excluded_ssid: Excluded SSID # This optional field can be used to excluded specific SSID(s) from # matching with the network. Multiple entries can be used to specify more # than one SSID. # # roaming_partner: Roaming partner information # This optional field can be used to configure preferences between roaming # partners. The field is a string in following format: # ,<0/1 exact match>,,<* or country code> # (non-exact match means any subdomain matches the entry; priority is in # 0..255 range with 0 being the highest priority) # # update_identifier: PPS MO ID # (Hotspot 2.0 PerProviderSubscription/UpdateIdentifier) # # provisioning_sp: FQDN of the SP that provisioned the credential # This optional field can be used to keep track of the SP that provisioned # the credential to find the PPS MO (./Wi-Fi/). # # sp_priority: Credential priority within a provisioning SP # This is the priority of the credential among all credentials # provisionined by the same SP (i.e., for entries that have identical # provisioning_sp value). The range of this priority is 0-255 with 0 # being the highest and 255 the lower priority. # # Minimum backhaul threshold (PPS//Policy/MinBackhauldThreshold/*) # These fields can be used to specify minimum download/upload backhaul # bandwidth that is preferred for the credential. This constraint is # ignored if the AP does not advertise WAN Metrics information or if the # limit would prevent any connection. Values are in kilobits per second. # min_dl_bandwidth_home # min_ul_bandwidth_home # min_dl_bandwidth_roaming # min_ul_bandwidth_roaming # # max_bss_load: Maximum BSS Load Channel Utilization (1..255) # (PPS//Policy/MaximumBSSLoadValue) # This value is used as the maximum channel utilization for network # selection purposes for home networks. If the AP does not advertise # BSS Load or if the limit would prevent any connection, this constraint # will be ignored. # # req_conn_capab: Required connection capability # (PPS//Policy/RequiredProtoPortTuple) # This value is used to configure set of required protocol/port pairs that # a roaming network shall support (include explicitly in Connection # Capability ANQP element). This constraint is ignored if the AP does not # advertise Connection Capability or if this constraint would prevent any # network connection. This policy is not used in home networks. # Format: [: remove_network all OK > remove_cred all OK Add a username/password credential: > add_cred 0 > set_cred 0 realm "mail.example.com" OK > set_cred 0 username "username" OK > set_cred 0 password "password" OK > set_cred 0 priority 1 OK > set_cred 0 temporary 1 OK Add a SIM credential using a simulated SIM/USIM card for testing: > add_cred 1 > set_cred 1 imsi "23456-0000000000" OK > set_cred 1 milenage "90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123" OK > set_cred 1 priority 1 OK Note: the return value of add_cred is used as the first argument to the following set_cred commands. Add a SIM credential using a external SIM/USIM processing: > set external_sim 1 OK > add_cred 1 > set_cred 1 imsi "23456-0000000000" OK > set_cred 1 eap SIM OK Add a WPA2-Enterprise network: > add_network 0 > set_network 0 key_mgmt WPA-EAP OK > set_network 0 ssid "enterprise" OK > set_network 0 eap TTLS OK > set_network 0 anonymous_identity "anonymous" OK > set_network 0 identity "user" OK > set_network 0 password "password" OK > set_network 0 priority 0 OK > enable_network 0 no-connect OK Add an open network: > add_network 3 > set_network 3 key_mgmt NONE OK > set_network 3 ssid "coffee-shop" OK > select_network 3 OK Note: the return value of add_network is used as the first argument to the following set_network commands. The preferred credentials/networks can be indicated with the priority parameter (1 is higher priority than 0). Interworking network selection can be started with interworking_select command. This instructs wpa_supplicant to run a network scan and iterate through the discovered APs to request ANQP information from the APs that advertise support for Interworking/Hotspot 2.0: > interworking_select OK <3>Starting ANQP fetch for 02:00:00:00:01:00 <3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list <3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list <3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List <3>ANQP fetch completed <3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown INTERWORKING-AP event messages indicate the APs that support network selection and for which there is a matching credential. interworking_connect command can be used to select a network to connect with: > interworking_connect 02:00:00:00:01:00 OK <3>CTRL-EVENT-SCAN-RESULTS <3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz) <3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz) <3>Associated with 02:00:00:00:01:00 <3>CTRL-EVENT-EAP-STARTED EAP authentication started <3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21 <3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected <3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully <3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP] <3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (auth) [id=0 id_str=] wpa_supplicant creates a temporary network block for the selected network based on the configured credential and ANQP information from the AP: > list_networks network id / ssid / bssid / flags 0 Example Network any [CURRENT] > get_network 0 key_mgmt WPA-EAP > get_network 0 eap TTLS Alternatively to using an external program to select the network, "interworking_select auto" command can be used to request wpa_supplicant to select which network to use based on configured priorities: > remove_network all OK <3>CTRL-EVENT-DISCONNECTED bssid=02:00:00:00:01:00 reason=1 locally_generated=1 > interworking_select auto OK <3>Starting ANQP fetch for 02:00:00:00:01:00 <3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list <3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list <3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List <3>ANQP fetch completed <3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown <3>CTRL-EVENT-SCAN-RESULTS <3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz) <3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz) <3>Associated with 02:00:00:00:01:00 <3>CTRL-EVENT-EAP-STARTED EAP authentication started <3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21 <3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected <3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully <3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP] <3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (reauth) [id=0 id_str=] The connection status can be shown with the status command: > status bssid=02:00:00:00:01:00 ssid=Example Network id=0 mode=station pairwise_cipher=CCMP <--- link layer security indication group_cipher=CCMP key_mgmt=WPA2/IEEE 802.1X/EAP wpa_state=COMPLETED p2p_device_address=02:00:00:00:00:00 address=02:00:00:00:00:00 hs20=1 <--- HS 2.0 indication Supplicant PAE state=AUTHENTICATED suppPortStatus=Authorized EAP state=SUCCESS selectedMethod=21 (EAP-TTLS) EAP TLS cipher=AES-128-SHA EAP-TTLSv0 Phase2 method=PAP > status bssid=02:00:00:00:02:00 ssid=coffee-shop id=3 mode=station pairwise_cipher=NONE group_cipher=NONE key_mgmt=NONE wpa_state=COMPLETED p2p_device_address=02:00:00:00:00:00 address=02:00:00:00:00:00 Note: The Hotspot 2.0 indication is shown as "hs20=1" in the status command output. Link layer security is indicated with the pairwise_cipher (CCMP = secure, NONE = no encryption used). Also the scan results include the Hotspot 2.0 indication: > scan_results bssid / frequency / signal level / flags / ssid 02:00:00:00:01:00 2412 -30 [WPA2-EAP-CCMP][ESS][HS20] Example Network ANQP information for the BSS can be fetched using the BSS command: > bss 02:00:00:00:01:00 id=1 bssid=02:00:00:00:01:00 freq=2412 beacon_int=100 capabilities=0x0411 qual=0 noise=-92 level=-30 tsf=1345573286517276 age=105 ie=000f4578616d706c65204e6574776f726b010882848b960c1218240301012a010432043048606c30140100000fac040100000fac040100000fac0100007f04000000806b091e07010203040506076c027f006f1001531122331020304050010203040506dd05506f9a1000 flags=[WPA2-EAP-CCMP][ESS][HS20] ssid=Example Network anqp_roaming_consortium=031122330510203040500601020304050603fedcba ANQP queries can also be requested with the anqp_get and hs20_anqp_get commands: > anqp_get 02:00:00:00:01:00 261 OK <3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list > hs20_anqp_get 02:00:00:00:01:00 2 OK <3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List In addition, fetch_anqp command can be used to request similar set of ANQP queries to be done as is run as part of interworking_select: > scan OK <3>CTRL-EVENT-SCAN-RESULTS > fetch_anqp OK <3>Starting ANQP fetch for 02:00:00:00:01:00 <3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list <3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list <3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List <3>ANQP fetch completed wpa_supplicant-2.2/wpa_supplicant/wpas_glue.h0000664000175000017500000000137512343617166017415 0ustar jmjm/* * WPA Supplicant - Glue code to setup EAPOL and RSN modules * Copyright (c) 2003-2008, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef WPAS_GLUE_H #define WPAS_GLUE_H enum wpa_ctrl_req_type; int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s); int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s); void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field, const char *default_txt, const char **txt); enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field); #endif /* WPAS_GLUE_H */ wpa_supplicant-2.2/wpa_supplicant/bgscan_simple.c0000664000175000017500000002030512343617166020222 0ustar jmjm/* * WPA Supplicant - background scan and roaming module: simple * Copyright (c) 2009-2010, 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 "eloop.h" #include "drivers/driver.h" #include "config_ssid.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "scan.h" #include "bgscan.h" struct bgscan_simple_data { struct wpa_supplicant *wpa_s; const struct wpa_ssid *ssid; int scan_interval; int signal_threshold; int short_scan_count; /* counter for scans using short scan interval */ int max_short_scans; /* maximum times we short-scan before back-off */ int short_interval; /* use if signal < threshold */ int long_interval; /* use if signal > threshold */ struct os_reltime last_bgscan; }; static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx) { struct bgscan_simple_data *data = eloop_ctx; struct wpa_supplicant *wpa_s = data->wpa_s; struct wpa_driver_scan_params params; os_memset(¶ms, 0, sizeof(params)); params.num_ssids = 1; params.ssids[0].ssid = data->ssid->ssid; params.ssids[0].ssid_len = data->ssid->ssid_len; params.freqs = data->ssid->scan_freq; /* * A more advanced bgscan module would learn about most like channels * over time and request scans only for some channels (probing others * every now and then) to reduce effect on the data connection. */ wpa_printf(MSG_DEBUG, "bgscan simple: Request a background scan"); if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) { wpa_printf(MSG_DEBUG, "bgscan simple: Failed to trigger scan"); eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout, data, NULL); } else { if (data->scan_interval == data->short_interval) { data->short_scan_count++; /* * Spend at most the duration of a long scan interval * scanning at the short scan interval. After that, * revert to the long scan interval. */ if (data->short_scan_count > data->max_short_scans) { data->scan_interval = data->long_interval; wpa_printf(MSG_DEBUG, "bgscan simple: Backing " "off to long scan interval"); } } else if (data->short_scan_count > 0) { /* * If we lasted a long scan interval without any * CQM triggers, decrease the short-scan count, * which allows 1 more short-scan interval to * occur in the future when CQM triggers. */ data->short_scan_count--; } os_get_reltime(&data->last_bgscan); } } static int bgscan_simple_get_params(struct bgscan_simple_data *data, const char *params) { const char *pos; if (params == NULL) return 0; data->short_interval = atoi(params); pos = os_strchr(params, ':'); if (pos == NULL) return 0; pos++; data->signal_threshold = atoi(pos); pos = os_strchr(pos, ':'); if (pos == NULL) { wpa_printf(MSG_ERROR, "bgscan simple: Missing scan interval " "for high signal"); return -1; } pos++; data->long_interval = atoi(pos); return 0; } static void * bgscan_simple_init(struct wpa_supplicant *wpa_s, const char *params, const struct wpa_ssid *ssid) { struct bgscan_simple_data *data; data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; data->wpa_s = wpa_s; data->ssid = ssid; if (bgscan_simple_get_params(data, params) < 0) { os_free(data); return NULL; } if (data->short_interval <= 0) data->short_interval = 30; if (data->long_interval <= 0) data->long_interval = 30; wpa_printf(MSG_DEBUG, "bgscan simple: Signal strength threshold %d " "Short bgscan interval %d Long bgscan interval %d", data->signal_threshold, data->short_interval, data->long_interval); if (data->signal_threshold && wpa_drv_signal_monitor(wpa_s, data->signal_threshold, 4) < 0) { wpa_printf(MSG_ERROR, "bgscan simple: Failed to enable " "signal strength monitoring"); } data->scan_interval = data->short_interval; data->max_short_scans = data->long_interval / data->short_interval + 1; if (data->signal_threshold) { /* Poll for signal info to set initial scan interval */ struct wpa_signal_info siginfo; if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 && siginfo.current_signal >= data->signal_threshold) data->scan_interval = data->long_interval; } wpa_printf(MSG_DEBUG, "bgscan simple: Init scan interval: %d", data->scan_interval); eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout, data, NULL); /* * This function is called immediately after an association, so it is * reasonable to assume that a scan was completed recently. This makes * us skip an immediate new scan in cases where the current signal * level is below the bgscan threshold. */ os_get_reltime(&data->last_bgscan); return data; } static void bgscan_simple_deinit(void *priv) { struct bgscan_simple_data *data = priv; eloop_cancel_timeout(bgscan_simple_timeout, data, NULL); if (data->signal_threshold) wpa_drv_signal_monitor(data->wpa_s, 0, 0); os_free(data); } static int bgscan_simple_notify_scan(void *priv, struct wpa_scan_results *scan_res) { struct bgscan_simple_data *data = priv; wpa_printf(MSG_DEBUG, "bgscan simple: scan result notification"); eloop_cancel_timeout(bgscan_simple_timeout, data, NULL); eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout, data, NULL); /* * A more advanced bgscan could process scan results internally, select * the BSS and request roam if needed. This sample uses the existing * BSS/ESS selection routine. Change this to return 1 if selection is * done inside the bgscan module. */ return 0; } static void bgscan_simple_notify_beacon_loss(void *priv) { wpa_printf(MSG_DEBUG, "bgscan simple: beacon loss"); /* TODO: speed up background scanning */ } static void bgscan_simple_notify_signal_change(void *priv, int above, int current_signal, int current_noise, int current_txrate) { struct bgscan_simple_data *data = priv; int scan = 0; struct os_reltime now; if (data->short_interval == data->long_interval || data->signal_threshold == 0) return; wpa_printf(MSG_DEBUG, "bgscan simple: signal level changed " "(above=%d current_signal=%d current_noise=%d " "current_txrate=%d))", above, current_signal, current_noise, current_txrate); if (data->scan_interval == data->long_interval && !above) { wpa_printf(MSG_DEBUG, "bgscan simple: Start using short " "bgscan interval"); data->scan_interval = data->short_interval; os_get_reltime(&now); if (now.sec > data->last_bgscan.sec + 1 && data->short_scan_count <= data->max_short_scans) /* * If we haven't just previously (<1 second ago) * performed a scan, and we haven't depleted our * budget for short-scans, perform a scan * immediately. */ scan = 1; else if (data->last_bgscan.sec + data->long_interval > now.sec + data->scan_interval) { /* * Restart scan interval timer if currently scheduled * scan is too far in the future. */ eloop_cancel_timeout(bgscan_simple_timeout, data, NULL); eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout, data, NULL); } } else if (data->scan_interval == data->short_interval && above) { wpa_printf(MSG_DEBUG, "bgscan simple: Start using long bgscan " "interval"); data->scan_interval = data->long_interval; eloop_cancel_timeout(bgscan_simple_timeout, data, NULL); eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout, data, NULL); } else if (!above) { /* * Signal dropped further 4 dB. Request a new scan if we have * not yet scanned in a while. */ os_get_reltime(&now); if (now.sec > data->last_bgscan.sec + 10) scan = 1; } if (scan) { wpa_printf(MSG_DEBUG, "bgscan simple: Trigger immediate scan"); eloop_cancel_timeout(bgscan_simple_timeout, data, NULL); eloop_register_timeout(0, 0, bgscan_simple_timeout, data, NULL); } } const struct bgscan_ops bgscan_simple_ops = { .name = "simple", .init = bgscan_simple_init, .deinit = bgscan_simple_deinit, .notify_scan = bgscan_simple_notify_scan, .notify_beacon_loss = bgscan_simple_notify_beacon_loss, .notify_signal_change = bgscan_simple_notify_signal_change, }; wpa_supplicant-2.2/wpa_supplicant/nmake.mak0000664000175000017500000001511612343617166017041 0ustar jmjm# Makefile for Microsoft nmake to build wpa_supplicant # This can be run in Visual Studio 2005 Command Prompt # Note: Make sure that cl.exe is configured to include Platform SDK # include and lib directories (vsvars32.bat) all: wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe wpasvc.exe win_if_list.exe # Root directory for WinPcap developer's pack # (http://www.winpcap.org/install/bin/WpdPack_3_1.zip) WINPCAPDIR=C:\dev\WpdPack # Root directory for OpenSSL # (http://www.openssl.org/source/openssl-0.9.8a.tar.gz) # Build and installed following instructions in INSTALL.W32 # Note: If EAP-FAST is included in the build, OpenSSL needs to be patched to # support it (openssl-tls-extensions.patch) # Alternatively, see README-Windows.txt for information about binary # installation package for OpenSSL. OPENSSLDIR=C:\dev\openssl CC = cl OBJDIR = objs CFLAGS = /DCONFIG_NATIVE_WINDOWS CFLAGS = $(CFLAGS) /DCONFIG_NDIS_EVENTS_INTEGRATED CFLAGS = $(CFLAGS) /DCONFIG_ANSI_C_EXTRA CFLAGS = $(CFLAGS) /DCONFIG_WINPCAP CFLAGS = $(CFLAGS) /DIEEE8021X_EAPOL CFLAGS = $(CFLAGS) /DPKCS12_FUNCS CFLAGS = $(CFLAGS) /DEAP_MD5 CFLAGS = $(CFLAGS) /DEAP_TLS CFLAGS = $(CFLAGS) /DEAP_MSCHAPv2 CFLAGS = $(CFLAGS) /DEAP_PEAP CFLAGS = $(CFLAGS) /DEAP_TTLS CFLAGS = $(CFLAGS) /DEAP_GTC CFLAGS = $(CFLAGS) /DEAP_OTP CFLAGS = $(CFLAGS) /DEAP_SIM CFLAGS = $(CFLAGS) /DEAP_LEAP CFLAGS = $(CFLAGS) /DEAP_PSK CFLAGS = $(CFLAGS) /DEAP_AKA #CFLAGS = $(CFLAGS) /DEAP_FAST CFLAGS = $(CFLAGS) /DEAP_PAX CFLAGS = $(CFLAGS) /DEAP_TNC CFLAGS = $(CFLAGS) /DPCSC_FUNCS CFLAGS = $(CFLAGS) /DCONFIG_CTRL_IFACE CFLAGS = $(CFLAGS) /DCONFIG_CTRL_IFACE_NAMED_PIPE CFLAGS = $(CFLAGS) /DCONFIG_DRIVER_NDIS CFLAGS = $(CFLAGS) /I..\src /I..\src\utils CFLAGS = $(CFLAGS) /I. CFLAGS = $(CFLAGS) /DWIN32 CFLAGS = $(CFLAGS) /Fo$(OBJDIR)\\ /c CFLAGS = $(CFLAGS) /W3 #CFLAGS = $(CFLAGS) /WX # VS 2005 complains about lot of deprecated string functions; let's ignore them # at least for now since snprintf and strncpy can be used in a safe way CFLAGS = $(CFLAGS) /D_CRT_SECURE_NO_DEPRECATE OBJS = \ $(OBJDIR)\os_win32.obj \ $(OBJDIR)\eloop_win.obj \ $(OBJDIR)\sha1.obj \ $(OBJDIR)\sha1-tlsprf.obj \ $(OBJDIR)\sha1-pbkdf2.obj \ $(OBJDIR)\md5.obj \ $(OBJDIR)\aes-cbc.obj \ $(OBJDIR)\aes-ctr.obj \ $(OBJDIR)\aes-eax.obj \ $(OBJDIR)\aes-encblock.obj \ $(OBJDIR)\aes-omac1.obj \ $(OBJDIR)\aes-unwrap.obj \ $(OBJDIR)\aes-wrap.obj \ $(OBJDIR)\common.obj \ $(OBJDIR)\wpa_debug.obj \ $(OBJDIR)\wpabuf.obj \ $(OBJDIR)\wpa_supplicant.obj \ $(OBJDIR)\wpa.obj \ $(OBJDIR)\wpa_common.obj \ $(OBJDIR)\wpa_ie.obj \ $(OBJDIR)\preauth.obj \ $(OBJDIR)\pmksa_cache.obj \ $(OBJDIR)\eapol_supp_sm.obj \ $(OBJDIR)\eap.obj \ $(OBJDIR)\eap_common.obj \ $(OBJDIR)\chap.obj \ $(OBJDIR)\eap_methods.obj \ $(OBJDIR)\eap_md5.obj \ $(OBJDIR)\eap_tls.obj \ $(OBJDIR)\eap_tls_common.obj \ $(OBJDIR)\eap_mschapv2.obj \ $(OBJDIR)\mschapv2.obj \ $(OBJDIR)\eap_peap.obj \ $(OBJDIR)\eap_peap_common.obj \ $(OBJDIR)\eap_ttls.obj \ $(OBJDIR)\eap_gtc.obj \ $(OBJDIR)\eap_otp.obj \ $(OBJDIR)\eap_leap.obj \ $(OBJDIR)\eap_sim.obj \ $(OBJDIR)\eap_sim_common.obj \ $(OBJDIR)\eap_aka.obj \ $(OBJDIR)\eap_pax.obj \ $(OBJDIR)\eap_pax_common.obj \ $(OBJDIR)\eap_psk.obj \ $(OBJDIR)\eap_psk_common.obj \ $(OBJDIR)\eap_tnc.obj \ $(OBJDIR)\tncc.obj \ $(OBJDIR)\base64.obj \ $(OBJDIR)\ctrl_iface.obj \ $(OBJDIR)\ctrl_iface_named_pipe.obj \ $(OBJDIR)\driver_ndis.obj \ $(OBJDIR)\driver_ndis_.obj \ $(OBJDIR)\scan_helpers.obj \ $(OBJDIR)\events.obj \ $(OBJDIR)\blacklist.obj \ $(OBJDIR)\scan.obj \ $(OBJDIR)\wpas_glue.obj \ $(OBJDIR)\eap_register.obj \ $(OBJDIR)\config.obj \ $(OBJDIR)\l2_packet_winpcap.obj \ $(OBJDIR)\tls_openssl.obj \ $(OBJDIR)\ms_funcs.obj \ $(OBJDIR)\crypto_openssl.obj \ $(OBJDIR)\fips_prf_openssl.obj \ $(OBJDIR)\pcsc_funcs.obj \ $(OBJDIR)\notify.obj \ $(OBJDIR)\ndis_events.obj # OBJS = $(OBJS) $(OBJDIR)\eap_fast.obj OBJS_t = $(OBJS) \ $(OBJDIR)\eapol_test.obj \ $(OBJDIR)\radius.obj \ $(OBJDIR)\radius_client.obj \ $(OBJDIR)\config_file.obj $(OBJDIR)\base64.obj OBJS_t2 = $(OBJS) \ $(OBJDIR)\preauth_test.obj \ $(OBJDIR)\config_file.obj $(OBJDIR)\base64.obj OBJS2 = $(OBJDIR)\drivers.obj \ $(OBJDIR)\config_file.obj \ $(OBJS2) $(OBJDIR)\main.obj OBJS3 = $(OBJDIR)\drivers.obj \ $(OBJDIR)\config_winreg.obj \ $(OBJS3) $(OBJDIR)\main_winsvc.obj OBJS_c = \ $(OBJDIR)\os_win32.obj \ $(OBJDIR)\wpa_cli.obj \ $(OBJDIR)\wpa_ctrl.obj \ $(OBJDIR)\common.obj OBJS_p = \ $(OBJDIR)\os_win32.obj \ $(OBJDIR)\common.obj \ $(OBJDIR)\wpa_debug.obj \ $(OBJDIR)\wpabuf.obj \ $(OBJDIR)\sha1.obj \ $(OBJDIR)\md5.obj \ $(OBJDIR)\crypto_openssl.obj \ $(OBJDIR)\sha1-pbkdf2.obj \ $(OBJDIR)\wpa_passphrase.obj LIBS = wbemuuid.lib libcmt.lib kernel32.lib uuid.lib ole32.lib oleaut32.lib \ ws2_32.lib Advapi32.lib Crypt32.lib Winscard.lib \ Packet.lib wpcap.lib \ libeay32.lib ssleay32.lib # If using Win32 OpenSSL binary installation from Shining Light Productions, # replace the last line with this for dynamic libraries # libeay32MT.lib ssleay32MT.lib # and this for static libraries # libeay32MT.lib ssleay32MT.lib Gdi32.lib User32.lib CFLAGS = $(CFLAGS) /I"$(WINPCAPDIR)/Include" /I"$(OPENSSLDIR)\include" LFLAGS = /libpath:"$(WINPCAPDIR)\Lib" /libpath:"$(OPENSSLDIR)\lib" wpa_supplicant.exe: $(OBJDIR) $(OBJS) $(OBJS2) link.exe /out:wpa_supplicant.exe $(LFLAGS) $(OBJS) $(OBJS2) $(LIBS) wpasvc.exe: $(OBJDIR) $(OBJS) $(OBJS3) link.exe /out:wpasvc.exe $(LFLAGS) $(OBJS) $(OBJS3) $(LIBS) wpa_cli.exe: $(OBJDIR) $(OBJS_c) link.exe /out:wpa_cli.exe $(LFLAGS) $(OBJS_c) $(LIBS) wpa_passphrase.exe: $(OBJDIR) $(OBJS_p) link.exe /out:wpa_passphrase.exe $(LFLAGS) $(OBJS_p) $(LIBS) eapol_test.exe: $(OBJDIR) $(OBJS_t) link.exe /out:eapol_test.exe $(LFLAGS) $(OBJS_t) $(LIBS) preauth_test.exe: $(OBJDIR) $(OBJS_t2) link.exe /out:preauth_test.exe $(LFLAGS) $(OBJS_t2) $(LIBS) win_if_list.exe: $(OBJDIR) $(OBJDIR)\win_if_list.obj link.exe /out:win_if_list.exe $(LFLAGS) $(OBJDIR)\win_if_list.obj $(LIBS) {..\src\utils}.c{$(OBJDIR)}.obj:: $(CC) $(CFLAGS) $< {..\src\common}.c{$(OBJDIR)}.obj:: $(CC) $(CFLAGS) $< {..\src\rsn_supp}.c{$(OBJDIR)}.obj:: $(CC) $(CFLAGS) $< {..\src\eapol_supp}.c{$(OBJDIR)}.obj:: $(CC) $(CFLAGS) $< {..\src\crypto}.c{$(OBJDIR)}.obj:: $(CC) $(CFLAGS) $< {..\src\eap_peer}.c{$(OBJDIR)}.obj:: $(CC) $(CFLAGS) $< {..\src\eap_common}.c{$(OBJDIR)}.obj:: $(CC) $(CFLAGS) $< {..\src\drivers}.c{$(OBJDIR)}.obj:: $(CC) $(CFLAGS) $< {..\src\l2_packet}.c{$(OBJDIR)}.obj:: $(CC) $(CFLAGS) $< {.\}.c{$(OBJDIR)}.obj:: $(CC) $(CFLAGS) $< {.\}.cpp{$(OBJDIR)}.obj:: $(CC) $(CFLAGS) $< $(OBJDIR): if not exist "$(OBJDIR)" mkdir "$(OBJDIR)" clean: erase $(OBJDIR)\*.obj wpa_supplicant.exe wpa_supplicant-2.2/wpa_supplicant/gas_query.c0000664000175000017500000004536312343617166017426 0ustar jmjm/* * Generic advertisement service (GAS) query * Copyright (c) 2009, Atheros Communications * Copyright (c) 2011-2014, Qualcomm Atheros, Inc. * Copyright (c) 2011-2014, 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 "utils/eloop.h" #include "common/ieee802_11_defs.h" #include "common/gas.h" #include "common/wpa_ctrl.h" #include "rsn_supp/wpa.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "offchannel.h" #include "gas_query.h" /** GAS query timeout in seconds */ #define GAS_QUERY_TIMEOUT_PERIOD 2 /** * struct gas_query_pending - Pending GAS query */ struct gas_query_pending { struct dl_list list; struct gas_query *gas; u8 addr[ETH_ALEN]; u8 dialog_token; u8 next_frag_id; unsigned int wait_comeback:1; unsigned int offchannel_tx_started:1; int freq; u16 status_code; struct wpabuf *req; struct wpabuf *adv_proto; struct wpabuf *resp; struct os_reltime last_oper; void (*cb)(void *ctx, const u8 *dst, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, const struct wpabuf *resp, u16 status_code); void *ctx; }; /** * struct gas_query - Internal GAS query data */ struct gas_query { struct wpa_supplicant *wpa_s; struct dl_list pending; /* struct gas_query_pending */ struct gas_query_pending *current; struct wpa_radio_work *work; }; static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx); static void gas_query_timeout(void *eloop_data, void *user_ctx); static int ms_from_time(struct os_reltime *last) { struct os_reltime now, res; os_get_reltime(&now); os_reltime_sub(&now, last, &res); return res.sec * 1000 + res.usec / 1000; } /** * gas_query_init - Initialize GAS query component * @wpa_s: Pointer to wpa_supplicant data * Returns: Pointer to GAS query data or %NULL on failure */ struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s) { struct gas_query *gas; gas = os_zalloc(sizeof(*gas)); if (gas == NULL) return NULL; gas->wpa_s = wpa_s; dl_list_init(&gas->pending); return gas; } static const char * gas_result_txt(enum gas_query_result result) { switch (result) { case GAS_QUERY_SUCCESS: return "SUCCESS"; case GAS_QUERY_FAILURE: return "FAILURE"; case GAS_QUERY_TIMEOUT: return "TIMEOUT"; case GAS_QUERY_PEER_ERROR: return "PEER_ERROR"; case GAS_QUERY_INTERNAL_ERROR: return "INTERNAL_ERROR"; case GAS_QUERY_CANCELLED: return "CANCELLED"; case GAS_QUERY_DELETED_AT_DEINIT: return "DELETED_AT_DEINIT"; } return "N/A"; } static void gas_query_free(struct gas_query_pending *query, int del_list) { struct gas_query *gas = query->gas; if (del_list) dl_list_del(&query->list); if (gas->work && gas->work->ctx == query) { radio_work_done(gas->work); gas->work = NULL; } wpabuf_free(query->req); wpabuf_free(query->adv_proto); wpabuf_free(query->resp); os_free(query); } static void gas_query_done(struct gas_query *gas, struct gas_query_pending *query, enum gas_query_result result) { wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_DONE "addr=" MACSTR " dialog_token=%u freq=%d status_code=%u result=%s", MAC2STR(query->addr), query->dialog_token, query->freq, query->status_code, gas_result_txt(result)); if (gas->current == query) gas->current = NULL; if (query->offchannel_tx_started) offchannel_send_action_done(gas->wpa_s); eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); eloop_cancel_timeout(gas_query_timeout, gas, query); dl_list_del(&query->list); query->cb(query->ctx, query->addr, query->dialog_token, result, query->adv_proto, query->resp, query->status_code); gas_query_free(query, 0); } /** * gas_query_deinit - Deinitialize GAS query component * @gas: GAS query data from gas_query_init() */ void gas_query_deinit(struct gas_query *gas) { struct gas_query_pending *query, *next; if (gas == NULL) return; dl_list_for_each_safe(query, next, &gas->pending, struct gas_query_pending, list) gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT); os_free(gas); } static struct gas_query_pending * gas_query_get_pending(struct gas_query *gas, const u8 *addr, u8 dialog_token) { struct gas_query_pending *q; dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { if (os_memcmp(q->addr, addr, ETH_ALEN) == 0 && q->dialog_token == dialog_token) return q; } return NULL; } static int gas_query_append(struct gas_query_pending *query, const u8 *data, size_t len) { if (wpabuf_resize(&query->resp, len) < 0) { wpa_printf(MSG_DEBUG, "GAS: No memory to store the response"); return -1; } wpabuf_put_data(query->resp, data, len); return 0; } static void gas_query_tx_status(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *data, size_t data_len, enum offchannel_send_action_result result) { struct gas_query_pending *query; struct gas_query *gas = wpa_s->gas; int dur; if (gas->current == NULL) { wpa_printf(MSG_DEBUG, "GAS: Unexpected TX status: freq=%u dst=" MACSTR " result=%d - no query in progress", freq, MAC2STR(dst), result); return; } query = gas->current; dur = ms_from_time(&query->last_oper); wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR " result=%d query=%p dialog_token=%u dur=%d ms", freq, MAC2STR(dst), result, query, query->dialog_token, dur); if (os_memcmp(dst, query->addr, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination"); return; } os_get_reltime(&query->last_oper); if (result == OFFCHANNEL_SEND_ACTION_SUCCESS) { eloop_cancel_timeout(gas_query_timeout, gas, query); eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout, gas, query); } if (result == OFFCHANNEL_SEND_ACTION_FAILED) { eloop_cancel_timeout(gas_query_timeout, gas, query); eloop_register_timeout(0, 0, gas_query_timeout, gas, query); } } static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr) { if (wpa_s->current_ssid == NULL || wpa_s->wpa_state < WPA_4WAY_HANDSHAKE || os_memcmp(addr, wpa_s->bssid, ETH_ALEN) != 0) return 0; return wpa_sm_pmf_enabled(wpa_s->wpa); } static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, struct wpabuf *req) { int res, prot = pmf_in_use(gas->wpa_s, query->addr); wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u " "freq=%d prot=%d", MAC2STR(query->addr), (unsigned int) wpabuf_len(req), query->freq, prot); if (prot) { u8 *categ = wpabuf_mhead_u8(req); *categ = WLAN_ACTION_PROTECTED_DUAL; } os_get_reltime(&query->last_oper); res = offchannel_send_action(gas->wpa_s, query->freq, query->addr, gas->wpa_s->own_addr, query->addr, wpabuf_head(req), wpabuf_len(req), 1000, gas_query_tx_status, 0); if (res == 0) query->offchannel_tx_started = 1; return res; } static void gas_query_tx_comeback_req(struct gas_query *gas, struct gas_query_pending *query) { struct wpabuf *req; req = gas_build_comeback_req(query->dialog_token); if (req == NULL) { gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); return; } if (gas_query_tx(gas, query, req) < 0) { wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " MACSTR, MAC2STR(query->addr)); gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); } wpabuf_free(req); } static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx) { struct gas_query *gas = eloop_data; struct gas_query_pending *query = user_ctx; wpa_printf(MSG_DEBUG, "GAS: Comeback timeout for request to " MACSTR, MAC2STR(query->addr)); gas_query_tx_comeback_req(gas, query); } static void gas_query_tx_comeback_req_delay(struct gas_query *gas, struct gas_query_pending *query, u16 comeback_delay) { unsigned int secs, usecs; secs = (comeback_delay * 1024) / 1000000; usecs = comeback_delay * 1024 - secs * 1000000; wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR " in %u secs %u usecs", MAC2STR(query->addr), secs, usecs); eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); eloop_register_timeout(secs, usecs, gas_query_tx_comeback_timeout, gas, query); } static void gas_query_rx_initial(struct gas_query *gas, struct gas_query_pending *query, const u8 *adv_proto, const u8 *resp, size_t len, u16 comeback_delay) { wpa_printf(MSG_DEBUG, "GAS: Received initial response from " MACSTR " (dialog_token=%u comeback_delay=%u)", MAC2STR(query->addr), query->dialog_token, comeback_delay); query->adv_proto = wpabuf_alloc_copy(adv_proto, 2 + adv_proto[1]); if (query->adv_proto == NULL) { gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); return; } if (comeback_delay) { query->wait_comeback = 1; gas_query_tx_comeback_req_delay(gas, query, comeback_delay); return; } /* Query was completed without comeback mechanism */ if (gas_query_append(query, resp, len) < 0) { gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); return; } gas_query_done(gas, query, GAS_QUERY_SUCCESS); } static void gas_query_rx_comeback(struct gas_query *gas, struct gas_query_pending *query, const u8 *adv_proto, const u8 *resp, size_t len, u8 frag_id, u8 more_frags, u16 comeback_delay) { wpa_printf(MSG_DEBUG, "GAS: Received comeback response from " MACSTR " (dialog_token=%u frag_id=%u more_frags=%u " "comeback_delay=%u)", MAC2STR(query->addr), query->dialog_token, frag_id, more_frags, comeback_delay); if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) || os_memcmp(adv_proto, wpabuf_head(query->adv_proto), wpabuf_len(query->adv_proto)) != 0) { wpa_printf(MSG_DEBUG, "GAS: Advertisement Protocol changed " "between initial and comeback response from " MACSTR, MAC2STR(query->addr)); gas_query_done(gas, query, GAS_QUERY_PEER_ERROR); return; } if (comeback_delay) { if (frag_id) { wpa_printf(MSG_DEBUG, "GAS: Invalid comeback response " "with non-zero frag_id and comeback_delay " "from " MACSTR, MAC2STR(query->addr)); gas_query_done(gas, query, GAS_QUERY_PEER_ERROR); return; } gas_query_tx_comeback_req_delay(gas, query, comeback_delay); return; } if (frag_id != query->next_frag_id) { wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response " "from " MACSTR, MAC2STR(query->addr)); if (frag_id + 1 == query->next_frag_id) { wpa_printf(MSG_DEBUG, "GAS: Drop frame as possible " "retry of previous fragment"); return; } gas_query_done(gas, query, GAS_QUERY_PEER_ERROR); return; } query->next_frag_id++; if (gas_query_append(query, resp, len) < 0) { gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); return; } if (more_frags) { gas_query_tx_comeback_req(gas, query); return; } gas_query_done(gas, query, GAS_QUERY_SUCCESS); } /** * gas_query_rx - Indicate reception of a Public Action or Protected Dual frame * @gas: GAS query data from gas_query_init() * @da: Destination MAC address of the Action frame * @sa: Source MAC address of the Action frame * @bssid: BSSID of the Action frame * @categ: Category of the Action frame * @data: Payload of the Action frame * @len: Length of @data * @freq: Frequency (in MHz) on which the frame was received * Returns: 0 if the Public Action frame was a GAS frame or -1 if not */ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, const u8 *bssid, u8 categ, const u8 *data, size_t len, int freq) { struct gas_query_pending *query; u8 action, dialog_token, frag_id = 0, more_frags = 0; u16 comeback_delay, resp_len; const u8 *pos, *adv_proto; int prot, pmf; if (gas == NULL || len < 4) return -1; prot = categ == WLAN_ACTION_PROTECTED_DUAL; pmf = pmf_in_use(gas->wpa_s, bssid); if (prot && !pmf) { wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled"); return 0; } if (!prot && pmf) { wpa_printf(MSG_DEBUG, "GAS: Drop unexpected unprotected GAS frame when PMF is enabled"); return 0; } pos = data; action = *pos++; dialog_token = *pos++; if (action != WLAN_PA_GAS_INITIAL_RESP && action != WLAN_PA_GAS_COMEBACK_RESP) return -1; /* Not a GAS response */ query = gas_query_get_pending(gas, sa, dialog_token); if (query == NULL) { wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR " dialog token %u", MAC2STR(sa), dialog_token); return -1; } wpa_printf(MSG_DEBUG, "GAS: Response in %d ms from " MACSTR, ms_from_time(&query->last_oper), MAC2STR(sa)); if (query->wait_comeback && action == WLAN_PA_GAS_INITIAL_RESP) { wpa_printf(MSG_DEBUG, "GAS: Unexpected initial response from " MACSTR " dialog token %u when waiting for comeback " "response", MAC2STR(sa), dialog_token); return 0; } if (!query->wait_comeback && action == WLAN_PA_GAS_COMEBACK_RESP) { wpa_printf(MSG_DEBUG, "GAS: Unexpected comeback response from " MACSTR " dialog token %u when waiting for initial " "response", MAC2STR(sa), dialog_token); return 0; } query->status_code = WPA_GET_LE16(pos); pos += 2; if (query->status_code == WLAN_STATUS_QUERY_RESP_OUTSTANDING && action == WLAN_PA_GAS_COMEBACK_RESP) { wpa_printf(MSG_DEBUG, "GAS: Allow non-zero status for outstanding comeback response"); } else if (query->status_code != WLAN_STATUS_SUCCESS) { wpa_printf(MSG_DEBUG, "GAS: Query to " MACSTR " dialog token " "%u failed - status code %u", MAC2STR(sa), dialog_token, query->status_code); gas_query_done(gas, query, GAS_QUERY_FAILURE); return 0; } if (action == WLAN_PA_GAS_COMEBACK_RESP) { if (pos + 1 > data + len) return 0; frag_id = *pos & 0x7f; more_frags = (*pos & 0x80) >> 7; pos++; } /* Comeback Delay */ if (pos + 2 > data + len) return 0; comeback_delay = WPA_GET_LE16(pos); pos += 2; /* Advertisement Protocol element */ if (pos + 2 > data + len || pos + 2 + pos[1] > data + len) { wpa_printf(MSG_DEBUG, "GAS: No room for Advertisement " "Protocol element in the response from " MACSTR, MAC2STR(sa)); return 0; } if (*pos != WLAN_EID_ADV_PROTO) { wpa_printf(MSG_DEBUG, "GAS: Unexpected Advertisement " "Protocol element ID %u in response from " MACSTR, *pos, MAC2STR(sa)); return 0; } adv_proto = pos; pos += 2 + pos[1]; /* Query Response Length */ if (pos + 2 > data + len) { wpa_printf(MSG_DEBUG, "GAS: No room for GAS Response Length"); return 0; } resp_len = WPA_GET_LE16(pos); pos += 2; if (pos + resp_len > data + len) { wpa_printf(MSG_DEBUG, "GAS: Truncated Query Response in " "response from " MACSTR, MAC2STR(sa)); return 0; } if (pos + resp_len < data + len) { wpa_printf(MSG_DEBUG, "GAS: Ignore %u octets of extra data " "after Query Response from " MACSTR, (unsigned int) (data + len - pos - resp_len), MAC2STR(sa)); } if (action == WLAN_PA_GAS_COMEBACK_RESP) gas_query_rx_comeback(gas, query, adv_proto, pos, resp_len, frag_id, more_frags, comeback_delay); else gas_query_rx_initial(gas, query, adv_proto, pos, resp_len, comeback_delay); return 0; } static void gas_query_timeout(void *eloop_data, void *user_ctx) { struct gas_query *gas = eloop_data; struct gas_query_pending *query = user_ctx; wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR " dialog token %u", MAC2STR(query->addr), query->dialog_token); gas_query_done(gas, query, GAS_QUERY_TIMEOUT); } static int gas_query_dialog_token_available(struct gas_query *gas, const u8 *dst, u8 dialog_token) { struct gas_query_pending *q; dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 && dialog_token == q->dialog_token) return 0; } return 1; } static void gas_query_start_cb(struct wpa_radio_work *work, int deinit) { struct gas_query_pending *query = work->ctx; struct gas_query *gas = query->gas; if (deinit) { if (work->started) { gas->work = NULL; gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT); return; } gas_query_free(query, 1); return; } gas->work = work; if (gas_query_tx(gas, query, query->req) < 0) { wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " MACSTR, MAC2STR(query->addr)); gas_query_free(query, 1); return; } gas->current = query; wpa_printf(MSG_DEBUG, "GAS: Starting query timeout for dialog token %u", query->dialog_token); eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout, gas, query); } /** * gas_query_req - Request a GAS query * @gas: GAS query data from gas_query_init() * @dst: Destination MAC address for the query * @freq: Frequency (in MHz) for the channel on which to send the query * @req: GAS query payload (to be freed by gas_query module in case of success * return) * @cb: Callback function for reporting GAS query result and response * @ctx: Context pointer to use with the @cb call * Returns: dialog token (>= 0) on success or -1 on failure */ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, struct wpabuf *req, void (*cb)(void *ctx, const u8 *dst, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, const struct wpabuf *resp, u16 status_code), void *ctx) { struct gas_query_pending *query; int dialog_token; static int next_start = 0; if (wpabuf_len(req) < 3) return -1; for (dialog_token = 0; dialog_token < 256; dialog_token++) { if (gas_query_dialog_token_available( gas, dst, (next_start + dialog_token) % 256)) break; } if (dialog_token == 256) return -1; /* Too many pending queries */ dialog_token = (next_start + dialog_token) % 256; next_start = (dialog_token + 1) % 256; query = os_zalloc(sizeof(*query)); if (query == NULL) return -1; query->gas = gas; os_memcpy(query->addr, dst, ETH_ALEN); query->dialog_token = dialog_token; query->freq = freq; query->cb = cb; query->ctx = ctx; query->req = req; dl_list_add(&gas->pending, &query->list); *(wpabuf_mhead_u8(req) + 2) = dialog_token; wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_START "addr=" MACSTR " dialog_token=%u freq=%d", MAC2STR(query->addr), query->dialog_token, query->freq); if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb, query) < 0) { gas_query_free(query, 1); return -1; } return dialog_token; } /** * gas_query_cancel - Cancel a pending GAS query * @gas: GAS query data from gas_query_init() * @dst: Destination MAC address for the query * @dialog_token: Dialog token from gas_query_req() */ void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token) { struct gas_query_pending *query; query = gas_query_get_pending(gas, dst, dialog_token); if (query) gas_query_done(gas, query, GAS_QUERY_CANCELLED); } wpa_supplicant-2.2/wpa_supplicant/eapol_test.c0000664000175000017500000011045512343617166017561 0ustar jmjm/* * WPA Supplicant - test code * Copyright (c) 2003-2013, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. * * IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c. * Not used in production version. */ #include "includes.h" #include #include "common.h" #include "utils/ext_password.h" #include "config.h" #include "eapol_supp/eapol_supp_sm.h" #include "eap_peer/eap.h" #include "eap_server/eap_methods.h" #include "eloop.h" #include "utils/base64.h" #include "rsn_supp/wpa.h" #include "wpa_supplicant_i.h" #include "radius/radius.h" #include "radius/radius_client.h" #include "common/wpa_ctrl.h" #include "ctrl_iface.h" #include "pcsc_funcs.h" #include "wpas_glue.h" struct wpa_driver_ops *wpa_drivers[] = { NULL }; struct extra_radius_attr { u8 type; char syntax; char *data; struct extra_radius_attr *next; }; struct eapol_test_data { struct wpa_supplicant *wpa_s; int eapol_test_num_reauths; int no_mppe_keys; int num_mppe_ok, num_mppe_mismatch; int req_eap_key_name; u8 radius_identifier; struct radius_msg *last_recv_radius; struct in_addr own_ip_addr; struct radius_client_data *radius; struct hostapd_radius_servers *radius_conf; /* last received EAP Response from Authentication Server */ struct wpabuf *last_eap_radius; u8 authenticator_pmk[PMK_LEN]; size_t authenticator_pmk_len; u8 authenticator_eap_key_name[256]; size_t authenticator_eap_key_name_len; int radius_access_accept_received; int radius_access_reject_received; int auth_timed_out; u8 *eap_identity; size_t eap_identity_len; char *connect_info; u8 own_addr[ETH_ALEN]; struct extra_radius_attr *extra_attrs; FILE *server_cert_file; }; static struct eapol_test_data eapol_test; static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx); static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, int level, const char *txt, size_t len) { if (addr) wpa_printf(MSG_DEBUG, "STA " MACSTR ": %s\n", MAC2STR(addr), txt); else wpa_printf(MSG_DEBUG, "%s", txt); } static int add_extra_attr(struct radius_msg *msg, struct extra_radius_attr *attr) { size_t len; char *pos; u32 val; char buf[RADIUS_MAX_ATTR_LEN + 1]; switch (attr->syntax) { case 's': os_snprintf(buf, sizeof(buf), "%s", attr->data); len = os_strlen(buf); break; case 'n': buf[0] = '\0'; len = 1; break; case 'x': pos = attr->data; if (pos[0] == '0' && pos[1] == 'x') pos += 2; len = os_strlen(pos); if ((len & 1) || (len / 2) > RADIUS_MAX_ATTR_LEN) { printf("Invalid extra attribute hexstring\n"); return -1; } len /= 2; if (hexstr2bin(pos, (u8 *) buf, len) < 0) { printf("Invalid extra attribute hexstring\n"); return -1; } break; case 'd': val = htonl(atoi(attr->data)); os_memcpy(buf, &val, 4); len = 4; break; default: printf("Incorrect extra attribute syntax specification\n"); return -1; } if (!radius_msg_add_attr(msg, attr->type, (u8 *) buf, len)) { printf("Could not add attribute %d\n", attr->type); return -1; } return 0; } static int add_extra_attrs(struct radius_msg *msg, struct extra_radius_attr *attrs) { struct extra_radius_attr *p; for (p = attrs; p; p = p->next) { if (add_extra_attr(msg, p) < 0) return -1; } return 0; } static struct extra_radius_attr * find_extra_attr(struct extra_radius_attr *attrs, u8 type) { struct extra_radius_attr *p; for (p = attrs; p; p = p->next) { if (p->type == type) return p; } return NULL; } static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e, const u8 *eap, size_t len) { struct radius_msg *msg; char buf[RADIUS_MAX_ATTR_LEN + 1]; const struct eap_hdr *hdr; const u8 *pos; wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " "packet"); e->radius_identifier = radius_client_get_id(e->radius); msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, e->radius_identifier); if (msg == NULL) { printf("Could not create net RADIUS packet\n"); return; } radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e)); hdr = (const struct eap_hdr *) eap; pos = (const u8 *) (hdr + 1); if (len > sizeof(*hdr) && hdr->code == EAP_CODE_RESPONSE && pos[0] == EAP_TYPE_IDENTITY) { pos++; os_free(e->eap_identity); e->eap_identity_len = len - sizeof(*hdr) - 1; e->eap_identity = os_malloc(e->eap_identity_len); if (e->eap_identity) { os_memcpy(e->eap_identity, pos, e->eap_identity_len); wpa_hexdump(MSG_DEBUG, "Learned identity from " "EAP-Response-Identity", e->eap_identity, e->eap_identity_len); } } if (e->eap_identity && !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, e->eap_identity, e->eap_identity_len)) { printf("Could not add User-Name\n"); goto fail; } if (e->req_eap_key_name && !radius_msg_add_attr(msg, RADIUS_ATTR_EAP_KEY_NAME, (u8 *) "\0", 1)) { printf("Could not add EAP-Key-Name\n"); goto fail; } if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_IP_ADDRESS) && !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, (u8 *) &e->own_ip_addr, 4)) { printf("Could not add NAS-IP-Address\n"); goto fail; } os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(e->wpa_s->own_addr)); if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CALLING_STATION_ID) && !radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, (u8 *) buf, os_strlen(buf))) { printf("Could not add Calling-Station-Id\n"); goto fail; } /* TODO: should probably check MTU from driver config; 2304 is max for * IEEE 802.11, but use 1400 to avoid problems with too large packets */ if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_FRAMED_MTU) && !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { printf("Could not add Framed-MTU\n"); goto fail; } if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_PORT_TYPE) && !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { printf("Could not add NAS-Port-Type\n"); goto fail; } os_snprintf(buf, sizeof(buf), "%s", e->connect_info); if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CONNECT_INFO) && !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, (u8 *) buf, os_strlen(buf))) { printf("Could not add Connect-Info\n"); goto fail; } if (add_extra_attrs(msg, e->extra_attrs) < 0) goto fail; if (eap && !radius_msg_add_eap(msg, eap, len)) { printf("Could not add EAP-Message\n"); goto fail; } /* State attribute must be copied if and only if this packet is * Access-Request reply to the previous Access-Challenge */ if (e->last_recv_radius && radius_msg_get_hdr(e->last_recv_radius)->code == RADIUS_CODE_ACCESS_CHALLENGE) { int res = radius_msg_copy_attr(msg, e->last_recv_radius, RADIUS_ATTR_STATE); if (res < 0) { printf("Could not copy State attribute from previous " "Access-Challenge\n"); goto fail; } if (res > 0) { wpa_printf(MSG_DEBUG, " Copied RADIUS State " "Attribute"); } } if (radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr) < 0) goto fail; return; fail: radius_msg_free(msg); } static int eapol_test_eapol_send(void *ctx, int type, const u8 *buf, size_t len) { printf("WPA: eapol_test_eapol_send(type=%d len=%lu)\n", type, (unsigned long) len); if (type == IEEE802_1X_TYPE_EAP_PACKET) { wpa_hexdump(MSG_DEBUG, "TX EAP -> RADIUS", buf, len); ieee802_1x_encapsulate_radius(&eapol_test, buf, len); } return 0; } static void eapol_test_set_config_blob(void *ctx, struct wpa_config_blob *blob) { struct eapol_test_data *e = ctx; wpa_config_set_blob(e->wpa_s->conf, blob); } static const struct wpa_config_blob * eapol_test_get_config_blob(void *ctx, const char *name) { struct eapol_test_data *e = ctx; return wpa_config_get_blob(e->wpa_s->conf, name); } static void eapol_test_eapol_done_cb(void *ctx) { printf("WPA: EAPOL processing complete\n"); } static void eapol_sm_reauth(void *eloop_ctx, void *timeout_ctx) { struct eapol_test_data *e = eloop_ctx; printf("\n\n\n\n\neapol_test: Triggering EAP reauthentication\n\n"); e->radius_access_accept_received = 0; send_eap_request_identity(e->wpa_s, NULL); } static int eapol_test_compare_pmk(struct eapol_test_data *e) { u8 pmk[PMK_LEN]; int ret = 1; const u8 *sess_id; size_t sess_id_len; if (eapol_sm_get_key(e->wpa_s->eapol, pmk, PMK_LEN) == 0) { wpa_hexdump(MSG_DEBUG, "PMK from EAPOL", pmk, PMK_LEN); if (os_memcmp(pmk, e->authenticator_pmk, PMK_LEN) != 0) { printf("WARNING: PMK mismatch\n"); wpa_hexdump(MSG_DEBUG, "PMK from AS", e->authenticator_pmk, PMK_LEN); } else if (e->radius_access_accept_received) ret = 0; } else if (e->authenticator_pmk_len == 16 && eapol_sm_get_key(e->wpa_s->eapol, pmk, 16) == 0) { wpa_hexdump(MSG_DEBUG, "LEAP PMK from EAPOL", pmk, 16); if (os_memcmp(pmk, e->authenticator_pmk, 16) != 0) { printf("WARNING: PMK mismatch\n"); wpa_hexdump(MSG_DEBUG, "PMK from AS", e->authenticator_pmk, 16); } else if (e->radius_access_accept_received) ret = 0; } else if (e->radius_access_accept_received && e->no_mppe_keys) { /* No keying material expected */ ret = 0; } if (ret && !e->no_mppe_keys) e->num_mppe_mismatch++; else if (!e->no_mppe_keys) e->num_mppe_ok++; sess_id = eapol_sm_get_session_id(e->wpa_s->eapol, &sess_id_len); if (!sess_id) return ret; if (e->authenticator_eap_key_name_len == 0) { wpa_printf(MSG_INFO, "No EAP-Key-Name received from server"); return ret; } if (e->authenticator_eap_key_name_len != sess_id_len || os_memcmp(e->authenticator_eap_key_name, sess_id, sess_id_len) != 0) { wpa_printf(MSG_INFO, "Locally derived EAP Session-Id does not match EAP-Key-Name from server"); wpa_hexdump(MSG_DEBUG, "EAP Session-Id", sess_id, sess_id_len); wpa_hexdump(MSG_DEBUG, "EAP-Key-Name from server", e->authenticator_eap_key_name, e->authenticator_eap_key_name_len); } else { wpa_printf(MSG_INFO, "Locally derived EAP Session-Id matches EAP-Key-Name from server"); } return ret; } static void eapol_sm_cb(struct eapol_sm *eapol, enum eapol_supp_result result, void *ctx) { struct eapol_test_data *e = ctx; printf("eapol_sm_cb: result=%d\n", result); e->eapol_test_num_reauths--; if (e->eapol_test_num_reauths < 0) eloop_terminate(); else { eapol_test_compare_pmk(e); eloop_register_timeout(0, 100000, eapol_sm_reauth, e, NULL); } } static void eapol_test_write_cert(FILE *f, const char *subject, const struct wpabuf *cert) { unsigned char *encoded; encoded = base64_encode(wpabuf_head(cert), wpabuf_len(cert), NULL); if (encoded == NULL) return; fprintf(f, "%s\n-----BEGIN CERTIFICATE-----\n%s" "-----END CERTIFICATE-----\n\n", subject, encoded); os_free(encoded); } #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) static void eapol_test_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field, const char *default_txt) { struct eapol_test_data *e = ctx; struct wpa_supplicant *wpa_s = e->wpa_s; struct wpa_ssid *ssid = wpa_s->current_ssid; const char *field_name, *txt = NULL; char *buf; size_t buflen; int len; if (ssid == NULL) return; field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt, &txt); if (field_name == NULL) { wpa_printf(MSG_WARNING, "Unhandled EAP param %d needed", field); return; } buflen = 100 + os_strlen(txt) + ssid->ssid_len; buf = os_malloc(buflen); if (buf == NULL) return; len = os_snprintf(buf, buflen, WPA_CTRL_REQ "%s-%d:%s needed for SSID ", field_name, ssid->id, txt); if (len < 0 || (size_t) len >= buflen) { os_free(buf); return; } if (ssid->ssid && buflen > len + ssid->ssid_len) { os_memcpy(buf + len, ssid->ssid, ssid->ssid_len); len += ssid->ssid_len; buf[len] = '\0'; } buf[buflen - 1] = '\0'; wpa_msg(wpa_s, MSG_INFO, "%s", buf); os_free(buf); } #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ #define eapol_test_eap_param_needed NULL #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ static void eapol_test_cert_cb(void *ctx, int depth, const char *subject, const char *cert_hash, const struct wpabuf *cert) { struct eapol_test_data *e = ctx; wpa_msg(e->wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT "depth=%d subject='%s'%s%s", depth, subject, cert_hash ? " hash=" : "", cert_hash ? cert_hash : ""); if (cert) { char *cert_hex; size_t len = wpabuf_len(cert) * 2 + 1; cert_hex = os_malloc(len); if (cert_hex) { wpa_snprintf_hex(cert_hex, len, wpabuf_head(cert), wpabuf_len(cert)); wpa_msg_ctrl(e->wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT "depth=%d subject='%s' cert=%s", depth, subject, cert_hex); os_free(cert_hex); } if (e->server_cert_file) eapol_test_write_cert(e->server_cert_file, subject, cert); } } static void eapol_test_set_anon_id(void *ctx, const u8 *id, size_t len) { struct eapol_test_data *e = ctx; struct wpa_supplicant *wpa_s = e->wpa_s; char *str; int res; wpa_hexdump_ascii(MSG_DEBUG, "EAP method updated anonymous_identity", id, len); if (wpa_s->current_ssid == NULL) return; if (id == NULL) { if (wpa_config_set(wpa_s->current_ssid, "anonymous_identity", "NULL", 0) < 0) return; } else { str = os_malloc(len * 2 + 1); if (str == NULL) return; wpa_snprintf_hex(str, len * 2 + 1, id, len); res = wpa_config_set(wpa_s->current_ssid, "anonymous_identity", str, 0); os_free(str); if (res < 0) return; } } static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct eapol_config eapol_conf; struct eapol_ctx *ctx; ctx = os_zalloc(sizeof(*ctx)); if (ctx == NULL) { printf("Failed to allocate EAPOL context.\n"); return -1; } ctx->ctx = e; ctx->msg_ctx = wpa_s; ctx->scard_ctx = wpa_s->scard; ctx->cb = eapol_sm_cb; ctx->cb_ctx = e; ctx->eapol_send_ctx = wpa_s; ctx->preauth = 0; ctx->eapol_done_cb = eapol_test_eapol_done_cb; ctx->eapol_send = eapol_test_eapol_send; ctx->set_config_blob = eapol_test_set_config_blob; ctx->get_config_blob = eapol_test_get_config_blob; ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path; ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path; ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path; ctx->eap_param_needed = eapol_test_eap_param_needed; ctx->cert_cb = eapol_test_cert_cb; ctx->cert_in_cb = 1; ctx->set_anon_id = eapol_test_set_anon_id; wpa_s->eapol = eapol_sm_init(ctx); if (wpa_s->eapol == NULL) { os_free(ctx); printf("Failed to initialize EAPOL state machines.\n"); return -1; } wpa_s->current_ssid = ssid; os_memset(&eapol_conf, 0, sizeof(eapol_conf)); eapol_conf.accept_802_1x_keys = 1; eapol_conf.required_keys = 0; eapol_conf.fast_reauth = wpa_s->conf->fast_reauth; eapol_conf.workaround = ssid->eap_workaround; eapol_conf.external_sim = wpa_s->conf->external_sim; eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf); eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard); eapol_sm_notify_portValid(wpa_s->eapol, FALSE); /* 802.1X::portControl = Auto */ eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE); return 0; } static void test_eapol_clean(struct eapol_test_data *e, struct wpa_supplicant *wpa_s) { struct extra_radius_attr *p, *prev; radius_client_deinit(e->radius); wpabuf_free(e->last_eap_radius); radius_msg_free(e->last_recv_radius); e->last_recv_radius = NULL; os_free(e->eap_identity); e->eap_identity = NULL; eapol_sm_deinit(wpa_s->eapol); wpa_s->eapol = NULL; if (e->radius_conf && e->radius_conf->auth_server) { os_free(e->radius_conf->auth_server->shared_secret); os_free(e->radius_conf->auth_server); } os_free(e->radius_conf); e->radius_conf = NULL; scard_deinit(wpa_s->scard); if (wpa_s->ctrl_iface) { wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); wpa_s->ctrl_iface = NULL; } ext_password_deinit(wpa_s->ext_pw); wpa_s->ext_pw = NULL; wpa_config_free(wpa_s->conf); p = e->extra_attrs; while (p) { prev = p; p = p->next; os_free(prev); } } static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; u8 buf[100], *pos; struct ieee802_1x_hdr *hdr; struct eap_hdr *eap; hdr = (struct ieee802_1x_hdr *) buf; hdr->version = EAPOL_VERSION; hdr->type = IEEE802_1X_TYPE_EAP_PACKET; hdr->length = htons(5); eap = (struct eap_hdr *) (hdr + 1); eap->code = EAP_CODE_REQUEST; eap->identifier = 0; eap->length = htons(5); pos = (u8 *) (eap + 1); *pos = EAP_TYPE_IDENTITY; printf("Sending fake EAP-Request-Identity\n"); eapol_sm_rx_eapol(wpa_s->eapol, wpa_s->bssid, buf, sizeof(*hdr) + 5); } static void eapol_test_timeout(void *eloop_ctx, void *timeout_ctx) { struct eapol_test_data *e = eloop_ctx; printf("EAPOL test timed out\n"); e->auth_timed_out = 1; eloop_terminate(); } static char *eap_type_text(u8 type) { switch (type) { case EAP_TYPE_IDENTITY: return "Identity"; case EAP_TYPE_NOTIFICATION: return "Notification"; case EAP_TYPE_NAK: return "Nak"; case EAP_TYPE_TLS: return "TLS"; case EAP_TYPE_TTLS: return "TTLS"; case EAP_TYPE_PEAP: return "PEAP"; case EAP_TYPE_SIM: return "SIM"; case EAP_TYPE_GTC: return "GTC"; case EAP_TYPE_MD5: return "MD5"; case EAP_TYPE_OTP: return "OTP"; case EAP_TYPE_FAST: return "FAST"; case EAP_TYPE_SAKE: return "SAKE"; case EAP_TYPE_PSK: return "PSK"; default: return "Unknown"; } } static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e) { struct wpabuf *eap; const struct eap_hdr *hdr; int eap_type = -1; char buf[64]; struct radius_msg *msg; if (e->last_recv_radius == NULL) return; msg = e->last_recv_radius; eap = radius_msg_get_eap(msg); if (eap == NULL) { /* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3: * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message * attribute */ wpa_printf(MSG_DEBUG, "could not extract " "EAP-Message from RADIUS message"); wpabuf_free(e->last_eap_radius); e->last_eap_radius = NULL; return; } if (wpabuf_len(eap) < sizeof(*hdr)) { wpa_printf(MSG_DEBUG, "too short EAP packet " "received from authentication server"); wpabuf_free(eap); return; } if (wpabuf_len(eap) > sizeof(*hdr)) eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)]; hdr = wpabuf_head(eap); switch (hdr->code) { case EAP_CODE_REQUEST: os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", eap_type >= 0 ? eap_type_text(eap_type) : "??", eap_type); break; case EAP_CODE_RESPONSE: os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", eap_type >= 0 ? eap_type_text(eap_type) : "??", eap_type); break; case EAP_CODE_SUCCESS: os_strlcpy(buf, "EAP Success", sizeof(buf)); /* LEAP uses EAP Success within an authentication, so must not * stop here with eloop_terminate(); */ break; case EAP_CODE_FAILURE: os_strlcpy(buf, "EAP Failure", sizeof(buf)); eloop_terminate(); break; default: os_strlcpy(buf, "unknown EAP code", sizeof(buf)); wpa_hexdump_buf(MSG_DEBUG, "Decapsulated EAP packet", eap); break; } wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d " "id=%d len=%d) from RADIUS server: %s", hdr->code, hdr->identifier, ntohs(hdr->length), buf); /* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */ wpabuf_free(e->last_eap_radius); e->last_eap_radius = eap; { struct ieee802_1x_hdr *dot1x; dot1x = os_malloc(sizeof(*dot1x) + wpabuf_len(eap)); assert(dot1x != NULL); dot1x->version = EAPOL_VERSION; dot1x->type = IEEE802_1X_TYPE_EAP_PACKET; dot1x->length = htons(wpabuf_len(eap)); os_memcpy((u8 *) (dot1x + 1), wpabuf_head(eap), wpabuf_len(eap)); eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid, (u8 *) dot1x, sizeof(*dot1x) + wpabuf_len(eap)); os_free(dot1x); } } static void ieee802_1x_get_keys(struct eapol_test_data *e, struct radius_msg *msg, struct radius_msg *req, const u8 *shared_secret, size_t shared_secret_len) { struct radius_ms_mppe_keys *keys; u8 *buf; size_t len; keys = radius_msg_get_ms_keys(msg, req, shared_secret, shared_secret_len); if (keys && keys->send == NULL && keys->recv == NULL) { os_free(keys); keys = radius_msg_get_cisco_keys(msg, req, shared_secret, shared_secret_len); } if (keys) { if (keys->send) { wpa_hexdump(MSG_DEBUG, "MS-MPPE-Send-Key (sign)", keys->send, keys->send_len); } if (keys->recv) { wpa_hexdump(MSG_DEBUG, "MS-MPPE-Recv-Key (crypt)", keys->recv, keys->recv_len); e->authenticator_pmk_len = keys->recv_len > PMK_LEN ? PMK_LEN : keys->recv_len; os_memcpy(e->authenticator_pmk, keys->recv, e->authenticator_pmk_len); if (e->authenticator_pmk_len == 16 && keys->send && keys->send_len == 16) { /* MS-CHAP-v2 derives 16 octet keys */ wpa_printf(MSG_DEBUG, "Use MS-MPPE-Send-Key " "to extend PMK to 32 octets"); os_memcpy(e->authenticator_pmk + e->authenticator_pmk_len, keys->send, keys->send_len); e->authenticator_pmk_len += keys->send_len; } } os_free(keys->send); os_free(keys->recv); os_free(keys); } if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_EAP_KEY_NAME, &buf, &len, NULL) == 0) { os_memcpy(e->authenticator_eap_key_name, buf, len); e->authenticator_eap_key_name_len = len; } else { e->authenticator_eap_key_name_len = 0; } } /* Process the RADIUS frames from Authentication Server */ static RadiusRxResult ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, const u8 *shared_secret, size_t shared_secret_len, void *data) { struct eapol_test_data *e = data; struct radius_hdr *hdr = radius_msg_get_hdr(msg); /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be * present when packet contains an EAP-Message attribute */ if (hdr->code == RADIUS_CODE_ACCESS_REJECT && radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, 0) < 0 && radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { wpa_printf(MSG_DEBUG, "Allowing RADIUS " "Access-Reject without Message-Authenticator " "since it does not include EAP-Message\n"); } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 1)) { printf("Incoming RADIUS packet did not have correct " "Message-Authenticator - dropped\n"); return RADIUS_RX_UNKNOWN; } if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && hdr->code != RADIUS_CODE_ACCESS_REJECT && hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { printf("Unknown RADIUS message code\n"); return RADIUS_RX_UNKNOWN; } e->radius_identifier = -1; wpa_printf(MSG_DEBUG, "RADIUS packet matching with station"); radius_msg_free(e->last_recv_radius); e->last_recv_radius = msg; switch (hdr->code) { case RADIUS_CODE_ACCESS_ACCEPT: e->radius_access_accept_received = 1; ieee802_1x_get_keys(e, msg, req, shared_secret, shared_secret_len); break; case RADIUS_CODE_ACCESS_REJECT: e->radius_access_reject_received = 1; break; } ieee802_1x_decapsulate_radius(e); if ((hdr->code == RADIUS_CODE_ACCESS_ACCEPT && e->eapol_test_num_reauths < 0) || hdr->code == RADIUS_CODE_ACCESS_REJECT) { eloop_terminate(); } return RADIUS_RX_QUEUED; } static void wpa_init_conf(struct eapol_test_data *e, struct wpa_supplicant *wpa_s, const char *authsrv, int port, const char *secret, const char *cli_addr) { struct hostapd_radius_server *as; int res; wpa_s->bssid[5] = 1; os_memcpy(wpa_s->own_addr, e->own_addr, ETH_ALEN); e->own_ip_addr.s_addr = htonl((127 << 24) | 1); os_strlcpy(wpa_s->ifname, "test", sizeof(wpa_s->ifname)); e->radius_conf = os_zalloc(sizeof(struct hostapd_radius_servers)); assert(e->radius_conf != NULL); e->radius_conf->num_auth_servers = 1; as = os_zalloc(sizeof(struct hostapd_radius_server)); assert(as != NULL); #if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA) { int a[4]; u8 *pos; sscanf(authsrv, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]); pos = (u8 *) &as->addr.u.v4; *pos++ = a[0]; *pos++ = a[1]; *pos++ = a[2]; *pos++ = a[3]; } #else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */ inet_aton(authsrv, &as->addr.u.v4); #endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */ as->addr.af = AF_INET; as->port = port; as->shared_secret = (u8 *) os_strdup(secret); as->shared_secret_len = os_strlen(secret); e->radius_conf->auth_server = as; e->radius_conf->auth_servers = as; e->radius_conf->msg_dumps = 1; if (cli_addr) { if (hostapd_parse_ip_addr(cli_addr, &e->radius_conf->client_addr) == 0) e->radius_conf->force_client_addr = 1; else { wpa_printf(MSG_ERROR, "Invalid IP address '%s'", cli_addr); assert(0); } } e->radius = radius_client_init(wpa_s, e->radius_conf); assert(e->radius != NULL); res = radius_client_register(e->radius, RADIUS_AUTH, ieee802_1x_receive_auth, e); assert(res == 0); } static int scard_test(void) { struct scard_data *scard; size_t len; char imsi[20]; unsigned char _rand[16]; #ifdef PCSC_FUNCS unsigned char sres[4]; unsigned char kc[8]; #endif /* PCSC_FUNCS */ #define num_triplets 5 unsigned char rand_[num_triplets][16]; unsigned char sres_[num_triplets][4]; unsigned char kc_[num_triplets][8]; int i, res; size_t j; #define AKA_RAND_LEN 16 #define AKA_AUTN_LEN 16 #define AKA_AUTS_LEN 14 #define RES_MAX_LEN 16 #define IK_LEN 16 #define CK_LEN 16 unsigned char aka_rand[AKA_RAND_LEN]; unsigned char aka_autn[AKA_AUTN_LEN]; unsigned char aka_auts[AKA_AUTS_LEN]; unsigned char aka_res[RES_MAX_LEN]; size_t aka_res_len; unsigned char aka_ik[IK_LEN]; unsigned char aka_ck[CK_LEN]; scard = scard_init(NULL); if (scard == NULL) return -1; if (scard_set_pin(scard, "1234")) { wpa_printf(MSG_WARNING, "PIN validation failed"); scard_deinit(scard); return -1; } len = sizeof(imsi); if (scard_get_imsi(scard, imsi, &len)) goto failed; wpa_hexdump_ascii(MSG_DEBUG, "SCARD: IMSI", (u8 *) imsi, len); /* NOTE: Permanent Username: 1 | IMSI */ wpa_printf(MSG_DEBUG, "SCARD: MNC length %d", scard_get_mnc_len(scard)); os_memset(_rand, 0, sizeof(_rand)); if (scard_gsm_auth(scard, _rand, sres, kc)) goto failed; os_memset(_rand, 0xff, sizeof(_rand)); if (scard_gsm_auth(scard, _rand, sres, kc)) goto failed; for (i = 0; i < num_triplets; i++) { os_memset(rand_[i], i, sizeof(rand_[i])); if (scard_gsm_auth(scard, rand_[i], sres_[i], kc_[i])) goto failed; } for (i = 0; i < num_triplets; i++) { printf("1"); for (j = 0; j < len; j++) printf("%c", imsi[j]); printf(","); for (j = 0; j < 16; j++) printf("%02X", rand_[i][j]); printf(","); for (j = 0; j < 4; j++) printf("%02X", sres_[i][j]); printf(","); for (j = 0; j < 8; j++) printf("%02X", kc_[i][j]); printf("\n"); } wpa_printf(MSG_DEBUG, "Trying to use UMTS authentication"); /* seq 39 (0x28) */ os_memset(aka_rand, 0xaa, 16); os_memcpy(aka_autn, "\x86\x71\x31\xcb\xa2\xfc\x61\xdf" "\xa3\xb3\x97\x9d\x07\x32\xa2\x12", 16); res = scard_umts_auth(scard, aka_rand, aka_autn, aka_res, &aka_res_len, aka_ik, aka_ck, aka_auts); if (res == 0) { wpa_printf(MSG_DEBUG, "UMTS auth completed successfully"); wpa_hexdump(MSG_DEBUG, "RES", aka_res, aka_res_len); wpa_hexdump(MSG_DEBUG, "IK", aka_ik, IK_LEN); wpa_hexdump(MSG_DEBUG, "CK", aka_ck, CK_LEN); } else if (res == -2) { wpa_printf(MSG_DEBUG, "UMTS auth resulted in synchronization " "failure"); wpa_hexdump(MSG_DEBUG, "AUTS", aka_auts, AKA_AUTS_LEN); } else { wpa_printf(MSG_DEBUG, "UMTS auth failed"); } failed: scard_deinit(scard); return 0; #undef num_triplets } static int scard_get_triplets(int argc, char *argv[]) { struct scard_data *scard; size_t len; char imsi[20]; unsigned char _rand[16]; unsigned char sres[4]; unsigned char kc[8]; int num_triplets; int i; size_t j; if (argc < 2 || ((num_triplets = atoi(argv[1])) <= 0)) { printf("invalid parameters for sim command\n"); return -1; } if (argc <= 2 || os_strcmp(argv[2], "debug") != 0) { /* disable debug output */ wpa_debug_level = 99; } scard = scard_init(NULL); if (scard == NULL) { printf("Failed to open smartcard connection\n"); return -1; } if (scard_set_pin(scard, argv[0])) { wpa_printf(MSG_WARNING, "PIN validation failed"); scard_deinit(scard); return -1; } len = sizeof(imsi); if (scard_get_imsi(scard, imsi, &len)) { scard_deinit(scard); return -1; } for (i = 0; i < num_triplets; i++) { os_memset(_rand, i, sizeof(_rand)); if (scard_gsm_auth(scard, _rand, sres, kc)) break; /* IMSI:Kc:SRES:RAND */ for (j = 0; j < len; j++) printf("%c", imsi[j]); printf(":"); for (j = 0; j < 8; j++) printf("%02X", kc[j]); printf(":"); for (j = 0; j < 4; j++) printf("%02X", sres[j]); printf(":"); for (j = 0; j < 16; j++) printf("%02X", _rand[j]); printf("\n"); } scard_deinit(scard); return 0; } static void eapol_test_terminate(int sig, void *signal_ctx) { struct wpa_supplicant *wpa_s = signal_ctx; wpa_msg(wpa_s, MSG_INFO, "Signal %d received - terminating", sig); eloop_terminate(); } static void usage(void) { printf("usage:\n" "eapol_test [-enWS] -c [-a] [-p] " "[-s]\\\n" " [-r] [-t] [-C] \\\n" " [-M] [-o] \\\n" " [-A]\n" "eapol_test scard\n" "eapol_test sim [debug]\n" "\n"); printf("options:\n" " -c = configuration file\n" " -a = IP address of the authentication server, " "default 127.0.0.1\n" " -p = UDP port of the authentication server, " "default 1812\n" " -s = shared secret with the authentication " "server, default 'radius'\n" " -A = IP address of the client, default: select " "automatically\n" " -r = number of re-authentications\n" " -e = Request EAP-Key-Name\n" " -W = wait for a control interface monitor before starting\n" " -S = save configuration after authentication\n" " -n = no MPPE keys expected\n" " -t = sets timeout in seconds (default: 30 s)\n" " -C = RADIUS Connect-Info (default: " "CONNECT 11Mbps 802.11b)\n" " -M = Set own MAC address " "(Calling-Station-Id,\n" " default: 02:00:00:00:00:01)\n" " -o = Write received server certificate\n" " chain to the specified file\n" " -N = send arbitrary attribute specified by:\n" " attr_id:syntax:value or attr_id\n" " attr_id - number id of the attribute\n" " syntax - one of: s, d, x\n" " s = string\n" " d = integer\n" " x = octet string\n" " value - attribute value.\n" " When only attr_id is specified, NULL will be used as " "value.\n" " Multiple attributes can be specified by using the " "option several times.\n"); } int main(int argc, char *argv[]) { struct wpa_global global; struct wpa_supplicant wpa_s; int c, ret = 1, wait_for_monitor = 0, save_config = 0; char *as_addr = "127.0.0.1"; int as_port = 1812; char *as_secret = "radius"; char *cli_addr = NULL; char *conf = NULL; int timeout = 30; char *pos; struct extra_radius_attr *p = NULL, *p1; if (os_program_init()) return -1; hostapd_logger_register_cb(hostapd_logger_cb); os_memset(&eapol_test, 0, sizeof(eapol_test)); eapol_test.connect_info = "CONNECT 11Mbps 802.11b"; os_memcpy(eapol_test.own_addr, "\x02\x00\x00\x00\x00\x01", ETH_ALEN); wpa_debug_level = 0; wpa_debug_show_keys = 1; for (;;) { c = getopt(argc, argv, "a:A:c:C:eM:nN:o:p:r:s:St:W"); if (c < 0) break; switch (c) { case 'a': as_addr = optarg; break; case 'A': cli_addr = optarg; break; case 'c': conf = optarg; break; case 'C': eapol_test.connect_info = optarg; break; case 'e': eapol_test.req_eap_key_name = 1; break; case 'M': if (hwaddr_aton(optarg, eapol_test.own_addr)) { usage(); return -1; } break; case 'n': eapol_test.no_mppe_keys++; break; case 'o': if (eapol_test.server_cert_file) fclose(eapol_test.server_cert_file); eapol_test.server_cert_file = fopen(optarg, "w"); if (eapol_test.server_cert_file == NULL) { printf("Could not open '%s' for writing\n", optarg); return -1; } break; case 'p': as_port = atoi(optarg); break; case 'r': eapol_test.eapol_test_num_reauths = atoi(optarg); break; case 's': as_secret = optarg; break; case 'S': save_config++; break; case 't': timeout = atoi(optarg); break; case 'W': wait_for_monitor++; break; case 'N': p1 = os_zalloc(sizeof(*p1)); if (p1 == NULL) break; if (!p) eapol_test.extra_attrs = p1; else p->next = p1; p = p1; p->type = atoi(optarg); pos = os_strchr(optarg, ':'); if (pos == NULL) { p->syntax = 'n'; p->data = NULL; break; } pos++; if (pos[0] == '\0' || pos[1] != ':') { printf("Incorrect format of attribute " "specification\n"); break; } p->syntax = pos[0]; p->data = pos + 2; break; default: usage(); return -1; } } if (argc > optind && os_strcmp(argv[optind], "scard") == 0) { return scard_test(); } if (argc > optind && os_strcmp(argv[optind], "sim") == 0) { return scard_get_triplets(argc - optind - 1, &argv[optind + 1]); } if (conf == NULL) { usage(); printf("Configuration file is required.\n"); return -1; } if (eap_register_methods()) { wpa_printf(MSG_ERROR, "Failed to register EAP methods"); return -1; } if (eloop_init()) { wpa_printf(MSG_ERROR, "Failed to initialize event loop"); return -1; } os_memset(&global, 0, sizeof(global)); os_memset(&wpa_s, 0, sizeof(wpa_s)); wpa_s.global = &global; eapol_test.wpa_s = &wpa_s; dl_list_init(&wpa_s.bss); dl_list_init(&wpa_s.bss_id); wpa_s.conf = wpa_config_read(conf, NULL); if (wpa_s.conf == NULL) { printf("Failed to parse configuration file '%s'.\n", conf); return -1; } if (wpa_s.conf->ssid == NULL) { printf("No networks defined.\n"); return -1; } wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret, cli_addr); wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s); if (wpa_s.ctrl_iface == NULL) { printf("Failed to initialize control interface '%s'.\n" "You may have another eapol_test process already " "running or the file was\n" "left by an unclean termination of eapol_test in " "which case you will need\n" "to manually remove this file before starting " "eapol_test again.\n", wpa_s.conf->ctrl_interface); return -1; } if (wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid)) return -1; if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid)) return -1; if (wpas_init_ext_pw(&wpa_s) < 0) return -1; if (wait_for_monitor) wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface); eloop_register_timeout(timeout, 0, eapol_test_timeout, &eapol_test, NULL); eloop_register_timeout(0, 0, send_eap_request_identity, &wpa_s, NULL); eloop_register_signal_terminate(eapol_test_terminate, &wpa_s); eloop_register_signal_reconfig(eapol_test_terminate, &wpa_s); eloop_run(); eloop_cancel_timeout(eapol_test_timeout, &eapol_test, NULL); eloop_cancel_timeout(eapol_sm_reauth, &eapol_test, NULL); if (eapol_test_compare_pmk(&eapol_test) == 0 || eapol_test.no_mppe_keys) ret = 0; if (eapol_test.auth_timed_out) ret = -2; if (eapol_test.radius_access_reject_received) ret = -3; if (save_config) wpa_config_write(conf, wpa_s.conf); test_eapol_clean(&eapol_test, &wpa_s); eap_peer_unregister_methods(); #ifdef CONFIG_AP eap_server_unregister_methods(); #endif /* CONFIG_AP */ eloop_destroy(); if (eapol_test.server_cert_file) fclose(eapol_test.server_cert_file); printf("MPPE keys OK: %d mismatch: %d\n", eapol_test.num_mppe_ok, eapol_test.num_mppe_mismatch); if (eapol_test.num_mppe_mismatch) ret = -4; if (ret) printf("FAILURE\n"); else printf("SUCCESS\n"); os_program_deinit(); return ret; } wpa_supplicant-2.2/wpa_supplicant/main.c0000664000175000017500000002113212343617166016337 0ustar jmjm/* * WPA Supplicant / main() function for UNIX like OSes and MinGW * Copyright (c) 2003-2013, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #ifdef __linux__ #include #endif /* __linux__ */ #include "common.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "p2p_supplicant.h" static void usage(void) { int i; printf("%s\n\n%s\n" "usage:\n" " wpa_supplicant [-BddhKLqq" #ifdef CONFIG_DEBUG_SYSLOG "s" #endif /* CONFIG_DEBUG_SYSLOG */ "t" #ifdef CONFIG_DBUS "u" #endif /* CONFIG_DBUS */ "vW] [-P] " "[-g] \\\n" " [-G] \\\n" " -i -c [-C] [-D] " "[-p] \\\n" " [-b] [-e]" #ifdef CONFIG_DEBUG_FILE " [-f]" #endif /* CONFIG_DEBUG_FILE */ " \\\n" " [-o] [-O] \\\n" " [-N -i -c [-C] " "[-D] \\\n" #ifdef CONFIG_P2P " [-m] \\\n" #endif /* CONFIG_P2P */ " [-p] [-b] [-I] " "...]\n" "\n" "drivers:\n", wpa_supplicant_version, wpa_supplicant_license); for (i = 0; wpa_drivers[i]; i++) { printf(" %s = %s\n", wpa_drivers[i]->name, wpa_drivers[i]->desc); } #ifndef CONFIG_NO_STDOUT_DEBUG printf("options:\n" " -b = optional bridge interface name\n" " -B = run daemon in the background\n" " -c = Configuration file\n" " -C = ctrl_interface parameter (only used if -c is not)\n" " -i = interface name\n" " -I = additional configuration file\n" " -d = increase debugging verbosity (-dd even more)\n" " -D = driver name (can be multiple drivers: nl80211,wext)\n" " -e = entropy file\n"); #ifdef CONFIG_DEBUG_FILE printf(" -f = log output to debug file instead of stdout\n"); #endif /* CONFIG_DEBUG_FILE */ printf(" -g = global ctrl_interface\n" " -G = global ctrl_interface group\n" " -K = include keys (passwords, etc.) in debug output\n"); #ifdef CONFIG_DEBUG_SYSLOG printf(" -s = log output to syslog instead of stdout\n"); #endif /* CONFIG_DEBUG_SYSLOG */ #ifdef CONFIG_DEBUG_LINUX_TRACING printf(" -T = record to Linux tracing in addition to logging\n"); printf(" (records all messages regardless of debug verbosity)\n"); #endif /* CONFIG_DEBUG_LINUX_TRACING */ printf(" -t = include timestamp in debug messages\n" " -h = show this help text\n" " -L = show license (BSD)\n" " -o = override driver parameter for new interfaces\n" " -O = override ctrl_interface parameter for new interfaces\n" " -p = driver parameters\n" " -P = PID file\n" " -q = decrease debugging verbosity (-qq even less)\n"); #ifdef CONFIG_DBUS printf(" -u = enable DBus control interface\n"); #endif /* CONFIG_DBUS */ printf(" -v = show version\n" " -W = wait for a control interface monitor before starting\n" #ifdef CONFIG_P2P " -m = Configuration file for the P2P Device interface\n" #endif /* CONFIG_P2P */ " -N = start describing new interface\n"); printf("example:\n" " wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n", wpa_drivers[0] ? wpa_drivers[0]->name : "nl80211"); #endif /* CONFIG_NO_STDOUT_DEBUG */ } static void license(void) { #ifndef CONFIG_NO_STDOUT_DEBUG printf("%s\n\n%s%s%s%s%s\n", wpa_supplicant_version, wpa_supplicant_full_license1, wpa_supplicant_full_license2, wpa_supplicant_full_license3, wpa_supplicant_full_license4, wpa_supplicant_full_license5); #endif /* CONFIG_NO_STDOUT_DEBUG */ } static void wpa_supplicant_fd_workaround(int start) { #ifdef __linux__ static int fd[3] = { -1, -1, -1 }; int i; /* When started from pcmcia-cs scripts, wpa_supplicant might start with * fd 0, 1, and 2 closed. This will cause some issues because many * places in wpa_supplicant are still printing out to stdout. As a * workaround, make sure that fd's 0, 1, and 2 are not used for other * sockets. */ if (start) { for (i = 0; i < 3; i++) { fd[i] = open("/dev/null", O_RDWR); if (fd[i] > 2) { close(fd[i]); fd[i] = -1; break; } } } else { for (i = 0; i < 3; i++) { if (fd[i] >= 0) { close(fd[i]); fd[i] = -1; } } } #endif /* __linux__ */ } int main(int argc, char *argv[]) { int c, i; struct wpa_interface *ifaces, *iface; int iface_count, exitcode = -1; struct wpa_params params; struct wpa_global *global; if (os_program_init()) return -1; os_memset(¶ms, 0, sizeof(params)); params.wpa_debug_level = MSG_INFO; iface = ifaces = os_zalloc(sizeof(struct wpa_interface)); if (ifaces == NULL) return -1; iface_count = 1; wpa_supplicant_fd_workaround(1); for (;;) { c = getopt(argc, argv, "b:Bc:C:D:de:f:g:G:hi:I:KLm:No:O:p:P:qsTtuvW"); if (c < 0) break; switch (c) { case 'b': iface->bridge_ifname = optarg; break; case 'B': params.daemonize++; break; case 'c': iface->confname = optarg; break; case 'C': iface->ctrl_interface = optarg; break; case 'D': iface->driver = optarg; break; case 'd': #ifdef CONFIG_NO_STDOUT_DEBUG printf("Debugging disabled with " "CONFIG_NO_STDOUT_DEBUG=y build time " "option.\n"); goto out; #else /* CONFIG_NO_STDOUT_DEBUG */ params.wpa_debug_level--; break; #endif /* CONFIG_NO_STDOUT_DEBUG */ case 'e': params.entropy_file = optarg; break; #ifdef CONFIG_DEBUG_FILE case 'f': params.wpa_debug_file_path = optarg; break; #endif /* CONFIG_DEBUG_FILE */ case 'g': params.ctrl_interface = optarg; break; case 'G': params.ctrl_interface_group = optarg; break; case 'h': usage(); exitcode = 0; goto out; case 'i': iface->ifname = optarg; break; case 'I': iface->confanother = optarg; break; case 'K': params.wpa_debug_show_keys++; break; case 'L': license(); exitcode = 0; goto out; #ifdef CONFIG_P2P case 'm': iface->conf_p2p_dev = optarg; break; #endif /* CONFIG_P2P */ case 'o': params.override_driver = optarg; break; case 'O': params.override_ctrl_interface = optarg; break; case 'p': iface->driver_param = optarg; break; case 'P': os_free(params.pid_file); params.pid_file = os_rel2abs_path(optarg); break; case 'q': params.wpa_debug_level++; break; #ifdef CONFIG_DEBUG_SYSLOG case 's': params.wpa_debug_syslog++; break; #endif /* CONFIG_DEBUG_SYSLOG */ #ifdef CONFIG_DEBUG_LINUX_TRACING case 'T': params.wpa_debug_tracing++; break; #endif /* CONFIG_DEBUG_LINUX_TRACING */ case 't': params.wpa_debug_timestamp++; break; #ifdef CONFIG_DBUS case 'u': params.dbus_ctrl_interface = 1; break; #endif /* CONFIG_DBUS */ case 'v': printf("%s\n", wpa_supplicant_version); exitcode = 0; goto out; case 'W': params.wait_for_monitor++; break; case 'N': iface_count++; iface = os_realloc_array(ifaces, iface_count, sizeof(struct wpa_interface)); if (iface == NULL) goto out; ifaces = iface; iface = &ifaces[iface_count - 1]; os_memset(iface, 0, sizeof(*iface)); break; default: usage(); exitcode = 0; goto out; } } exitcode = 0; global = wpa_supplicant_init(¶ms); if (global == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant"); exitcode = -1; goto out; } else { wpa_printf(MSG_INFO, "Successfully initialized " "wpa_supplicant"); } for (i = 0; exitcode == 0 && i < iface_count; i++) { struct wpa_supplicant *wpa_s; if ((ifaces[i].confname == NULL && ifaces[i].ctrl_interface == NULL) || ifaces[i].ifname == NULL) { if (iface_count == 1 && (params.ctrl_interface || params.dbus_ctrl_interface)) break; usage(); exitcode = -1; break; } wpa_s = wpa_supplicant_add_iface(global, &ifaces[i]); if (wpa_s == NULL) { exitcode = -1; break; } #ifdef CONFIG_P2P if (wpa_s->global->p2p == NULL && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) && wpas_p2p_add_p2pdev_interface(wpa_s) < 0) exitcode = -1; #endif /* CONFIG_P2P */ } if (exitcode == 0) exitcode = wpa_supplicant_run(global); wpa_supplicant_deinit(global); out: wpa_supplicant_fd_workaround(0); os_free(ifaces); os_free(params.pid_file); os_program_deinit(); return exitcode; } wpa_supplicant-2.2/wpa_supplicant/autoscan_periodic.c0000664000175000017500000000315212343617166021110 0ustar jmjm/* * WPA Supplicant - auto scan periodic module * Copyright (c) 2012, Intel Corporation. All rights reserved. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include "common.h" #include "wpa_supplicant_i.h" #include "autoscan.h" struct autoscan_periodic_data { int periodic_interval; }; static int autoscan_periodic_get_params(struct autoscan_periodic_data *data, const char *params) { int interval; if (params == NULL) return -1; interval = atoi(params); if (interval < 0) return -1; data->periodic_interval = interval; return 0; } static void * autoscan_periodic_init(struct wpa_supplicant *wpa_s, const char *params) { struct autoscan_periodic_data *data; data = os_zalloc(sizeof(struct autoscan_periodic_data)); if (data == NULL) return NULL; if (autoscan_periodic_get_params(data, params) < 0) { os_free(data); return NULL; } wpa_printf(MSG_DEBUG, "autoscan periodic: interval is %d", data->periodic_interval); return data; } static void autoscan_periodic_deinit(void *priv) { struct autoscan_periodic_data *data = priv; os_free(data); } static int autoscan_periodic_notify_scan(void *priv, struct wpa_scan_results *scan_res) { struct autoscan_periodic_data *data = priv; wpa_printf(MSG_DEBUG, "autoscan periodic: scan result notification"); return data->periodic_interval; } const struct autoscan_ops autoscan_periodic_ops = { .name = "periodic", .init = autoscan_periodic_init, .deinit = autoscan_periodic_deinit, .notify_scan = autoscan_periodic_notify_scan, }; wpa_supplicant-2.2/wpa_supplicant/wifi_display.h0000664000175000017500000000134612343617166020110 0ustar jmjm/* * wpa_supplicant - Wi-Fi Display * Copyright (c) 2011, Atheros Communications, Inc. * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef WIFI_DISPLAY_H #define WIFI_DISPLAY_H int wifi_display_init(struct wpa_global *global); void wifi_display_deinit(struct wpa_global *global); void wifi_display_enable(struct wpa_global *global, int enabled); int wifi_display_subelem_set(struct wpa_global *global, char *cmd); int wifi_display_subelem_get(struct wpa_global *global, char *cmd, char *buf, size_t buflen); char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id); #endif /* WIFI_DISPLAY_H */ wpa_supplicant-2.2/wpa_supplicant/wpa_supplicant.c0000664000175000017500000040305512343617166020454 0ustar jmjm/* * WPA Supplicant * Copyright (c) 2003-2014, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. * * This file implements functions for registering and unregistering * %wpa_supplicant interfaces. In addition, this file contains number of * functions for managing network connections. */ #include "includes.h" #include "common.h" #include "crypto/random.h" #include "crypto/sha1.h" #include "eapol_supp/eapol_supp_sm.h" #include "eap_peer/eap.h" #include "eap_peer/eap_proxy.h" #include "eap_server/eap_methods.h" #include "rsn_supp/wpa.h" #include "eloop.h" #include "config.h" #include "utils/ext_password.h" #include "l2_packet/l2_packet.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "ctrl_iface.h" #include "pcsc_funcs.h" #include "common/version.h" #include "rsn_supp/preauth.h" #include "rsn_supp/pmksa_cache.h" #include "common/wpa_ctrl.h" #include "common/ieee802_11_defs.h" #include "p2p/p2p.h" #include "blacklist.h" #include "wpas_glue.h" #include "wps_supplicant.h" #include "ibss_rsn.h" #include "sme.h" #include "gas_query.h" #include "ap.h" #include "p2p_supplicant.h" #include "wifi_display.h" #include "notify.h" #include "bgscan.h" #include "autoscan.h" #include "bss.h" #include "scan.h" #include "offchannel.h" #include "hs20_supplicant.h" #include "wnm_sta.h" #include "wpas_kay.h" const char *wpa_supplicant_version = "wpa_supplicant v" VERSION_STR "\n" "Copyright (c) 2003-2014, Jouni Malinen and contributors"; const char *wpa_supplicant_license = "This software may be distributed under the terms of the BSD license.\n" "See README for more details.\n" #ifdef EAP_TLS_OPENSSL "\nThis product includes software developed by the OpenSSL Project\n" "for use in the OpenSSL Toolkit (http://www.openssl.org/)\n" #endif /* EAP_TLS_OPENSSL */ ; #ifndef CONFIG_NO_STDOUT_DEBUG /* Long text divided into parts in order to fit in C89 strings size limits. */ const char *wpa_supplicant_full_license1 = ""; const char *wpa_supplicant_full_license2 = "This software may be distributed under the terms of the BSD license.\n" "\n" "Redistribution and use in source and binary forms, with or without\n" "modification, are permitted provided that the following conditions are\n" "met:\n" "\n"; const char *wpa_supplicant_full_license3 = "1. Redistributions of source code must retain the above copyright\n" " notice, this list of conditions and the following disclaimer.\n" "\n" "2. Redistributions in binary form must reproduce the above copyright\n" " notice, this list of conditions and the following disclaimer in the\n" " documentation and/or other materials provided with the distribution.\n" "\n"; const char *wpa_supplicant_full_license4 = "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n" " names of its contributors may be used to endorse or promote products\n" " derived from this software without specific prior written permission.\n" "\n" "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"; const char *wpa_supplicant_full_license5 = "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" "\n"; #endif /* CONFIG_NO_STDOUT_DEBUG */ /* Configure default/group WEP keys for static WEP */ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { int i, set = 0; for (i = 0; i < NUM_WEP_KEYS; i++) { if (ssid->wep_key_len[i] == 0) continue; set = 1; wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL, i, i == ssid->wep_tx_keyidx, NULL, 0, ssid->wep_key[i], ssid->wep_key_len[i]); } return set; } int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { u8 key[32]; size_t keylen; enum wpa_alg alg; u8 seq[6] = { 0 }; /* IBSS/WPA-None uses only one key (Group) for both receiving and * sending unicast and multicast packets. */ if (ssid->mode != WPAS_MODE_IBSS) { wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid mode %d (not " "IBSS/ad-hoc) for WPA-None", ssid->mode); return -1; } if (!ssid->psk_set) { wpa_msg(wpa_s, MSG_INFO, "WPA: No PSK configured for " "WPA-None"); return -1; } switch (wpa_s->group_cipher) { case WPA_CIPHER_CCMP: os_memcpy(key, ssid->psk, 16); keylen = 16; alg = WPA_ALG_CCMP; break; case WPA_CIPHER_GCMP: os_memcpy(key, ssid->psk, 16); keylen = 16; alg = WPA_ALG_GCMP; break; case WPA_CIPHER_TKIP: /* WPA-None uses the same Michael MIC key for both TX and RX */ os_memcpy(key, ssid->psk, 16 + 8); os_memcpy(key + 16 + 8, ssid->psk + 16, 8); keylen = 32; alg = WPA_ALG_TKIP; break; default: wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid group cipher %d for " "WPA-None", wpa_s->group_cipher); return -1; } /* TODO: should actually remember the previously used seq#, both for TX * and RX from each STA.. */ return wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen); } static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; const u8 *bssid = wpa_s->bssid; if (is_zero_ether_addr(bssid)) bssid = wpa_s->pending_bssid; wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.", MAC2STR(bssid)); wpa_blacklist_add(wpa_s, bssid); wpa_sm_notify_disassoc(wpa_s->wpa); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); wpa_s->reassociate = 1; /* * If we timed out, the AP or the local radio may be busy. * So, wait a second until scanning again. */ wpa_supplicant_req_scan(wpa_s, 1, 0); } /** * wpa_supplicant_req_auth_timeout - Schedule a timeout for authentication * @wpa_s: Pointer to wpa_supplicant data * @sec: Number of seconds after which to time out authentication * @usec: Number of microseconds after which to time out authentication * * This function is used to schedule a timeout for the current authentication * attempt. */ void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s, int sec, int usec) { if (wpa_s->conf->ap_scan == 0 && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) return; wpa_dbg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec " "%d usec", sec, usec); eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL); } /** * wpa_supplicant_cancel_auth_timeout - Cancel authentication timeout * @wpa_s: Pointer to wpa_supplicant data * * This function is used to cancel authentication timeout scheduled with * wpa_supplicant_req_auth_timeout() and it is called when authentication has * been completed. */ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s) { wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout"); eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); wpa_blacklist_del(wpa_s, wpa_s->bssid); } /** * wpa_supplicant_initiate_eapol - Configure EAPOL state machine * @wpa_s: Pointer to wpa_supplicant data * * This function is used to configure EAPOL state machine based on the selected * authentication mode. */ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s) { #ifdef IEEE8021X_EAPOL struct eapol_config eapol_conf; struct wpa_ssid *ssid = wpa_s->current_ssid; #ifdef CONFIG_IBSS_RSN if (ssid->mode == WPAS_MODE_IBSS && wpa_s->key_mgmt != WPA_KEY_MGMT_NONE && wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) { /* * RSN IBSS authentication is per-STA and we can disable the * per-BSSID EAPOL authentication. */ eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized); eapol_sm_notify_eap_success(wpa_s->eapol, TRUE); eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE); return; } #endif /* CONFIG_IBSS_RSN */ eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE); if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized); else eapol_sm_notify_portControl(wpa_s->eapol, Auto); os_memset(&eapol_conf, 0, sizeof(eapol_conf)); if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { eapol_conf.accept_802_1x_keys = 1; eapol_conf.required_keys = 0; if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_UNICAST) { eapol_conf.required_keys |= EAPOL_REQUIRE_KEY_UNICAST; } if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_BROADCAST) { eapol_conf.required_keys |= EAPOL_REQUIRE_KEY_BROADCAST; } if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED) eapol_conf.required_keys = 0; } eapol_conf.fast_reauth = wpa_s->conf->fast_reauth; eapol_conf.workaround = ssid->eap_workaround; eapol_conf.eap_disabled = !wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) && wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA && wpa_s->key_mgmt != WPA_KEY_MGMT_WPS; eapol_conf.external_sim = wpa_s->conf->external_sim; eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf); #endif /* IEEE8021X_EAPOL */ ieee802_1x_alloc_kay_sm(wpa_s, ssid); } /** * wpa_supplicant_set_non_wpa_policy - Set WPA parameters to non-WPA mode * @wpa_s: Pointer to wpa_supplicant data * @ssid: Configuration data for the network * * This function is used to configure WPA state machine and related parameters * to a mode where WPA is not enabled. This is called as part of the * authentication configuration when the selected network does not use WPA. */ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { int i; if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) wpa_s->key_mgmt = WPA_KEY_MGMT_WPS; else if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA; else wpa_s->key_mgmt = WPA_KEY_MGMT_NONE; wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0); wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0); wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); wpa_s->pairwise_cipher = WPA_CIPHER_NONE; wpa_s->group_cipher = WPA_CIPHER_NONE; wpa_s->mgmt_group_cipher = 0; for (i = 0; i < NUM_WEP_KEYS; i++) { if (ssid->wep_key_len[i] > 5) { wpa_s->pairwise_cipher = WPA_CIPHER_WEP104; wpa_s->group_cipher = WPA_CIPHER_WEP104; break; } else if (ssid->wep_key_len[i] > 0) { wpa_s->pairwise_cipher = WPA_CIPHER_WEP40; wpa_s->group_cipher = WPA_CIPHER_WEP40; break; } } wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE, wpa_s->pairwise_cipher); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher); #ifdef CONFIG_IEEE80211W wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP, wpa_s->mgmt_group_cipher); #endif /* CONFIG_IEEE80211W */ pmksa_cache_clear_current(wpa_s->wpa); } void free_hw_features(struct wpa_supplicant *wpa_s) { int i; if (wpa_s->hw.modes == NULL) return; for (i = 0; i < wpa_s->hw.num_modes; i++) { os_free(wpa_s->hw.modes[i].channels); os_free(wpa_s->hw.modes[i].rates); } os_free(wpa_s->hw.modes); wpa_s->hw.modes = NULL; } static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) { bgscan_deinit(wpa_s); autoscan_deinit(wpa_s); scard_deinit(wpa_s->scard); wpa_s->scard = NULL; wpa_sm_set_scard_ctx(wpa_s->wpa, NULL); eapol_sm_register_scard_ctx(wpa_s->eapol, NULL); l2_packet_deinit(wpa_s->l2); wpa_s->l2 = NULL; if (wpa_s->l2_br) { l2_packet_deinit(wpa_s->l2_br); wpa_s->l2_br = NULL; } if (wpa_s->conf != NULL) { struct wpa_ssid *ssid; for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) wpas_notify_network_removed(wpa_s, ssid); } os_free(wpa_s->confname); wpa_s->confname = NULL; os_free(wpa_s->confanother); wpa_s->confanother = NULL; #ifdef CONFIG_P2P os_free(wpa_s->conf_p2p_dev); wpa_s->conf_p2p_dev = NULL; #endif /* CONFIG_P2P */ wpa_sm_set_eapol(wpa_s->wpa, NULL); eapol_sm_deinit(wpa_s->eapol); wpa_s->eapol = NULL; rsn_preauth_deinit(wpa_s->wpa); #ifdef CONFIG_TDLS wpa_tdls_deinit(wpa_s->wpa); #endif /* CONFIG_TDLS */ pmksa_candidate_free(wpa_s->wpa); wpa_sm_deinit(wpa_s->wpa); wpa_s->wpa = NULL; wpa_blacklist_clear(wpa_s); wpa_bss_deinit(wpa_s); wpa_supplicant_cancel_delayed_sched_scan(wpa_s); wpa_supplicant_cancel_scan(wpa_s); wpa_supplicant_cancel_auth_timeout(wpa_s); eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL); #ifdef CONFIG_DELAYED_MIC_ERROR_REPORT eloop_cancel_timeout(wpa_supplicant_delayed_mic_error_report, wpa_s, NULL); #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */ wpas_wps_deinit(wpa_s); wpabuf_free(wpa_s->pending_eapol_rx); wpa_s->pending_eapol_rx = NULL; #ifdef CONFIG_IBSS_RSN ibss_rsn_deinit(wpa_s->ibss_rsn); wpa_s->ibss_rsn = NULL; #endif /* CONFIG_IBSS_RSN */ sme_deinit(wpa_s); #ifdef CONFIG_AP wpa_supplicant_ap_deinit(wpa_s); #endif /* CONFIG_AP */ #ifdef CONFIG_P2P wpas_p2p_deinit(wpa_s); #endif /* CONFIG_P2P */ #ifdef CONFIG_OFFCHANNEL offchannel_deinit(wpa_s); #endif /* CONFIG_OFFCHANNEL */ wpa_supplicant_cancel_sched_scan(wpa_s); os_free(wpa_s->next_scan_freqs); wpa_s->next_scan_freqs = NULL; os_free(wpa_s->manual_scan_freqs); wpa_s->manual_scan_freqs = NULL; os_free(wpa_s->manual_sched_scan_freqs); wpa_s->manual_sched_scan_freqs = NULL; gas_query_deinit(wpa_s->gas); wpa_s->gas = NULL; free_hw_features(wpa_s); ieee802_1x_dealloc_kay_sm(wpa_s); os_free(wpa_s->bssid_filter); wpa_s->bssid_filter = NULL; os_free(wpa_s->disallow_aps_bssid); wpa_s->disallow_aps_bssid = NULL; os_free(wpa_s->disallow_aps_ssid); wpa_s->disallow_aps_ssid = NULL; wnm_bss_keep_alive_deinit(wpa_s); #ifdef CONFIG_WNM wnm_deallocate_memory(wpa_s); #endif /* CONFIG_WNM */ ext_password_deinit(wpa_s->ext_pw); wpa_s->ext_pw = NULL; wpabuf_free(wpa_s->last_gas_resp); wpa_s->last_gas_resp = NULL; wpabuf_free(wpa_s->prev_gas_resp); wpa_s->prev_gas_resp = NULL; os_free(wpa_s->last_scan_res); wpa_s->last_scan_res = NULL; #ifdef CONFIG_HS20 hs20_deinit(wpa_s); #endif /* CONFIG_HS20 */ } /** * wpa_clear_keys - Clear keys configured for the driver * @wpa_s: Pointer to wpa_supplicant data * @addr: Previously used BSSID or %NULL if not available * * This function clears the encryption keys that has been previously configured * for the driver. */ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr) { int i, max; #ifdef CONFIG_IEEE80211W max = 6; #else /* CONFIG_IEEE80211W */ max = 4; #endif /* CONFIG_IEEE80211W */ /* MLME-DELETEKEYS.request */ for (i = 0; i < max; i++) { if (wpa_s->keys_cleared & BIT(i)) continue; wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0, NULL, 0); } if (!(wpa_s->keys_cleared & BIT(0)) && addr && !is_zero_ether_addr(addr)) { wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL, 0); /* MLME-SETPROTECTION.request(None) */ wpa_drv_mlme_setprotection( wpa_s, addr, MLME_SETPROTECTION_PROTECT_TYPE_NONE, MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); } wpa_s->keys_cleared = (u32) -1; } /** * wpa_supplicant_state_txt - Get the connection state name as a text string * @state: State (wpa_state; WPA_*) * Returns: The state name as a printable text string */ const char * wpa_supplicant_state_txt(enum wpa_states state) { switch (state) { case WPA_DISCONNECTED: return "DISCONNECTED"; case WPA_INACTIVE: return "INACTIVE"; case WPA_INTERFACE_DISABLED: return "INTERFACE_DISABLED"; case WPA_SCANNING: return "SCANNING"; case WPA_AUTHENTICATING: return "AUTHENTICATING"; case WPA_ASSOCIATING: return "ASSOCIATING"; case WPA_ASSOCIATED: return "ASSOCIATED"; case WPA_4WAY_HANDSHAKE: return "4WAY_HANDSHAKE"; case WPA_GROUP_HANDSHAKE: return "GROUP_HANDSHAKE"; case WPA_COMPLETED: return "COMPLETED"; default: return "UNKNOWN"; } } #ifdef CONFIG_BGSCAN static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s) { const char *name; if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan) name = wpa_s->current_ssid->bgscan; else name = wpa_s->conf->bgscan; if (name == NULL || name[0] == '\0') return; if (wpas_driver_bss_selection(wpa_s)) return; if (wpa_s->current_ssid == wpa_s->bgscan_ssid) return; #ifdef CONFIG_P2P if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) return; #endif /* CONFIG_P2P */ bgscan_deinit(wpa_s); if (wpa_s->current_ssid) { if (bgscan_init(wpa_s, wpa_s->current_ssid, name)) { wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize " "bgscan"); /* * Live without bgscan; it is only used as a roaming * optimization, so the initial connection is not * affected. */ } else { struct wpa_scan_results *scan_res; wpa_s->bgscan_ssid = wpa_s->current_ssid; scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0); if (scan_res) { bgscan_notify_scan(wpa_s, scan_res); wpa_scan_results_free(scan_res); } } } else wpa_s->bgscan_ssid = NULL; } static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s) { if (wpa_s->bgscan_ssid != NULL) { bgscan_deinit(wpa_s); wpa_s->bgscan_ssid = NULL; } } #endif /* CONFIG_BGSCAN */ static void wpa_supplicant_start_autoscan(struct wpa_supplicant *wpa_s) { if (autoscan_init(wpa_s, 0)) wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize autoscan"); } static void wpa_supplicant_stop_autoscan(struct wpa_supplicant *wpa_s) { autoscan_deinit(wpa_s); } void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s) { if (wpa_s->wpa_state == WPA_DISCONNECTED || wpa_s->wpa_state == WPA_SCANNING) { autoscan_deinit(wpa_s); wpa_supplicant_start_autoscan(wpa_s); } } /** * wpa_supplicant_set_state - Set current connection state * @wpa_s: Pointer to wpa_supplicant data * @state: The new connection state * * This function is called whenever the connection state changes, e.g., * association is completed for WPA/WPA2 4-Way Handshake is started. */ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, enum wpa_states state) { enum wpa_states old_state = wpa_s->wpa_state; wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s", wpa_supplicant_state_txt(wpa_s->wpa_state), wpa_supplicant_state_txt(state)); if (state == WPA_INTERFACE_DISABLED) { /* Assure normal scan when interface is restored */ wpa_s->normal_scans = 0; } if (state == WPA_COMPLETED) { wpas_connect_work_done(wpa_s); /* Reinitialize normal_scan counter */ wpa_s->normal_scans = 0; } if (state != WPA_SCANNING) wpa_supplicant_notify_scanning(wpa_s, 0); if (state == WPA_COMPLETED && wpa_s->new_connection) { struct wpa_ssid *ssid = wpa_s->current_ssid; #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to " MACSTR " completed [id=%d id_str=%s]", MAC2STR(wpa_s->bssid), ssid ? ssid->id : -1, ssid && ssid->id_str ? ssid->id_str : ""); #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ wpas_clear_temp_disabled(wpa_s, ssid, 1); wpa_s->extra_blacklist_count = 0; wpa_s->new_connection = 0; wpa_drv_set_operstate(wpa_s, 1); #ifndef IEEE8021X_EAPOL wpa_drv_set_supp_port(wpa_s, 1); #endif /* IEEE8021X_EAPOL */ wpa_s->after_wps = 0; wpa_s->known_wps_freq = 0; #ifdef CONFIG_P2P wpas_p2p_completed(wpa_s); #endif /* CONFIG_P2P */ sme_sched_obss_scan(wpa_s, 1); } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING || state == WPA_ASSOCIATED) { wpa_s->new_connection = 1; wpa_drv_set_operstate(wpa_s, 0); #ifndef IEEE8021X_EAPOL wpa_drv_set_supp_port(wpa_s, 0); #endif /* IEEE8021X_EAPOL */ sme_sched_obss_scan(wpa_s, 0); } wpa_s->wpa_state = state; #ifdef CONFIG_BGSCAN if (state == WPA_COMPLETED) wpa_supplicant_start_bgscan(wpa_s); else if (state < WPA_ASSOCIATED) wpa_supplicant_stop_bgscan(wpa_s); #endif /* CONFIG_BGSCAN */ if (state == WPA_AUTHENTICATING) wpa_supplicant_stop_autoscan(wpa_s); if (state == WPA_DISCONNECTED || state == WPA_INACTIVE) wpa_supplicant_start_autoscan(wpa_s); if (wpa_s->wpa_state != old_state) { wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state); if (wpa_s->wpa_state == WPA_COMPLETED || old_state == WPA_COMPLETED) wpas_notify_auth_changed(wpa_s); } } void wpa_supplicant_terminate_proc(struct wpa_global *global) { int pending = 0; #ifdef CONFIG_WPS struct wpa_supplicant *wpa_s = global->ifaces; while (wpa_s) { struct wpa_supplicant *next = wpa_s->next; if (wpas_wps_terminate_pending(wpa_s) == 1) pending = 1; #ifdef CONFIG_P2P if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE || (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)) wpas_p2p_disconnect(wpa_s); #endif /* CONFIG_P2P */ wpa_s = next; } #endif /* CONFIG_WPS */ if (pending) return; eloop_terminate(); } static void wpa_supplicant_terminate(int sig, void *signal_ctx) { struct wpa_global *global = signal_ctx; wpa_supplicant_terminate_proc(global); } void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s) { enum wpa_states old_state = wpa_s->wpa_state; wpa_s->pairwise_cipher = 0; wpa_s->group_cipher = 0; wpa_s->mgmt_group_cipher = 0; wpa_s->key_mgmt = 0; if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); if (wpa_s->wpa_state != old_state) wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state); } /** * wpa_supplicant_reload_configuration - Reload configuration data * @wpa_s: Pointer to wpa_supplicant data * Returns: 0 on success or -1 if configuration parsing failed * * This function can be used to request that the configuration data is reloaded * (e.g., after configuration file change). This function is reloading * configuration only for one interface, so this may need to be called multiple * times if %wpa_supplicant is controlling multiple interfaces and all * interfaces need reconfiguration. */ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s) { struct wpa_config *conf; int reconf_ctrl; int old_ap_scan; if (wpa_s->confname == NULL) return -1; conf = wpa_config_read(wpa_s->confname, NULL); if (conf == NULL) { wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration " "file '%s' - exiting", wpa_s->confname); return -1; } wpa_config_read(wpa_s->confanother, conf); conf->changed_parameters = (unsigned int) -1; reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface || (conf->ctrl_interface && wpa_s->conf->ctrl_interface && os_strcmp(conf->ctrl_interface, wpa_s->conf->ctrl_interface) != 0); if (reconf_ctrl && wpa_s->ctrl_iface) { wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); wpa_s->ctrl_iface = NULL; } eapol_sm_invalidate_cached_session(wpa_s->eapol); if (wpa_s->current_ssid) { wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); } /* * TODO: should notify EAPOL SM about changes in opensc_engine_path, * pkcs11_engine_path, pkcs11_module_path. */ if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) { /* * Clear forced success to clear EAP state for next * authentication. */ eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); } eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_sm_set_config(wpa_s->wpa, NULL); wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL); wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth); rsn_preauth_deinit(wpa_s->wpa); old_ap_scan = wpa_s->conf->ap_scan; wpa_config_free(wpa_s->conf); wpa_s->conf = conf; if (old_ap_scan != wpa_s->conf->ap_scan) wpas_notify_ap_scan_changed(wpa_s); if (reconf_ctrl) wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s); wpa_supplicant_update_config(wpa_s); wpa_supplicant_clear_status(wpa_s); if (wpa_supplicant_enabled_networks(wpa_s)) { wpa_s->reassociate = 1; wpa_supplicant_req_scan(wpa_s, 0, 0); } wpa_dbg(wpa_s, MSG_DEBUG, "Reconfiguration completed"); return 0; } static void wpa_supplicant_reconfig(int sig, void *signal_ctx) { struct wpa_global *global = signal_ctx; struct wpa_supplicant *wpa_s; for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { wpa_dbg(wpa_s, MSG_DEBUG, "Signal %d received - reconfiguring", sig); if (wpa_supplicant_reload_configuration(wpa_s) < 0) { wpa_supplicant_terminate_proc(global); } } } static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_ie_data *ie) { int ret = wpa_sm_parse_own_wpa_ie(wpa_s->wpa, ie); if (ret) { if (ret == -2) { wpa_msg(wpa_s, MSG_INFO, "WPA: Failed to parse WPA IE " "from association info"); } return -1; } wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set " "cipher suites"); if (!(ie->group_cipher & ssid->group_cipher)) { wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled group " "cipher 0x%x (mask 0x%x) - reject", ie->group_cipher, ssid->group_cipher); return -1; } if (!(ie->pairwise_cipher & ssid->pairwise_cipher)) { wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled pairwise " "cipher 0x%x (mask 0x%x) - reject", ie->pairwise_cipher, ssid->pairwise_cipher); return -1; } if (!(ie->key_mgmt & ssid->key_mgmt)) { wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled key " "management 0x%x (mask 0x%x) - reject", ie->key_mgmt, ssid->key_mgmt); return -1; } #ifdef CONFIG_IEEE80211W if (!(ie->capabilities & WPA_CAPABILITY_MFPC) && (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ? wpa_s->conf->pmf : ssid->ieee80211w) == MGMT_FRAME_PROTECTION_REQUIRED) { wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP " "that does not support management frame protection - " "reject"); return -1; } #endif /* CONFIG_IEEE80211W */ return 0; } /** * wpa_supplicant_set_suites - Set authentication and encryption parameters * @wpa_s: Pointer to wpa_supplicant data * @bss: Scan results for the selected BSS, or %NULL if not available * @ssid: Configuration data for the selected network * @wpa_ie: Buffer for the WPA/RSN IE * @wpa_ie_len: Maximum wpa_ie buffer size on input. This is changed to be the * used buffer length in case the functions returns success. * Returns: 0 on success or -1 on failure * * This function is used to configure authentication and encryption parameters * based on the network configuration and scan result for the selected BSS (if * available). */ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid, u8 *wpa_ie, size_t *wpa_ie_len) { struct wpa_ie_data ie; int sel, proto; const u8 *bss_wpa, *bss_rsn, *bss_osen; if (bss) { bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN); bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); } else bss_wpa = bss_rsn = bss_osen = NULL; if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) && wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 && (ie.group_cipher & ssid->group_cipher) && (ie.pairwise_cipher & ssid->pairwise_cipher) && (ie.key_mgmt & ssid->key_mgmt)) { wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0"); proto = WPA_PROTO_RSN; } else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) && wpa_parse_wpa_ie(bss_wpa, 2 +bss_wpa[1], &ie) == 0 && (ie.group_cipher & ssid->group_cipher) && (ie.pairwise_cipher & ssid->pairwise_cipher) && (ie.key_mgmt & ssid->key_mgmt)) { wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0"); proto = WPA_PROTO_WPA; #ifdef CONFIG_HS20 } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN)) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using OSEN"); /* TODO: parse OSEN element */ ie.group_cipher = WPA_CIPHER_CCMP; ie.pairwise_cipher = WPA_CIPHER_CCMP; ie.key_mgmt = WPA_KEY_MGMT_OSEN; proto = WPA_PROTO_OSEN; #endif /* CONFIG_HS20 */ } else if (bss) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN"); return -1; } else { if (ssid->proto & WPA_PROTO_OSEN) proto = WPA_PROTO_OSEN; else if (ssid->proto & WPA_PROTO_RSN) proto = WPA_PROTO_RSN; else proto = WPA_PROTO_WPA; if (wpa_supplicant_suites_from_ai(wpa_s, ssid, &ie) < 0) { os_memset(&ie, 0, sizeof(ie)); ie.group_cipher = ssid->group_cipher; ie.pairwise_cipher = ssid->pairwise_cipher; ie.key_mgmt = ssid->key_mgmt; #ifdef CONFIG_IEEE80211W ie.mgmt_group_cipher = ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION ? WPA_CIPHER_AES_128_CMAC : 0; #endif /* CONFIG_IEEE80211W */ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites " "based on configuration"); } else proto = ie.proto; } wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d " "pairwise %d key_mgmt %d proto %d", ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto); #ifdef CONFIG_IEEE80211W if (ssid->ieee80211w) { wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d", ie.mgmt_group_cipher); } #endif /* CONFIG_IEEE80211W */ wpa_s->wpa_proto = proto; wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, !!(ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN))); if (bss || !wpa_s->ap_ies_from_associnfo) { if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa, bss_wpa ? 2 + bss_wpa[1] : 0) || wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn, bss_rsn ? 2 + bss_rsn[1] : 0)) return -1; } sel = ie.group_cipher & ssid->group_cipher; wpa_s->group_cipher = wpa_pick_group_cipher(sel); if (wpa_s->group_cipher < 0) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group " "cipher"); return -1; } wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK %s", wpa_cipher_txt(wpa_s->group_cipher)); sel = ie.pairwise_cipher & ssid->pairwise_cipher; wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1); if (wpa_s->pairwise_cipher < 0) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise " "cipher"); return -1; } wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s", wpa_cipher_txt(wpa_s->pairwise_cipher)); sel = ie.key_mgmt & ssid->key_mgmt; #ifdef CONFIG_SAE if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE); #endif /* CONFIG_SAE */ if (0) { #ifdef CONFIG_IEEE80211R } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) { wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X"); } else if (sel & WPA_KEY_MGMT_FT_PSK) { wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK"); #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_SAE } else if (sel & WPA_KEY_MGMT_SAE) { wpa_s->key_mgmt = WPA_KEY_MGMT_SAE; wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE"); } else if (sel & WPA_KEY_MGMT_FT_SAE) { wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE; wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE"); #endif /* CONFIG_SAE */ #ifdef CONFIG_IEEE80211W } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) { wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X with SHA256"); } else if (sel & WPA_KEY_MGMT_PSK_SHA256) { wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT PSK with SHA256"); #endif /* CONFIG_IEEE80211W */ } else if (sel & WPA_KEY_MGMT_IEEE8021X) { wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X"); } else if (sel & WPA_KEY_MGMT_PSK) { wpa_s->key_mgmt = WPA_KEY_MGMT_PSK; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK"); } else if (sel & WPA_KEY_MGMT_WPA_NONE) { wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE"); #ifdef CONFIG_HS20 } else if (sel & WPA_KEY_MGMT_OSEN) { wpa_s->key_mgmt = WPA_KEY_MGMT_OSEN; wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using KEY_MGMT OSEN"); #endif /* CONFIG_HS20 */ } else { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select " "authenticated key management type"); return -1; } wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE, wpa_s->pairwise_cipher); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher); #ifdef CONFIG_IEEE80211W sel = ie.mgmt_group_cipher; if ((ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ? wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION || !(ie.capabilities & WPA_CAPABILITY_MFPC)) sel = 0; if (sel & WPA_CIPHER_AES_128_CMAC) { wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher " "AES-128-CMAC"); } else if (sel & WPA_CIPHER_BIP_GMAC_128) { wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_128; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher " "BIP-GMAC-128"); } else if (sel & WPA_CIPHER_BIP_GMAC_256) { wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_256; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher " "BIP-GMAC-256"); } else if (sel & WPA_CIPHER_BIP_CMAC_256) { wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_CMAC_256; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher " "BIP-CMAC-256"); } else { wpa_s->mgmt_group_cipher = 0; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher"); } wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP, wpa_s->mgmt_group_cipher); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ? wpa_s->conf->pmf : ssid->ieee80211w)); #endif /* CONFIG_IEEE80211W */ if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE"); return -1; } if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) { wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN); #ifndef CONFIG_NO_PBKDF2 if (bss && ssid->bssid_set && ssid->ssid_len == 0 && ssid->passphrase) { u8 psk[PMK_LEN]; pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len, 4096, psk, PMK_LEN); wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", psk, PMK_LEN); wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN); } #endif /* CONFIG_NO_PBKDF2 */ #ifdef CONFIG_EXT_PASSWORD if (ssid->ext_psk) { struct wpabuf *pw = ext_password_get(wpa_s->ext_pw, ssid->ext_psk); char pw_str[64 + 1]; u8 psk[PMK_LEN]; if (pw == NULL) { wpa_msg(wpa_s, MSG_INFO, "EXT PW: No PSK " "found from external storage"); return -1; } if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) { wpa_msg(wpa_s, MSG_INFO, "EXT PW: Unexpected " "PSK length %d in external storage", (int) wpabuf_len(pw)); ext_password_free(pw); return -1; } os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw)); pw_str[wpabuf_len(pw)] = '\0'; #ifndef CONFIG_NO_PBKDF2 if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss) { pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len, 4096, psk, PMK_LEN); os_memset(pw_str, 0, sizeof(pw_str)); wpa_hexdump_key(MSG_MSGDUMP, "PSK (from " "external passphrase)", psk, PMK_LEN); wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN); } else #endif /* CONFIG_NO_PBKDF2 */ if (wpabuf_len(pw) == 2 * PMK_LEN) { if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) { wpa_msg(wpa_s, MSG_INFO, "EXT PW: " "Invalid PSK hex string"); os_memset(pw_str, 0, sizeof(pw_str)); ext_password_free(pw); return -1; } wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN); } else { wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable " "PSK available"); os_memset(pw_str, 0, sizeof(pw_str)); ext_password_free(pw); return -1; } os_memset(pw_str, 0, sizeof(pw_str)); ext_password_free(pw); } #endif /* CONFIG_EXT_PASSWORD */ } else wpa_sm_set_pmk_from_pmksa(wpa_s->wpa); return 0; } static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) { *pos = 0x00; switch (idx) { case 0: /* Bits 0-7 */ break; case 1: /* Bits 8-15 */ break; case 2: /* Bits 16-23 */ #ifdef CONFIG_WNM *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */ *pos |= 0x08; /* Bit 19 - BSS Transition */ #endif /* CONFIG_WNM */ break; case 3: /* Bits 24-31 */ #ifdef CONFIG_WNM *pos |= 0x02; /* Bit 25 - SSID List */ #endif /* CONFIG_WNM */ #ifdef CONFIG_INTERWORKING if (wpa_s->conf->interworking) *pos |= 0x80; /* Bit 31 - Interworking */ #endif /* CONFIG_INTERWORKING */ break; case 4: /* Bits 32-39 */ #ifdef CONFIG_INTERWORKING if (wpa_s->drv_flags / WPA_DRIVER_FLAGS_QOS_MAPPING) *pos |= 0x01; /* Bit 32 - QoS Map */ #endif /* CONFIG_INTERWORKING */ break; case 5: /* Bits 40-47 */ #ifdef CONFIG_HS20 if (wpa_s->conf->hs20) *pos |= 0x40; /* Bit 46 - WNM-Notification */ #endif /* CONFIG_HS20 */ break; case 6: /* Bits 48-55 */ break; } } int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf) { u8 *pos = buf; u8 len = 6, i; if (len < wpa_s->extended_capa_len) len = wpa_s->extended_capa_len; *pos++ = WLAN_EID_EXT_CAPAB; *pos++ = len; for (i = 0; i < len; i++, pos++) { wpas_ext_capab_byte(wpa_s, pos, i); if (i < wpa_s->extended_capa_len) { *pos &= ~wpa_s->extended_capa_mask[i]; *pos |= wpa_s->extended_capa[i]; } } while (len > 0 && buf[1 + len] == 0) { len--; buf[1] = len; } if (len == 0) return 0; return 2 + len; } static int wpas_valid_bss(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss) { struct wpa_bss *bss; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (bss == test_bss) return 1; } return 0; } static int wpas_valid_ssid(struct wpa_supplicant *wpa_s, struct wpa_ssid *test_ssid) { struct wpa_ssid *ssid; for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (ssid == test_ssid) return 1; } return 0; } int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss, struct wpa_ssid *test_ssid) { if (test_bss && !wpas_valid_bss(wpa_s, test_bss)) return 0; return test_ssid == NULL || wpas_valid_ssid(wpa_s, test_ssid); } void wpas_connect_work_free(struct wpa_connect_work *cwork) { if (cwork == NULL) return; os_free(cwork); } void wpas_connect_work_done(struct wpa_supplicant *wpa_s) { struct wpa_connect_work *cwork; struct wpa_radio_work *work = wpa_s->connect_work; if (!work) return; wpa_s->connect_work = NULL; cwork = work->ctx; work->ctx = NULL; wpas_connect_work_free(cwork); radio_work_done(work); } static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit); /** * wpa_supplicant_associate - Request association * @wpa_s: Pointer to wpa_supplicant data * @bss: Scan results for the selected BSS, or %NULL if not available * @ssid: Configuration data for the selected network * * This function is used to request %wpa_supplicant to associate with a BSS. */ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid) { struct wpa_connect_work *cwork; #ifdef CONFIG_IBSS_RSN ibss_rsn_deinit(wpa_s->ibss_rsn); wpa_s->ibss_rsn = NULL; #endif /* CONFIG_IBSS_RSN */ if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO || ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) { #ifdef CONFIG_AP if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) { wpa_msg(wpa_s, MSG_INFO, "Driver does not support AP " "mode"); return; } if (wpa_supplicant_create_ap(wpa_s, ssid) < 0) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) wpas_p2p_ap_setup_failed(wpa_s); return; } wpa_s->current_bss = bss; #else /* CONFIG_AP */ wpa_msg(wpa_s, MSG_ERROR, "AP mode support not included in " "the build"); #endif /* CONFIG_AP */ return; } #ifdef CONFIG_TDLS if (bss) wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1), bss->ie_len); #endif /* CONFIG_TDLS */ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && ssid->mode == IEEE80211_MODE_INFRA) { sme_authenticate(wpa_s, bss, ssid); return; } if (wpa_s->connect_work) { wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since connect_work exist"); return; } if (radio_work_pending(wpa_s, "connect")) { wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since pending work exist"); return; } cwork = os_zalloc(sizeof(*cwork)); if (cwork == NULL) return; cwork->bss = bss; cwork->ssid = ssid; if (radio_add_work(wpa_s, bss ? bss->freq : 0, "connect", 1, wpas_start_assoc_cb, cwork) < 0) { os_free(cwork); } } static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) { struct wpa_connect_work *cwork = work->ctx; struct wpa_bss *bss = cwork->bss; struct wpa_ssid *ssid = cwork->ssid; struct wpa_supplicant *wpa_s = work->wpa_s; u8 wpa_ie[200]; size_t wpa_ie_len; int use_crypt, ret, i, bssid_changed; int algs = WPA_AUTH_ALG_OPEN; unsigned int cipher_pairwise, cipher_group; struct wpa_driver_associate_params params; int wep_keys_set = 0; int assoc_failed = 0; struct wpa_ssid *old_ssid; #ifdef CONFIG_HT_OVERRIDES struct ieee80211_ht_capabilities htcaps; struct ieee80211_ht_capabilities htcaps_mask; #endif /* CONFIG_HT_OVERRIDES */ #ifdef CONFIG_VHT_OVERRIDES struct ieee80211_vht_capabilities vhtcaps; struct ieee80211_vht_capabilities vhtcaps_mask; #endif /* CONFIG_VHT_OVERRIDES */ if (deinit) { if (work->started) { wpa_s->connect_work = NULL; /* cancel possible auth. timeout */ eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); } wpas_connect_work_free(cwork); return; } wpa_s->connect_work = work; if (!wpas_valid_bss_ssid(wpa_s, bss, ssid)) { wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt"); wpas_connect_work_done(wpa_s); return; } os_memset(¶ms, 0, sizeof(params)); wpa_s->reassociate = 0; wpa_s->eap_expected_failure = 0; if (bss && !wpas_driver_bss_selection(wpa_s)) { #ifdef CONFIG_IEEE80211R const u8 *ie, *md = NULL; #endif /* CONFIG_IEEE80211R */ wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR " (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq); bssid_changed = !is_zero_ether_addr(wpa_s->bssid); os_memset(wpa_s->bssid, 0, ETH_ALEN); os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN); if (bssid_changed) wpas_notify_bssid_changed(wpa_s); #ifdef CONFIG_IEEE80211R ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN) md = ie + 2; wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0); if (md) { /* Prepare for the next transition */ wpa_ft_prepare_auth_request(wpa_s->wpa, ie); } #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_WPS } else if ((ssid->ssid == NULL || ssid->ssid_len == 0) && wpa_s->conf->ap_scan == 2 && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) { /* Use ap_scan==1 style network selection to find the network */ wpa_s->scan_req = MANUAL_SCAN_REQ; wpa_s->reassociate = 1; wpa_supplicant_req_scan(wpa_s, 0, 0); return; #endif /* CONFIG_WPS */ } else { wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'", wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); } wpa_supplicant_cancel_sched_scan(wpa_s); wpa_supplicant_cancel_scan(wpa_s); /* Starting new association, so clear the possibly used WPA IE from the * previous association. */ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); #ifdef IEEE8021X_EAPOL if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) { if (ssid->leap) { if (ssid->non_leap == 0) algs = WPA_AUTH_ALG_LEAP; else algs |= WPA_AUTH_ALG_LEAP; } } #endif /* IEEE8021X_EAPOL */ wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs); if (ssid->auth_alg) { algs = ssid->auth_alg; wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: " "0x%x", algs); } if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) || wpa_bss_get_ie(bss, WLAN_EID_RSN)) && wpa_key_mgmt_wpa(ssid->key_mgmt)) { int try_opportunistic; try_opportunistic = (ssid->proactive_key_caching < 0 ? wpa_s->conf->okc : ssid->proactive_key_caching) && (ssid->proto & WPA_PROTO_RSN); if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, try_opportunistic) == 0) eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1); wpa_ie_len = sizeof(wpa_ie); if (wpa_supplicant_set_suites(wpa_s, bss, ssid, wpa_ie, &wpa_ie_len)) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA " "key management and encryption suites"); return; } } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss && wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) { /* * Both WPA and non-WPA IEEE 802.1X enabled in configuration - * use non-WPA since the scan results did not indicate that the * AP is using WPA or WPA2. */ wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); wpa_ie_len = 0; wpa_s->wpa_proto = 0; } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) { wpa_ie_len = sizeof(wpa_ie); if (wpa_supplicant_set_suites(wpa_s, NULL, ssid, wpa_ie, &wpa_ie_len)) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA " "key management and encryption suites (no " "scan results)"); return; } #ifdef CONFIG_WPS } else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { struct wpabuf *wps_ie; wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid)); if (wps_ie && wpabuf_len(wps_ie) <= sizeof(wpa_ie)) { wpa_ie_len = wpabuf_len(wps_ie); os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len); } else wpa_ie_len = 0; wpabuf_free(wps_ie); wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); if (!bss || (bss->caps & IEEE80211_CAP_PRIVACY)) params.wps = WPS_MODE_PRIVACY; else params.wps = WPS_MODE_OPEN; wpa_s->wpa_proto = 0; #endif /* CONFIG_WPS */ } else { wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); wpa_ie_len = 0; wpa_s->wpa_proto = 0; } #ifdef CONFIG_P2P if (wpa_s->global->p2p) { u8 *pos; size_t len; int res; pos = wpa_ie + wpa_ie_len; len = sizeof(wpa_ie) - wpa_ie_len; res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len, ssid->p2p_group); if (res >= 0) wpa_ie_len += res; } wpa_s->cross_connect_disallowed = 0; if (bss) { struct wpabuf *p2p; p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE); if (p2p) { wpa_s->cross_connect_disallowed = p2p_get_cross_connect_disallowed(p2p); wpabuf_free(p2p); wpa_dbg(wpa_s, MSG_DEBUG, "P2P: WLAN AP %s cross " "connection", wpa_s->cross_connect_disallowed ? "disallows" : "allows"); } } os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info)); #endif /* CONFIG_P2P */ #ifdef CONFIG_HS20 if (is_hs20_network(wpa_s, ssid, bss)) { struct wpabuf *hs20; hs20 = wpabuf_alloc(20); if (hs20) { int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid); wpas_hs20_add_indication(hs20, pps_mo_id); os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(hs20), wpabuf_len(hs20)); wpa_ie_len += wpabuf_len(hs20); wpabuf_free(hs20); } } #endif /* CONFIG_HS20 */ /* * Workaround: Add Extended Capabilities element only if the AP * included this element in Beacon/Probe Response frames. Some older * APs seem to have interoperability issues if this element is * included, so while the standard may require us to include the * element in all cases, it is justifiable to skip it to avoid * interoperability issues. */ if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) { u8 ext_capab[10]; int ext_capab_len; ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab); if (ext_capab_len > 0) { u8 *pos = wpa_ie; if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN) pos += 2 + pos[1]; os_memmove(pos + ext_capab_len, pos, wpa_ie_len - (pos - wpa_ie)); wpa_ie_len += ext_capab_len; os_memcpy(pos, ext_capab, ext_capab_len); } } wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL); use_crypt = 1; cipher_pairwise = wpa_s->pairwise_cipher; cipher_group = wpa_s->group_cipher; if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) use_crypt = 0; if (wpa_set_wep_keys(wpa_s, ssid)) { use_crypt = 1; wep_keys_set = 1; } } if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) use_crypt = 0; #ifdef IEEE8021X_EAPOL if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { if ((ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) == 0 && !wep_keys_set) { use_crypt = 0; } else { /* Assume that dynamic WEP-104 keys will be used and * set cipher suites in order for drivers to expect * encryption. */ cipher_pairwise = cipher_group = WPA_CIPHER_WEP104; } } #endif /* IEEE8021X_EAPOL */ if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) { /* Set the key before (and later after) association */ wpa_supplicant_set_wpa_none_key(wpa_s, ssid); } wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING); if (bss) { params.ssid = bss->ssid; params.ssid_len = bss->ssid_len; if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) { wpa_printf(MSG_DEBUG, "Limit connection to BSSID " MACSTR " freq=%u MHz based on scan results " "(bssid_set=%d)", MAC2STR(bss->bssid), bss->freq, ssid->bssid_set); params.bssid = bss->bssid; params.freq = bss->freq; } params.bssid_hint = bss->bssid; params.freq_hint = bss->freq; } else { params.ssid = ssid->ssid; params.ssid_len = ssid->ssid_len; } if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set && wpa_s->conf->ap_scan == 2) { params.bssid = ssid->bssid; params.fixed_bssid = 1; } if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 && params.freq == 0) params.freq = ssid->frequency; /* Initial channel for IBSS */ if (ssid->mode == WPAS_MODE_IBSS) { if (ssid->beacon_int) params.beacon_int = ssid->beacon_int; else params.beacon_int = wpa_s->conf->beacon_int; } params.wpa_ie = wpa_ie; params.wpa_ie_len = wpa_ie_len; params.pairwise_suite = cipher_pairwise; params.group_suite = cipher_group; params.key_mgmt_suite = wpa_s->key_mgmt; params.wpa_proto = wpa_s->wpa_proto; params.auth_alg = algs; params.mode = ssid->mode; params.bg_scan_period = ssid->bg_scan_period; for (i = 0; i < NUM_WEP_KEYS; i++) { if (ssid->wep_key_len[i]) params.wep_key[i] = ssid->wep_key[i]; params.wep_key_len[i] = ssid->wep_key_len[i]; } params.wep_tx_keyidx = ssid->wep_tx_keyidx; if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) && (params.key_mgmt_suite == WPA_KEY_MGMT_PSK || params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) { params.passphrase = ssid->passphrase; if (ssid->psk_set) params.psk = ssid->psk; } params.drop_unencrypted = use_crypt; #ifdef CONFIG_IEEE80211W params.mgmt_frame_protection = ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ? wpa_s->conf->pmf : ssid->ieee80211w; if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) { const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN); struct wpa_ie_data ie; if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 && ie.capabilities & (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) { wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected AP supports " "MFP: require MFP"); params.mgmt_frame_protection = MGMT_FRAME_PROTECTION_REQUIRED; } } #endif /* CONFIG_IEEE80211W */ params.p2p = ssid->p2p_group; if (wpa_s->parent->set_sta_uapsd) params.uapsd = wpa_s->parent->sta_uapsd; else params.uapsd = -1; #ifdef CONFIG_HT_OVERRIDES os_memset(&htcaps, 0, sizeof(htcaps)); os_memset(&htcaps_mask, 0, sizeof(htcaps_mask)); params.htcaps = (u8 *) &htcaps; params.htcaps_mask = (u8 *) &htcaps_mask; wpa_supplicant_apply_ht_overrides(wpa_s, ssid, ¶ms); #endif /* CONFIG_HT_OVERRIDES */ #ifdef CONFIG_VHT_OVERRIDES os_memset(&vhtcaps, 0, sizeof(vhtcaps)); os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask)); params.vhtcaps = &vhtcaps; params.vhtcaps_mask = &vhtcaps_mask; wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, ¶ms); #endif /* CONFIG_VHT_OVERRIDES */ #ifdef CONFIG_P2P /* * If multi-channel concurrency is not supported, check for any * frequency conflict. In case of any frequency conflict, remove the * least prioritized connection. */ if (wpa_s->num_multichan_concurrent < 2) { int freq, num; num = get_shared_radio_freqs(wpa_s, &freq, 1); if (num > 0 && freq > 0 && freq != params.freq) { wpa_printf(MSG_DEBUG, "Assoc conflicting freq found (%d != %d)", freq, params.freq); if (wpas_p2p_handle_frequency_conflicts(wpa_s, params.freq, ssid) < 0) return; } } #endif /* CONFIG_P2P */ ret = wpa_drv_associate(wpa_s, ¶ms); if (ret < 0) { wpa_msg(wpa_s, MSG_INFO, "Association request to the driver " "failed"); if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SANE_ERROR_CODES) { /* * The driver is known to mean what is saying, so we * can stop right here; the association will not * succeed. */ wpas_connection_failed(wpa_s, wpa_s->pending_bssid); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); return; } /* try to continue anyway; new association will be tried again * after timeout */ assoc_failed = 1; } if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) { /* Set the key after the association just in case association * cleared the previously configured key. */ wpa_supplicant_set_wpa_none_key(wpa_s, ssid); /* No need to timeout authentication since there is no key * management. */ wpa_supplicant_cancel_auth_timeout(wpa_s); wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); #ifdef CONFIG_IBSS_RSN } else if (ssid->mode == WPAS_MODE_IBSS && wpa_s->key_mgmt != WPA_KEY_MGMT_NONE && wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) { /* * RSN IBSS authentication is per-STA and we can disable the * per-BSSID authentication. */ wpa_supplicant_cancel_auth_timeout(wpa_s); #endif /* CONFIG_IBSS_RSN */ } else { /* Timeout for IEEE 802.11 authentication and association */ int timeout = 60; if (assoc_failed) { /* give IBSS a bit more time */ timeout = ssid->mode == WPAS_MODE_IBSS ? 10 : 5; } else if (wpa_s->conf->ap_scan == 1) { /* give IBSS a bit more time */ timeout = ssid->mode == WPAS_MODE_IBSS ? 20 : 10; } wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0); } if (wep_keys_set && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) { /* Set static WEP keys again */ wpa_set_wep_keys(wpa_s, ssid); } if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) { /* * Do not allow EAP session resumption between different * network configurations. */ eapol_sm_invalidate_cached_session(wpa_s->eapol); } old_ssid = wpa_s->current_ssid; wpa_s->current_ssid = ssid; wpa_s->current_bss = bss; wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); wpa_supplicant_initiate_eapol(wpa_s); if (old_ssid != wpa_s->current_ssid) wpas_notify_network_changed(wpa_s); } static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s, const u8 *addr) { struct wpa_ssid *old_ssid; wpa_clear_keys(wpa_s, addr); old_ssid = wpa_s->current_ssid; wpa_supplicant_mark_disassoc(wpa_s); wpa_sm_set_config(wpa_s->wpa, NULL); eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); if (old_ssid != wpa_s->current_ssid) wpas_notify_network_changed(wpa_s); eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); } /** * wpa_supplicant_deauthenticate - Deauthenticate the current connection * @wpa_s: Pointer to wpa_supplicant data * @reason_code: IEEE 802.11 reason code for the deauthenticate frame * * This function is used to request %wpa_supplicant to deauthenticate from the * current AP. */ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, int reason_code) { u8 *addr = NULL; union wpa_event_data event; int zero_addr = 0; wpa_dbg(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR " pending_bssid=" MACSTR " reason=%d state=%s", MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid), reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state)); if (!is_zero_ether_addr(wpa_s->bssid)) addr = wpa_s->bssid; else if (!is_zero_ether_addr(wpa_s->pending_bssid) && (wpa_s->wpa_state == WPA_AUTHENTICATING || wpa_s->wpa_state == WPA_ASSOCIATING)) addr = wpa_s->pending_bssid; else if (wpa_s->wpa_state == WPA_ASSOCIATING) { /* * When using driver-based BSS selection, we may not know the * BSSID with which we are currently trying to associate. We * need to notify the driver of this disconnection even in such * a case, so use the all zeros address here. */ addr = wpa_s->bssid; zero_addr = 1; } #ifdef CONFIG_TDLS wpa_tdls_teardown_peers(wpa_s->wpa); #endif /* CONFIG_TDLS */ if (addr) { wpa_drv_deauthenticate(wpa_s, addr, reason_code); os_memset(&event, 0, sizeof(event)); event.deauth_info.reason_code = (u16) reason_code; event.deauth_info.locally_generated = 1; wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event); if (zero_addr) addr = NULL; } wpa_supplicant_clear_connection(wpa_s, addr); } static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { if (!ssid || !ssid->disabled || ssid->disabled == 2) return; ssid->disabled = 0; wpas_clear_temp_disabled(wpa_s, ssid, 1); wpas_notify_network_enabled_changed(wpa_s, ssid); /* * Try to reassociate since there is no current configuration and a new * network was made available. */ if (!wpa_s->current_ssid && !wpa_s->disconnected) wpa_s->reassociate = 1; } /** * wpa_supplicant_enable_network - Mark a configured network as enabled * @wpa_s: wpa_supplicant structure for a network interface * @ssid: wpa_ssid structure for a configured network or %NULL * * Enables the specified network or all networks if no network specified. */ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { if (ssid == NULL) { for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) wpa_supplicant_enable_one_network(wpa_s, ssid); } else wpa_supplicant_enable_one_network(wpa_s, ssid); if (wpa_s->reassociate && !wpa_s->disconnected) { if (wpa_s->sched_scanning) { wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to add " "new network to scan filters"); wpa_supplicant_cancel_sched_scan(wpa_s); } if (wpa_supplicant_fast_associate(wpa_s) != 1) wpa_supplicant_req_scan(wpa_s, 0, 0); } } /** * wpa_supplicant_disable_network - Mark a configured network as disabled * @wpa_s: wpa_supplicant structure for a network interface * @ssid: wpa_ssid structure for a configured network or %NULL * * Disables the specified network or all networks if no network specified. */ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct wpa_ssid *other_ssid; int was_disabled; if (ssid == NULL) { if (wpa_s->sched_scanning) wpa_supplicant_cancel_sched_scan(wpa_s); for (other_ssid = wpa_s->conf->ssid; other_ssid; other_ssid = other_ssid->next) { was_disabled = other_ssid->disabled; if (was_disabled == 2) continue; /* do not change persistent P2P group * data */ other_ssid->disabled = 1; if (was_disabled != other_ssid->disabled) wpas_notify_network_enabled_changed( wpa_s, other_ssid); } if (wpa_s->current_ssid) wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); } else if (ssid->disabled != 2) { if (ssid == wpa_s->current_ssid) wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); was_disabled = ssid->disabled; ssid->disabled = 1; if (was_disabled != ssid->disabled) { wpas_notify_network_enabled_changed(wpa_s, ssid); if (wpa_s->sched_scanning) { wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan " "to remove network from filters"); wpa_supplicant_cancel_sched_scan(wpa_s); wpa_supplicant_req_scan(wpa_s, 0, 0); } } } } /** * wpa_supplicant_select_network - Attempt association with a network * @wpa_s: wpa_supplicant structure for a network interface * @ssid: wpa_ssid structure for a configured network or %NULL for any network */ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct wpa_ssid *other_ssid; int disconnected = 0; if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) { wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); disconnected = 1; } if (ssid) wpas_clear_temp_disabled(wpa_s, ssid, 1); /* * Mark all other networks disabled or mark all networks enabled if no * network specified. */ for (other_ssid = wpa_s->conf->ssid; other_ssid; other_ssid = other_ssid->next) { int was_disabled = other_ssid->disabled; if (was_disabled == 2) continue; /* do not change persistent P2P group data */ other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0; if (was_disabled && !other_ssid->disabled) wpas_clear_temp_disabled(wpa_s, other_ssid, 0); if (was_disabled != other_ssid->disabled) wpas_notify_network_enabled_changed(wpa_s, other_ssid); } if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid) { /* We are already associated with the selected network */ wpa_printf(MSG_DEBUG, "Already associated with the " "selected network - do nothing"); return; } if (ssid) { wpa_s->current_ssid = ssid; eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); } wpa_s->connect_without_scan = NULL; wpa_s->disconnected = 0; wpa_s->reassociate = 1; if (wpa_supplicant_fast_associate(wpa_s) != 1) wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0); if (ssid) wpas_notify_network_selected(wpa_s, ssid); } /** * wpas_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path * @wpa_s: wpa_supplicant structure for a network interface * @pkcs11_engine_path: PKCS #11 engine path or NULL * @pkcs11_module_path: PKCS #11 module path or NULL * Returns: 0 on success; -1 on failure * * Sets the PKCS #11 engine and module path. Both have to be NULL or a valid * path. If resetting the EAPOL state machine with the new PKCS #11 engine and * module path fails the paths will be reset to the default value (NULL). */ int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s, const char *pkcs11_engine_path, const char *pkcs11_module_path) { char *pkcs11_engine_path_copy = NULL; char *pkcs11_module_path_copy = NULL; if (pkcs11_engine_path != NULL) { pkcs11_engine_path_copy = os_strdup(pkcs11_engine_path); if (pkcs11_engine_path_copy == NULL) return -1; } if (pkcs11_module_path != NULL) { pkcs11_module_path_copy = os_strdup(pkcs11_module_path); if (pkcs11_module_path_copy == NULL) { os_free(pkcs11_engine_path_copy); return -1; } } os_free(wpa_s->conf->pkcs11_engine_path); os_free(wpa_s->conf->pkcs11_module_path); wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path_copy; wpa_s->conf->pkcs11_module_path = pkcs11_module_path_copy; wpa_sm_set_eapol(wpa_s->wpa, NULL); eapol_sm_deinit(wpa_s->eapol); wpa_s->eapol = NULL; if (wpa_supplicant_init_eapol(wpa_s)) { /* Error -> Reset paths to the default value (NULL) once. */ if (pkcs11_engine_path != NULL && pkcs11_module_path != NULL) wpas_set_pkcs11_engine_and_module_path(wpa_s, NULL, NULL); return -1; } wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol); return 0; } /** * wpa_supplicant_set_ap_scan - Set AP scan mode for interface * @wpa_s: wpa_supplicant structure for a network interface * @ap_scan: AP scan mode * Returns: 0 if succeed or -1 if ap_scan has an invalid value * */ int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan) { int old_ap_scan; if (ap_scan < 0 || ap_scan > 2) return -1; #ifdef ANDROID if (ap_scan == 2 && ap_scan != wpa_s->conf->ap_scan && wpa_s->wpa_state >= WPA_ASSOCIATING && wpa_s->wpa_state < WPA_COMPLETED) { wpa_printf(MSG_ERROR, "ap_scan = %d (%d) rejected while " "associating", wpa_s->conf->ap_scan, ap_scan); return 0; } #endif /* ANDROID */ old_ap_scan = wpa_s->conf->ap_scan; wpa_s->conf->ap_scan = ap_scan; if (old_ap_scan != wpa_s->conf->ap_scan) wpas_notify_ap_scan_changed(wpa_s); return 0; } /** * wpa_supplicant_set_bss_expiration_age - Set BSS entry expiration age * @wpa_s: wpa_supplicant structure for a network interface * @expire_age: Expiration age in seconds * Returns: 0 if succeed or -1 if expire_age has an invalid value * */ int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s, unsigned int bss_expire_age) { if (bss_expire_age < 10) { wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration age %u", bss_expire_age); return -1; } wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration age: %d sec", bss_expire_age); wpa_s->conf->bss_expiration_age = bss_expire_age; return 0; } /** * wpa_supplicant_set_bss_expiration_count - Set BSS entry expiration scan count * @wpa_s: wpa_supplicant structure for a network interface * @expire_count: number of scans after which an unseen BSS is reclaimed * Returns: 0 if succeed or -1 if expire_count has an invalid value * */ int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s, unsigned int bss_expire_count) { if (bss_expire_count < 1) { wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration count %u", bss_expire_count); return -1; } wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration scan count: %u", bss_expire_count); wpa_s->conf->bss_expiration_scan_count = bss_expire_count; return 0; } /** * wpa_supplicant_set_scan_interval - Set scan interval * @wpa_s: wpa_supplicant structure for a network interface * @scan_interval: scan interval in seconds * Returns: 0 if succeed or -1 if scan_interval has an invalid value * */ int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s, int scan_interval) { if (scan_interval < 0) { wpa_msg(wpa_s, MSG_ERROR, "Invalid scan interval %d", scan_interval); return -1; } wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec", scan_interval); wpa_supplicant_update_scan_int(wpa_s, scan_interval); return 0; } /** * wpa_supplicant_set_debug_params - Set global debug params * @global: wpa_global structure * @debug_level: debug level * @debug_timestamp: determines if show timestamp in debug data * @debug_show_keys: determines if show keys in debug data * Returns: 0 if succeed or -1 if debug_level has wrong value */ int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level, int debug_timestamp, int debug_show_keys) { int old_level, old_timestamp, old_show_keys; /* check for allowed debuglevels */ if (debug_level != MSG_EXCESSIVE && debug_level != MSG_MSGDUMP && debug_level != MSG_DEBUG && debug_level != MSG_INFO && debug_level != MSG_WARNING && debug_level != MSG_ERROR) return -1; old_level = wpa_debug_level; old_timestamp = wpa_debug_timestamp; old_show_keys = wpa_debug_show_keys; wpa_debug_level = debug_level; wpa_debug_timestamp = debug_timestamp ? 1 : 0; wpa_debug_show_keys = debug_show_keys ? 1 : 0; if (wpa_debug_level != old_level) wpas_notify_debug_level_changed(global); if (wpa_debug_timestamp != old_timestamp) wpas_notify_debug_timestamp_changed(global); if (wpa_debug_show_keys != old_show_keys) wpas_notify_debug_show_keys_changed(global); return 0; } /** * wpa_supplicant_get_ssid - Get a pointer to the current network structure * @wpa_s: Pointer to wpa_supplicant data * Returns: A pointer to the current network structure or %NULL on failure */ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s) { struct wpa_ssid *entry; u8 ssid[MAX_SSID_LEN]; int res; size_t ssid_len; u8 bssid[ETH_ALEN]; int wired; res = wpa_drv_get_ssid(wpa_s, ssid); if (res < 0) { wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from " "driver"); return NULL; } ssid_len = res; if (wpa_drv_get_bssid(wpa_s, bssid) < 0) { wpa_msg(wpa_s, MSG_WARNING, "Could not read BSSID from " "driver"); return NULL; } wired = wpa_s->conf->ap_scan == 0 && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED); entry = wpa_s->conf->ssid; while (entry) { if (!wpas_network_disabled(wpa_s, entry) && ((ssid_len == entry->ssid_len && os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) && (!entry->bssid_set || os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) return entry; #ifdef CONFIG_WPS if (!wpas_network_disabled(wpa_s, entry) && (entry->key_mgmt & WPA_KEY_MGMT_WPS) && (entry->ssid == NULL || entry->ssid_len == 0) && (!entry->bssid_set || os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) return entry; #endif /* CONFIG_WPS */ if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set && entry->ssid_len == 0 && os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0) return entry; entry = entry->next; } return NULL; } static int select_driver(struct wpa_supplicant *wpa_s, int i) { struct wpa_global *global = wpa_s->global; if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) { global->drv_priv[i] = wpa_drivers[i]->global_init(); if (global->drv_priv[i] == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize driver " "'%s'", wpa_drivers[i]->name); return -1; } } wpa_s->driver = wpa_drivers[i]; wpa_s->global_drv_priv = global->drv_priv[i]; return 0; } static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s, const char *name) { int i; size_t len; const char *pos, *driver = name; if (wpa_s == NULL) return -1; if (wpa_drivers[0] == NULL) { wpa_msg(wpa_s, MSG_ERROR, "No driver interfaces build into " "wpa_supplicant"); return -1; } if (name == NULL) { /* default to first driver in the list */ return select_driver(wpa_s, 0); } do { pos = os_strchr(driver, ','); if (pos) len = pos - driver; else len = os_strlen(driver); for (i = 0; wpa_drivers[i]; i++) { if (os_strlen(wpa_drivers[i]->name) == len && os_strncmp(driver, wpa_drivers[i]->name, len) == 0) { /* First driver that succeeds wins */ if (select_driver(wpa_s, i) == 0) return 0; } } driver = pos + 1; } while (pos); wpa_msg(wpa_s, MSG_ERROR, "Unsupported driver '%s'", name); return -1; } /** * wpa_supplicant_rx_eapol - Deliver a received EAPOL frame to wpa_supplicant * @ctx: Context pointer (wpa_s); this is the ctx variable registered * with struct wpa_driver_ops::init() * @src_addr: Source address of the EAPOL frame * @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header) * @len: Length of the EAPOL data * * This function is called for each received EAPOL frame. Most driver * interfaces rely on more generic OS mechanism for receiving frames through * l2_packet, but if such a mechanism is not available, the driver wrapper may * take care of received EAPOL frames and deliver them to the core supplicant * code by calling this function. */ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { struct wpa_supplicant *wpa_s = ctx; wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr)); wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len); #ifdef CONFIG_PEERKEY if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid && wpa_s->current_ssid->peerkey && !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) && wpa_sm_rx_eapol_peerkey(wpa_s->wpa, src_addr, buf, len) == 1) { wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Processed PeerKey EAPOL-Key"); return; } #endif /* CONFIG_PEERKEY */ if (wpa_s->wpa_state < WPA_ASSOCIATED || (wpa_s->last_eapol_matches_bssid && #ifdef CONFIG_AP !wpa_s->ap_iface && #endif /* CONFIG_AP */ os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) != 0)) { /* * There is possible race condition between receiving the * association event and the EAPOL frame since they are coming * through different paths from the driver. In order to avoid * issues in trying to process the EAPOL frame before receiving * association information, lets queue it for processing until * the association event is received. This may also be needed in * driver-based roaming case, so also use src_addr != BSSID as a * trigger if we have previously confirmed that the * Authenticator uses BSSID as the src_addr (which is not the * case with wired IEEE 802.1X). */ wpa_dbg(wpa_s, MSG_DEBUG, "Not associated - Delay processing " "of received EAPOL frame (state=%s bssid=" MACSTR ")", wpa_supplicant_state_txt(wpa_s->wpa_state), MAC2STR(wpa_s->bssid)); wpabuf_free(wpa_s->pending_eapol_rx); wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len); if (wpa_s->pending_eapol_rx) { os_get_reltime(&wpa_s->pending_eapol_rx_time); os_memcpy(wpa_s->pending_eapol_rx_src, src_addr, ETH_ALEN); } return; } wpa_s->last_eapol_matches_bssid = os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) == 0; #ifdef CONFIG_AP if (wpa_s->ap_iface) { wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len); return; } #endif /* CONFIG_AP */ if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) { wpa_dbg(wpa_s, MSG_DEBUG, "Ignored received EAPOL frame since " "no key management is configured"); return; } if (wpa_s->eapol_received == 0 && (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) || !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || wpa_s->wpa_state != WPA_COMPLETED) && (wpa_s->current_ssid == NULL || wpa_s->current_ssid->mode != IEEE80211_MODE_IBSS)) { /* Timeout for completing IEEE 802.1X and WPA authentication */ wpa_supplicant_req_auth_timeout( wpa_s, (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA || wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) ? 70 : 10, 0); } wpa_s->eapol_received++; if (wpa_s->countermeasures) { wpa_msg(wpa_s, MSG_INFO, "WPA: Countermeasures - dropped " "EAPOL packet"); return; } #ifdef CONFIG_IBSS_RSN if (wpa_s->current_ssid && wpa_s->current_ssid->mode == WPAS_MODE_IBSS) { ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len); return; } #endif /* CONFIG_IBSS_RSN */ /* Source address of the incoming EAPOL frame could be compared to the * current BSSID. However, it is possible that a centralized * Authenticator could be using another MAC address than the BSSID of * an AP, so just allow any address to be used for now. The replies are * still sent to the current BSSID (if available), though. */ os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN); if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) && eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0) return; wpa_drv_poll(wpa_s); if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len); else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { /* * Set portValid = TRUE here since we are going to skip 4-way * handshake processing which would normally set portValid. We * need this to allow the EAPOL state machines to be completed * without going through EAPOL-Key handshake. */ eapol_sm_notify_portValid(wpa_s->eapol, TRUE); } } int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s) { if (wpa_s->driver->send_eapol) { const u8 *addr = wpa_drv_get_mac_addr(wpa_s); if (addr) os_memcpy(wpa_s->own_addr, addr, ETH_ALEN); } else if ((!wpa_s->p2p_mgmt || !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) && !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) { l2_packet_deinit(wpa_s->l2); wpa_s->l2 = l2_packet_init(wpa_s->ifname, wpa_drv_get_mac_addr(wpa_s), ETH_P_EAPOL, wpa_supplicant_rx_eapol, wpa_s, 0); if (wpa_s->l2 == NULL) return -1; } else { const u8 *addr = wpa_drv_get_mac_addr(wpa_s); if (addr) os_memcpy(wpa_s->own_addr, addr, ETH_ALEN); } if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) { wpa_msg(wpa_s, MSG_ERROR, "Failed to get own L2 address"); return -1; } return 0; } static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { struct wpa_supplicant *wpa_s = ctx; const struct l2_ethhdr *eth; if (len < sizeof(*eth)) return; eth = (const struct l2_ethhdr *) buf; if (os_memcmp(eth->h_dest, wpa_s->own_addr, ETH_ALEN) != 0 && !(eth->h_dest[0] & 0x01)) { wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR " (bridge - not for this interface - ignore)", MAC2STR(src_addr), MAC2STR(eth->h_dest)); return; } wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR " (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest)); wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth), len - sizeof(*eth)); } /** * wpa_supplicant_driver_init - Initialize driver interface parameters * @wpa_s: Pointer to wpa_supplicant data * Returns: 0 on success, -1 on failure * * This function is called to initialize driver interface parameters. * wpa_drv_init() must have been called before this function to initialize the * driver interface. */ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s) { static int interface_count = 0; if (wpa_supplicant_update_mac_addr(wpa_s) < 0) return -1; wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR, MAC2STR(wpa_s->own_addr)); wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr); if (wpa_s->bridge_ifname[0]) { wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge " "interface '%s'", wpa_s->bridge_ifname); wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname, wpa_s->own_addr, ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1); if (wpa_s->l2_br == NULL) { wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet " "connection for the bridge interface '%s'", wpa_s->bridge_ifname); return -1; } } wpa_clear_keys(wpa_s, NULL); /* Make sure that TKIP countermeasures are not left enabled (could * happen if wpa_supplicant is killed during countermeasures. */ wpa_drv_set_countermeasures(wpa_s, 0); wpa_dbg(wpa_s, MSG_DEBUG, "RSN: flushing PMKID list in the driver"); wpa_drv_flush_pmkid(wpa_s); wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; wpa_s->prev_scan_wildcard = 0; if (wpa_supplicant_enabled_networks(wpa_s)) { if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); interface_count = 0; } if (!wpa_s->p2p_mgmt && wpa_supplicant_delayed_sched_scan(wpa_s, interface_count % 3, 100000)) wpa_supplicant_req_scan(wpa_s, interface_count % 3, 100000); interface_count++; } else wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); return 0; } static int wpa_supplicant_daemon(const char *pid_file) { wpa_printf(MSG_DEBUG, "Daemonize.."); return os_daemonize(pid_file); } static struct wpa_supplicant * wpa_supplicant_alloc(void) { struct wpa_supplicant *wpa_s; wpa_s = os_zalloc(sizeof(*wpa_s)); if (wpa_s == NULL) return NULL; wpa_s->scan_req = INITIAL_SCAN_REQ; wpa_s->scan_interval = 5; wpa_s->new_connection = 1; wpa_s->parent = wpa_s; wpa_s->sched_scanning = 0; return wpa_s; } #ifdef CONFIG_HT_OVERRIDES static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s, struct ieee80211_ht_capabilities *htcaps, struct ieee80211_ht_capabilities *htcaps_mask, const char *ht_mcs) { /* parse ht_mcs into hex array */ int i; const char *tmp = ht_mcs; char *end = NULL; /* If ht_mcs is null, do not set anything */ if (!ht_mcs) return 0; /* This is what we are setting in the kernel */ os_memset(&htcaps->supported_mcs_set, 0, IEEE80211_HT_MCS_MASK_LEN); wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs); for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) { errno = 0; long v = strtol(tmp, &end, 16); if (errno == 0) { wpa_msg(wpa_s, MSG_DEBUG, "htcap value[%i]: %ld end: %p tmp: %p", i, v, end, tmp); if (end == tmp) break; htcaps->supported_mcs_set[i] = v; tmp = end; } else { wpa_msg(wpa_s, MSG_ERROR, "Failed to parse ht-mcs: %s, error: %s\n", ht_mcs, strerror(errno)); return -1; } } /* * If we were able to parse any values, then set mask for the MCS set. */ if (i) { os_memset(&htcaps_mask->supported_mcs_set, 0xff, IEEE80211_HT_MCS_MASK_LEN - 1); /* skip the 3 reserved bits */ htcaps_mask->supported_mcs_set[IEEE80211_HT_MCS_MASK_LEN - 1] = 0x1f; } return 0; } static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s, struct ieee80211_ht_capabilities *htcaps, struct ieee80211_ht_capabilities *htcaps_mask, int disabled) { u16 msk; wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled); if (disabled == -1) return 0; msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE); htcaps_mask->ht_capabilities_info |= msk; if (disabled) htcaps->ht_capabilities_info &= msk; else htcaps->ht_capabilities_info |= msk; return 0; } static int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s, struct ieee80211_ht_capabilities *htcaps, struct ieee80211_ht_capabilities *htcaps_mask, int factor) { wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor); if (factor == -1) return 0; if (factor < 0 || factor > 3) { wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. " "Must be 0-3 or -1", factor); return -EINVAL; } htcaps_mask->a_mpdu_params |= 0x3; /* 2 bits for factor */ htcaps->a_mpdu_params &= ~0x3; htcaps->a_mpdu_params |= factor & 0x3; return 0; } static int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s, struct ieee80211_ht_capabilities *htcaps, struct ieee80211_ht_capabilities *htcaps_mask, int density) { wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density); if (density == -1) return 0; if (density < 0 || density > 7) { wpa_msg(wpa_s, MSG_ERROR, "ampdu_density: %d out of range. Must be 0-7 or -1.", density); return -EINVAL; } htcaps_mask->a_mpdu_params |= 0x1C; htcaps->a_mpdu_params &= ~(0x1C); htcaps->a_mpdu_params |= (density << 2) & 0x1C; return 0; } static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s, struct ieee80211_ht_capabilities *htcaps, struct ieee80211_ht_capabilities *htcaps_mask, int disabled) { /* Masking these out disables HT40 */ u16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET | HT_CAP_INFO_SHORT_GI40MHZ); wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled); if (disabled) htcaps->ht_capabilities_info &= ~msk; else htcaps->ht_capabilities_info |= msk; htcaps_mask->ht_capabilities_info |= msk; return 0; } static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s, struct ieee80211_ht_capabilities *htcaps, struct ieee80211_ht_capabilities *htcaps_mask, int disabled) { /* Masking these out disables SGI */ u16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ | HT_CAP_INFO_SHORT_GI40MHZ); wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled); if (disabled) htcaps->ht_capabilities_info &= ~msk; else htcaps->ht_capabilities_info |= msk; htcaps_mask->ht_capabilities_info |= msk; return 0; } static int wpa_set_disable_ldpc(struct wpa_supplicant *wpa_s, struct ieee80211_ht_capabilities *htcaps, struct ieee80211_ht_capabilities *htcaps_mask, int disabled) { /* Masking these out disables LDPC */ u16 msk = host_to_le16(HT_CAP_INFO_LDPC_CODING_CAP); wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled); if (disabled) htcaps->ht_capabilities_info &= ~msk; else htcaps->ht_capabilities_info |= msk; htcaps_mask->ht_capabilities_info |= msk; return 0; } void wpa_supplicant_apply_ht_overrides( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_driver_associate_params *params) { struct ieee80211_ht_capabilities *htcaps; struct ieee80211_ht_capabilities *htcaps_mask; if (!ssid) return; params->disable_ht = ssid->disable_ht; if (!params->htcaps || !params->htcaps_mask) return; htcaps = (struct ieee80211_ht_capabilities *) params->htcaps; htcaps_mask = (struct ieee80211_ht_capabilities *) params->htcaps_mask; wpa_set_htcap_mcs(wpa_s, htcaps, htcaps_mask, ssid->ht_mcs); wpa_disable_max_amsdu(wpa_s, htcaps, htcaps_mask, ssid->disable_max_amsdu); wpa_set_ampdu_factor(wpa_s, htcaps, htcaps_mask, ssid->ampdu_factor); wpa_set_ampdu_density(wpa_s, htcaps, htcaps_mask, ssid->ampdu_density); wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40); wpa_set_disable_sgi(wpa_s, htcaps, htcaps_mask, ssid->disable_sgi); wpa_set_disable_ldpc(wpa_s, htcaps, htcaps_mask, ssid->disable_ldpc); if (ssid->ht40_intolerant) { u16 bit = host_to_le16(HT_CAP_INFO_40MHZ_INTOLERANT); htcaps->ht_capabilities_info |= bit; htcaps_mask->ht_capabilities_info |= bit; } } #endif /* CONFIG_HT_OVERRIDES */ #ifdef CONFIG_VHT_OVERRIDES void wpa_supplicant_apply_vht_overrides( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_driver_associate_params *params) { struct ieee80211_vht_capabilities *vhtcaps; struct ieee80211_vht_capabilities *vhtcaps_mask; #ifdef CONFIG_HT_OVERRIDES int max_ampdu; const u32 max_ampdu_mask = VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX; #endif /* CONFIG_HT_OVERRIDES */ if (!ssid) return; params->disable_vht = ssid->disable_vht; vhtcaps = (void *) params->vhtcaps; vhtcaps_mask = (void *) params->vhtcaps_mask; if (!vhtcaps || !vhtcaps_mask) return; vhtcaps->vht_capabilities_info = ssid->vht_capa; vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask; #ifdef CONFIG_HT_OVERRIDES /* if max ampdu is <= 3, we have to make the HT cap the same */ if (ssid->vht_capa_mask & max_ampdu_mask) { max_ampdu = (ssid->vht_capa & max_ampdu_mask) >> find_first_bit(max_ampdu_mask); max_ampdu = max_ampdu < 3 ? max_ampdu : 3; wpa_set_ampdu_factor(wpa_s, (void *) params->htcaps, (void *) params->htcaps_mask, max_ampdu); } #endif /* CONFIG_HT_OVERRIDES */ #define OVERRIDE_MCS(i) \ if (ssid->vht_tx_mcs_nss_ ##i >= 0) { \ vhtcaps_mask->vht_supported_mcs_set.tx_map |= \ 3 << 2 * (i - 1); \ vhtcaps->vht_supported_mcs_set.tx_map |= \ ssid->vht_tx_mcs_nss_ ##i << 2 * (i - 1); \ } \ if (ssid->vht_rx_mcs_nss_ ##i >= 0) { \ vhtcaps_mask->vht_supported_mcs_set.rx_map |= \ 3 << 2 * (i - 1); \ vhtcaps->vht_supported_mcs_set.rx_map |= \ ssid->vht_rx_mcs_nss_ ##i << 2 * (i - 1); \ } OVERRIDE_MCS(1); OVERRIDE_MCS(2); OVERRIDE_MCS(3); OVERRIDE_MCS(4); OVERRIDE_MCS(5); OVERRIDE_MCS(6); OVERRIDE_MCS(7); OVERRIDE_MCS(8); } #endif /* CONFIG_VHT_OVERRIDES */ static int pcsc_reader_init(struct wpa_supplicant *wpa_s) { #ifdef PCSC_FUNCS size_t len; if (!wpa_s->conf->pcsc_reader) return 0; wpa_s->scard = scard_init(wpa_s->conf->pcsc_reader); if (!wpa_s->scard) return 1; if (wpa_s->conf->pcsc_pin && scard_set_pin(wpa_s->scard, wpa_s->conf->pcsc_pin) < 0) { scard_deinit(wpa_s->scard); wpa_s->scard = NULL; wpa_msg(wpa_s, MSG_ERROR, "PC/SC PIN validation failed"); return -1; } len = sizeof(wpa_s->imsi) - 1; if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) { scard_deinit(wpa_s->scard); wpa_s->scard = NULL; wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI"); return -1; } wpa_s->imsi[len] = '\0'; wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard); wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)", wpa_s->imsi, wpa_s->mnc_len); wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard); eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard); #endif /* PCSC_FUNCS */ return 0; } int wpas_init_ext_pw(struct wpa_supplicant *wpa_s) { char *val, *pos; ext_password_deinit(wpa_s->ext_pw); wpa_s->ext_pw = NULL; eapol_sm_set_ext_pw_ctx(wpa_s->eapol, NULL); if (!wpa_s->conf->ext_password_backend) return 0; val = os_strdup(wpa_s->conf->ext_password_backend); if (val == NULL) return -1; pos = os_strchr(val, ':'); if (pos) *pos++ = '\0'; wpa_printf(MSG_DEBUG, "EXT PW: Initialize backend '%s'", val); wpa_s->ext_pw = ext_password_init(val, pos); os_free(val); if (wpa_s->ext_pw == NULL) { wpa_printf(MSG_DEBUG, "EXT PW: Failed to initialize backend"); return -1; } eapol_sm_set_ext_pw_ctx(wpa_s->eapol, wpa_s->ext_pw); return 0; } static int wpas_check_wowlan_trigger(const char *start, const char *trigger, int capa_trigger, u8 *param_trigger) { if (os_strcmp(start, trigger) != 0) return 0; if (!capa_trigger) return 0; *param_trigger = 1; return 1; } int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s, struct wpa_driver_capa *capa) { struct wowlan_triggers triggers; char *start, *end, *buf; int last, ret; if (!wpa_s->conf->wowlan_triggers) return 0; buf = os_strdup(wpa_s->conf->wowlan_triggers); if (buf == NULL) return -1; os_memset(&triggers, 0, sizeof(triggers)); #define CHECK_TRIGGER(trigger) \ wpas_check_wowlan_trigger(start, #trigger, \ capa->wowlan_triggers.trigger, \ &triggers.trigger) start = buf; while (*start != '\0') { while (isblank(*start)) start++; if (*start == '\0') break; end = start; while (!isblank(*end) && *end != '\0') end++; last = *end == '\0'; *end = '\0'; if (!CHECK_TRIGGER(any) && !CHECK_TRIGGER(disconnect) && !CHECK_TRIGGER(magic_pkt) && !CHECK_TRIGGER(gtk_rekey_failure) && !CHECK_TRIGGER(eap_identity_req) && !CHECK_TRIGGER(four_way_handshake) && !CHECK_TRIGGER(rfkill_release)) { wpa_printf(MSG_DEBUG, "Unknown/unsupported wowlan trigger '%s'", start); ret = -1; goto out; } if (last) break; start = end + 1; } #undef CHECK_TRIGGER ret = wpa_drv_wowlan(wpa_s, &triggers); out: os_free(buf); return ret; } static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s, const char *rn) { struct wpa_supplicant *iface = wpa_s->global->ifaces; struct wpa_radio *radio; while (rn && iface) { radio = iface->radio; if (radio && os_strcmp(rn, radio->name) == 0) { wpa_printf(MSG_DEBUG, "Add interface %s to existing radio %s", wpa_s->ifname, rn); dl_list_add(&radio->ifaces, &wpa_s->radio_list); return radio; } iface = iface->next; } wpa_printf(MSG_DEBUG, "Add interface %s to a new radio %s", wpa_s->ifname, rn ? rn : "N/A"); radio = os_zalloc(sizeof(*radio)); if (radio == NULL) return NULL; if (rn) os_strlcpy(radio->name, rn, sizeof(radio->name)); dl_list_init(&radio->ifaces); dl_list_init(&radio->work); dl_list_add(&radio->ifaces, &wpa_s->radio_list); return radio; } static void radio_work_free(struct wpa_radio_work *work) { if (work->wpa_s->scan_work == work) { /* This should not really happen. */ wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as scan_work", work->type, work, work->started); work->wpa_s->scan_work = NULL; } #ifdef CONFIG_P2P if (work->wpa_s->p2p_scan_work == work) { /* This should not really happen. */ wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as p2p_scan_work", work->type, work, work->started); work->wpa_s->p2p_scan_work = NULL; } #endif /* CONFIG_P2P */ dl_list_del(&work->list); os_free(work); } static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx) { struct wpa_radio *radio = eloop_ctx; struct wpa_radio_work *work; struct os_reltime now, diff; struct wpa_supplicant *wpa_s; work = dl_list_first(&radio->work, struct wpa_radio_work, list); if (work == NULL) return; if (work->started) return; /* already started and still in progress */ wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant, radio_list); if (wpa_s && wpa_s->external_scan_running) { wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes"); return; } os_get_reltime(&now); os_reltime_sub(&now, &work->time, &diff); wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting radio work '%s'@%p after %ld.%06ld second wait", work->type, work, diff.sec, diff.usec); work->started = 1; work->time = now; work->cb(work, 0); } /* * This function removes both started and pending radio works running on * the provided interface's radio. * Prior to the removal of the radio work, its callback (cb) is called with * deinit set to be 1. Each work's callback is responsible for clearing its * internal data and restoring to a correct state. * @wpa_s: wpa_supplicant data * @type: type of works to be removed * @remove_all: 1 to remove all the works on this radio, 0 to remove only * this interface's works. */ void radio_remove_works(struct wpa_supplicant *wpa_s, const char *type, int remove_all) { struct wpa_radio_work *work, *tmp; struct wpa_radio *radio = wpa_s->radio; dl_list_for_each_safe(work, tmp, &radio->work, struct wpa_radio_work, list) { if (type && os_strcmp(type, work->type) != 0) continue; /* skip other ifaces' works */ if (!remove_all && work->wpa_s != wpa_s) continue; wpa_dbg(wpa_s, MSG_DEBUG, "Remove radio work '%s'@%p%s", work->type, work, work->started ? " (started)" : ""); work->cb(work, 1); radio_work_free(work); } /* in case we removed the started work */ radio_work_check_next(wpa_s); } static void radio_remove_interface(struct wpa_supplicant *wpa_s) { struct wpa_radio *radio = wpa_s->radio; if (!radio) return; wpa_printf(MSG_DEBUG, "Remove interface %s from radio %s", wpa_s->ifname, radio->name); dl_list_del(&wpa_s->radio_list); radio_remove_works(wpa_s, NULL, 0); wpa_s->radio = NULL; if (!dl_list_empty(&radio->ifaces)) return; /* Interfaces remain for this radio */ wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name); eloop_cancel_timeout(radio_start_next_work, radio, NULL); os_free(radio); } void radio_work_check_next(struct wpa_supplicant *wpa_s) { struct wpa_radio *radio = wpa_s->radio; if (dl_list_empty(&radio->work)) return; eloop_cancel_timeout(radio_start_next_work, radio, NULL); eloop_register_timeout(0, 0, radio_start_next_work, radio, NULL); } /** * radio_add_work - Add a radio work item * @wpa_s: Pointer to wpa_supplicant data * @freq: Frequency of the offchannel operation in MHz or 0 * @type: Unique identifier for each type of work * @next: Force as the next work to be executed * @cb: Callback function for indicating when radio is available * @ctx: Context pointer for the work (work->ctx in cb()) * Returns: 0 on success, -1 on failure * * This function is used to request time for an operation that requires * exclusive radio control. Once the radio is available, the registered callback * function will be called. radio_work_done() must be called once the exclusive * radio operation has been completed, so that the radio is freed for other * operations. The special case of deinit=1 is used to free the context data * during interface removal. That does not allow the callback function to start * the radio operation, i.e., it must free any resources allocated for the radio * work and return. * * The @freq parameter can be used to indicate a single channel on which the * offchannel operation will occur. This may allow multiple radio work * operations to be performed in parallel if they apply for the same channel. * Setting this to 0 indicates that the work item may use multiple channels or * requires exclusive control of the radio. */ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, const char *type, int next, void (*cb)(struct wpa_radio_work *work, int deinit), void *ctx) { struct wpa_radio_work *work; int was_empty; work = os_zalloc(sizeof(*work)); if (work == NULL) return -1; wpa_dbg(wpa_s, MSG_DEBUG, "Add radio work '%s'@%p", type, work); os_get_reltime(&work->time); work->freq = freq; work->type = type; work->wpa_s = wpa_s; work->cb = cb; work->ctx = ctx; was_empty = dl_list_empty(&wpa_s->radio->work); if (next) dl_list_add(&wpa_s->radio->work, &work->list); else dl_list_add_tail(&wpa_s->radio->work, &work->list); if (was_empty) { wpa_dbg(wpa_s, MSG_DEBUG, "First radio work item in the queue - schedule start immediately"); radio_work_check_next(wpa_s); } return 0; } /** * radio_work_done - Indicate that a radio work item has been completed * @work: Completed work * * This function is called once the callback function registered with * radio_add_work() has completed its work. */ void radio_work_done(struct wpa_radio_work *work) { struct wpa_supplicant *wpa_s = work->wpa_s; struct os_reltime now, diff; unsigned int started = work->started; os_get_reltime(&now); os_reltime_sub(&now, &work->time, &diff); wpa_dbg(wpa_s, MSG_DEBUG, "Radio work '%s'@%p %s in %ld.%06ld seconds", work->type, work, started ? "done" : "canceled", diff.sec, diff.usec); radio_work_free(work); if (started) radio_work_check_next(wpa_s); } int radio_work_pending(struct wpa_supplicant *wpa_s, const char *type) { struct wpa_radio_work *work; struct wpa_radio *radio = wpa_s->radio; dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) { if (work->wpa_s == wpa_s && os_strcmp(work->type, type) == 0) return 1; } return 0; } static int wpas_init_driver(struct wpa_supplicant *wpa_s, struct wpa_interface *iface) { const char *ifname, *driver, *rn; driver = iface->driver; next_driver: if (wpa_supplicant_set_driver(wpa_s, driver) < 0) return -1; wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname); if (wpa_s->drv_priv == NULL) { const char *pos; pos = driver ? os_strchr(driver, ',') : NULL; if (pos) { wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize " "driver interface - try next driver wrapper"); driver = pos + 1; goto next_driver; } wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver " "interface"); return -1; } if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) { wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected " "driver_param '%s'", wpa_s->conf->driver_param); return -1; } ifname = wpa_drv_get_ifname(wpa_s); if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced " "interface name with '%s'", ifname); os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname)); } rn = wpa_driver_get_radio_name(wpa_s); if (rn && rn[0] == '\0') rn = NULL; wpa_s->radio = radio_add_interface(wpa_s, rn); if (wpa_s->radio == NULL) return -1; return 0; } static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, struct wpa_interface *iface) { struct wpa_driver_capa capa; wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver " "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname, iface->confname ? iface->confname : "N/A", iface->driver ? iface->driver : "default", iface->ctrl_interface ? iface->ctrl_interface : "N/A", iface->bridge_ifname ? iface->bridge_ifname : "N/A"); if (iface->confname) { #ifdef CONFIG_BACKEND_FILE wpa_s->confname = os_rel2abs_path(iface->confname); if (wpa_s->confname == NULL) { wpa_printf(MSG_ERROR, "Failed to get absolute path " "for configuration file '%s'.", iface->confname); return -1; } wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'", iface->confname, wpa_s->confname); #else /* CONFIG_BACKEND_FILE */ wpa_s->confname = os_strdup(iface->confname); #endif /* CONFIG_BACKEND_FILE */ wpa_s->conf = wpa_config_read(wpa_s->confname, NULL); if (wpa_s->conf == NULL) { wpa_printf(MSG_ERROR, "Failed to read or parse " "configuration '%s'.", wpa_s->confname); return -1; } wpa_s->confanother = os_rel2abs_path(iface->confanother); wpa_config_read(wpa_s->confanother, wpa_s->conf); #ifdef CONFIG_P2P wpa_s->conf_p2p_dev = os_rel2abs_path(iface->conf_p2p_dev); wpa_config_read(wpa_s->conf_p2p_dev, wpa_s->conf); #endif /* CONFIG_P2P */ /* * Override ctrl_interface and driver_param if set on command * line. */ if (iface->ctrl_interface) { os_free(wpa_s->conf->ctrl_interface); wpa_s->conf->ctrl_interface = os_strdup(iface->ctrl_interface); } if (iface->driver_param) { os_free(wpa_s->conf->driver_param); wpa_s->conf->driver_param = os_strdup(iface->driver_param); } if (iface->p2p_mgmt && !iface->ctrl_interface) { os_free(wpa_s->conf->ctrl_interface); wpa_s->conf->ctrl_interface = NULL; } } else wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface, iface->driver_param); if (wpa_s->conf == NULL) { wpa_printf(MSG_ERROR, "\nNo configuration found."); return -1; } if (iface->ifname == NULL) { wpa_printf(MSG_ERROR, "\nInterface name is required."); return -1; } if (os_strlen(iface->ifname) >= sizeof(wpa_s->ifname)) { wpa_printf(MSG_ERROR, "\nToo long interface name '%s'.", iface->ifname); return -1; } os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname)); if (iface->bridge_ifname) { if (os_strlen(iface->bridge_ifname) >= sizeof(wpa_s->bridge_ifname)) { wpa_printf(MSG_ERROR, "\nToo long bridge interface " "name '%s'.", iface->bridge_ifname); return -1; } os_strlcpy(wpa_s->bridge_ifname, iface->bridge_ifname, sizeof(wpa_s->bridge_ifname)); } /* RSNA Supplicant Key Management - INITIALIZE */ eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE); eapol_sm_notify_portValid(wpa_s->eapol, FALSE); /* Initialize driver interface and register driver event handler before * L2 receive handler so that association events are processed before * EAPOL-Key packets if both become available for the same select() * call. */ if (wpas_init_driver(wpa_s, iface) < 0) return -1; if (wpa_supplicant_init_wpa(wpa_s) < 0) return -1; wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname, wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname : NULL); wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth); if (wpa_s->conf->dot11RSNAConfigPMKLifetime && wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, wpa_s->conf->dot11RSNAConfigPMKLifetime)) { wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for " "dot11RSNAConfigPMKLifetime"); return -1; } if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold && wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) { wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for " "dot11RSNAConfigPMKReauthThreshold"); return -1; } if (wpa_s->conf->dot11RSNAConfigSATimeout && wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, wpa_s->conf->dot11RSNAConfigSATimeout)) { wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for " "dot11RSNAConfigSATimeout"); return -1; } wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags); if (wpa_drv_get_capa(wpa_s, &capa) == 0) { wpa_s->drv_capa_known = 1; wpa_s->drv_flags = capa.flags; wpa_s->drv_enc = capa.enc; wpa_s->probe_resp_offloads = capa.probe_resp_offloads; wpa_s->max_scan_ssids = capa.max_scan_ssids; wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids; wpa_s->sched_scan_supported = capa.sched_scan_supported; wpa_s->max_match_sets = capa.max_match_sets; wpa_s->max_remain_on_chan = capa.max_remain_on_chan; wpa_s->max_stations = capa.max_stations; wpa_s->extended_capa = capa.extended_capa; wpa_s->extended_capa_mask = capa.extended_capa_mask; wpa_s->extended_capa_len = capa.extended_capa_len; wpa_s->num_multichan_concurrent = capa.num_multichan_concurrent; } if (wpa_s->max_remain_on_chan == 0) wpa_s->max_remain_on_chan = 1000; /* * Only take p2p_mgmt parameters when P2P Device is supported. * Doing it here as it determines whether l2_packet_init() will be done * during wpa_supplicant_driver_init(). */ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) wpa_s->p2p_mgmt = iface->p2p_mgmt; else iface->p2p_mgmt = 1; if (wpa_s->num_multichan_concurrent == 0) wpa_s->num_multichan_concurrent = 1; if (wpa_supplicant_driver_init(wpa_s) < 0) return -1; #ifdef CONFIG_TDLS if ((!iface->p2p_mgmt || !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) && wpa_tdls_init(wpa_s->wpa)) return -1; #endif /* CONFIG_TDLS */ if (wpa_s->conf->country[0] && wpa_s->conf->country[1] && wpa_drv_set_country(wpa_s, wpa_s->conf->country)) { wpa_dbg(wpa_s, MSG_DEBUG, "Failed to set country"); return -1; } if (wpas_wps_init(wpa_s)) return -1; if (wpa_supplicant_init_eapol(wpa_s) < 0) return -1; wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol); wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s); if (wpa_s->ctrl_iface == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize control interface '%s'.\n" "You may have another wpa_supplicant process " "already running or the file was\n" "left by an unclean termination of wpa_supplicant " "in which case you will need\n" "to manually remove this file before starting " "wpa_supplicant again.\n", wpa_s->conf->ctrl_interface); return -1; } wpa_s->gas = gas_query_init(wpa_s); if (wpa_s->gas == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize GAS query"); return -1; } #ifdef CONFIG_P2P if (iface->p2p_mgmt && wpas_p2p_init(wpa_s->global, wpa_s) < 0) { wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P"); return -1; } #endif /* CONFIG_P2P */ if (wpa_bss_init(wpa_s) < 0) return -1; /* * Set Wake-on-WLAN triggers, if configured. * Note: We don't restore/remove the triggers on shutdown (it doesn't * have effect anyway when the interface is down). */ if (wpas_set_wowlan_triggers(wpa_s, &capa) < 0) return -1; #ifdef CONFIG_EAP_PROXY { size_t len; wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, wpa_s->imsi, &len); if (wpa_s->mnc_len > 0) { wpa_s->imsi[len] = '\0'; wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)", wpa_s->imsi, wpa_s->mnc_len); } else { wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available"); } } #endif /* CONFIG_EAP_PROXY */ if (pcsc_reader_init(wpa_s) < 0) return -1; if (wpas_init_ext_pw(wpa_s) < 0) return -1; return 0; } static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s, int notify, int terminate) { wpa_s->disconnected = 1; if (wpa_s->drv_priv) { wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); wpa_drv_set_countermeasures(wpa_s, 0); wpa_clear_keys(wpa_s, NULL); } wpa_supplicant_cleanup(wpa_s); #ifdef CONFIG_P2P if (wpa_s == wpa_s->parent) wpas_p2p_group_remove(wpa_s, "*"); if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing " "the management interface is being removed"); wpas_p2p_deinit_global(wpa_s->global); } #endif /* CONFIG_P2P */ wpas_ctrl_radio_work_flush(wpa_s); radio_remove_interface(wpa_s); if (wpa_s->drv_priv) wpa_drv_deinit(wpa_s); if (notify) wpas_notify_iface_removed(wpa_s); if (terminate) wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING); if (wpa_s->ctrl_iface) { wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); wpa_s->ctrl_iface = NULL; } if (wpa_s->conf != NULL) { wpa_config_free(wpa_s->conf); wpa_s->conf = NULL; } os_free(wpa_s); } /** * wpa_supplicant_add_iface - Add a new network interface * @global: Pointer to global data from wpa_supplicant_init() * @iface: Interface configuration options * Returns: Pointer to the created interface or %NULL on failure * * This function is used to add new network interfaces for %wpa_supplicant. * This can be called before wpa_supplicant_run() to add interfaces before the * main event loop has been started. In addition, new interfaces can be added * dynamically while %wpa_supplicant is already running. This could happen, * e.g., when a hotplug network adapter is inserted. */ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global, struct wpa_interface *iface) { struct wpa_supplicant *wpa_s; struct wpa_interface t_iface; struct wpa_ssid *ssid; if (global == NULL || iface == NULL) return NULL; wpa_s = wpa_supplicant_alloc(); if (wpa_s == NULL) return NULL; wpa_s->global = global; t_iface = *iface; if (global->params.override_driver) { wpa_printf(MSG_DEBUG, "Override interface parameter: driver " "('%s' -> '%s')", iface->driver, global->params.override_driver); t_iface.driver = global->params.override_driver; } if (global->params.override_ctrl_interface) { wpa_printf(MSG_DEBUG, "Override interface parameter: " "ctrl_interface ('%s' -> '%s')", iface->ctrl_interface, global->params.override_ctrl_interface); t_iface.ctrl_interface = global->params.override_ctrl_interface; } if (wpa_supplicant_init_iface(wpa_s, &t_iface)) { wpa_printf(MSG_DEBUG, "Failed to add interface %s", iface->ifname); wpa_supplicant_deinit_iface(wpa_s, 0, 0); return NULL; } /* Notify the control interfaces about new iface */ if (wpas_notify_iface_added(wpa_s)) { wpa_supplicant_deinit_iface(wpa_s, 1, 0); return NULL; } for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) wpas_notify_network_added(wpa_s, ssid); wpa_s->next = global->ifaces; global->ifaces = wpa_s; wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); return wpa_s; } /** * wpa_supplicant_remove_iface - Remove a network interface * @global: Pointer to global data from wpa_supplicant_init() * @wpa_s: Pointer to the network interface to be removed * Returns: 0 if interface was removed, -1 if interface was not found * * This function can be used to dynamically remove network interfaces from * %wpa_supplicant, e.g., when a hotplug network adapter is ejected. In * addition, this function is used to remove all remaining interfaces when * %wpa_supplicant is terminated. */ int wpa_supplicant_remove_iface(struct wpa_global *global, struct wpa_supplicant *wpa_s, int terminate) { struct wpa_supplicant *prev; /* Remove interface from the global list of interfaces */ prev = global->ifaces; if (prev == wpa_s) { global->ifaces = wpa_s->next; } else { while (prev && prev->next != wpa_s) prev = prev->next; if (prev == NULL) return -1; prev->next = wpa_s->next; } wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname); if (global->p2p_group_formation == wpa_s) global->p2p_group_formation = NULL; if (global->p2p_invite_group == wpa_s) global->p2p_invite_group = NULL; wpa_supplicant_deinit_iface(wpa_s, 1, terminate); return 0; } /** * wpa_supplicant_get_eap_mode - Get the current EAP mode * @wpa_s: Pointer to the network interface * Returns: Pointer to the eap mode or the string "UNKNOWN" if not found */ const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s) { const char *eapol_method; if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) == 0 && wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA) { return "NO-EAP"; } eapol_method = eapol_sm_get_method_name(wpa_s->eapol); if (eapol_method == NULL) return "UNKNOWN-EAP"; return eapol_method; } /** * wpa_supplicant_get_iface - Get a new network interface * @global: Pointer to global data from wpa_supplicant_init() * @ifname: Interface name * Returns: Pointer to the interface or %NULL if not found */ struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global, const char *ifname) { struct wpa_supplicant *wpa_s; for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { if (os_strcmp(wpa_s->ifname, ifname) == 0) return wpa_s; } return NULL; } #ifndef CONFIG_NO_WPA_MSG static const char * wpa_supplicant_msg_ifname_cb(void *ctx) { struct wpa_supplicant *wpa_s = ctx; if (wpa_s == NULL) return NULL; return wpa_s->ifname; } #endif /* CONFIG_NO_WPA_MSG */ /** * wpa_supplicant_init - Initialize %wpa_supplicant * @params: Parameters for %wpa_supplicant * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure * * This function is used to initialize %wpa_supplicant. After successful * initialization, the returned data pointer can be used to add and remove * network interfaces, and eventually, to deinitialize %wpa_supplicant. */ struct wpa_global * wpa_supplicant_init(struct wpa_params *params) { struct wpa_global *global; int ret, i; if (params == NULL) return NULL; #ifdef CONFIG_DRIVER_NDIS { void driver_ndis_init_ops(void); driver_ndis_init_ops(); } #endif /* CONFIG_DRIVER_NDIS */ #ifndef CONFIG_NO_WPA_MSG wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb); #endif /* CONFIG_NO_WPA_MSG */ wpa_debug_open_file(params->wpa_debug_file_path); if (params->wpa_debug_syslog) wpa_debug_open_syslog(); if (params->wpa_debug_tracing) { ret = wpa_debug_open_linux_tracing(); if (ret) { wpa_printf(MSG_ERROR, "Failed to enable trace logging"); return NULL; } } ret = eap_register_methods(); if (ret) { wpa_printf(MSG_ERROR, "Failed to register EAP methods"); if (ret == -2) wpa_printf(MSG_ERROR, "Two or more EAP methods used " "the same EAP type."); return NULL; } global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; dl_list_init(&global->p2p_srv_bonjour); dl_list_init(&global->p2p_srv_upnp); global->params.daemonize = params->daemonize; global->params.wait_for_monitor = params->wait_for_monitor; global->params.dbus_ctrl_interface = params->dbus_ctrl_interface; if (params->pid_file) global->params.pid_file = os_strdup(params->pid_file); if (params->ctrl_interface) global->params.ctrl_interface = os_strdup(params->ctrl_interface); if (params->ctrl_interface_group) global->params.ctrl_interface_group = os_strdup(params->ctrl_interface_group); if (params->override_driver) global->params.override_driver = os_strdup(params->override_driver); if (params->override_ctrl_interface) global->params.override_ctrl_interface = os_strdup(params->override_ctrl_interface); wpa_debug_level = global->params.wpa_debug_level = params->wpa_debug_level; wpa_debug_show_keys = global->params.wpa_debug_show_keys = params->wpa_debug_show_keys; wpa_debug_timestamp = global->params.wpa_debug_timestamp = params->wpa_debug_timestamp; wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR); if (eloop_init()) { wpa_printf(MSG_ERROR, "Failed to initialize event loop"); wpa_supplicant_deinit(global); return NULL; } random_init(params->entropy_file); global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global); if (global->ctrl_iface == NULL) { wpa_supplicant_deinit(global); return NULL; } if (wpas_notify_supplicant_initialized(global)) { wpa_supplicant_deinit(global); return NULL; } for (i = 0; wpa_drivers[i]; i++) global->drv_count++; if (global->drv_count == 0) { wpa_printf(MSG_ERROR, "No drivers enabled"); wpa_supplicant_deinit(global); return NULL; } global->drv_priv = os_zalloc(global->drv_count * sizeof(void *)); if (global->drv_priv == NULL) { wpa_supplicant_deinit(global); return NULL; } #ifdef CONFIG_WIFI_DISPLAY if (wifi_display_init(global) < 0) { wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display"); wpa_supplicant_deinit(global); return NULL; } #endif /* CONFIG_WIFI_DISPLAY */ return global; } /** * wpa_supplicant_run - Run the %wpa_supplicant main event loop * @global: Pointer to global data from wpa_supplicant_init() * Returns: 0 after successful event loop run, -1 on failure * * This function starts the main event loop and continues running as long as * there are any remaining events. In most cases, this function is running as * long as the %wpa_supplicant process in still in use. */ int wpa_supplicant_run(struct wpa_global *global) { struct wpa_supplicant *wpa_s; if (global->params.daemonize && wpa_supplicant_daemon(global->params.pid_file)) return -1; if (global->params.wait_for_monitor) { for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) if (wpa_s->ctrl_iface) wpa_supplicant_ctrl_iface_wait( wpa_s->ctrl_iface); } eloop_register_signal_terminate(wpa_supplicant_terminate, global); eloop_register_signal_reconfig(wpa_supplicant_reconfig, global); eloop_run(); return 0; } /** * wpa_supplicant_deinit - Deinitialize %wpa_supplicant * @global: Pointer to global data from wpa_supplicant_init() * * This function is called to deinitialize %wpa_supplicant and to free all * allocated resources. Remaining network interfaces will also be removed. */ void wpa_supplicant_deinit(struct wpa_global *global) { int i; if (global == NULL) return; #ifdef CONFIG_WIFI_DISPLAY wifi_display_deinit(global); #endif /* CONFIG_WIFI_DISPLAY */ while (global->ifaces) wpa_supplicant_remove_iface(global, global->ifaces, 1); if (global->ctrl_iface) wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface); wpas_notify_supplicant_deinitialized(global); eap_peer_unregister_methods(); #ifdef CONFIG_AP eap_server_unregister_methods(); #endif /* CONFIG_AP */ for (i = 0; wpa_drivers[i] && global->drv_priv; i++) { if (!global->drv_priv[i]) continue; wpa_drivers[i]->global_deinit(global->drv_priv[i]); } os_free(global->drv_priv); random_deinit(); eloop_destroy(); if (global->params.pid_file) { os_daemonize_terminate(global->params.pid_file); os_free(global->params.pid_file); } os_free(global->params.ctrl_interface); os_free(global->params.ctrl_interface_group); os_free(global->params.override_driver); os_free(global->params.override_ctrl_interface); os_free(global->p2p_disallow_freq.range); os_free(global->p2p_go_avoid_freq.range); os_free(global->add_psk); os_free(global); wpa_debug_close_syslog(); wpa_debug_close_file(); wpa_debug_close_linux_tracing(); } void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s) { if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) && wpa_s->conf->country[0] && wpa_s->conf->country[1]) { char country[3]; country[0] = wpa_s->conf->country[0]; country[1] = wpa_s->conf->country[1]; country[2] = '\0'; if (wpa_drv_set_country(wpa_s, country) < 0) { wpa_printf(MSG_ERROR, "Failed to set country code " "'%s'", country); } } if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND) wpas_init_ext_pw(wpa_s); #ifdef CONFIG_WPS wpas_wps_update_config(wpa_s); #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P wpas_p2p_update_config(wpa_s); #endif /* CONFIG_P2P */ wpa_s->conf->changed_parameters = 0; } static void add_freq(int *freqs, int *num_freqs, int freq) { int i; for (i = 0; i < *num_freqs; i++) { if (freqs[i] == freq) return; } freqs[*num_freqs] = freq; (*num_freqs)++; } static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss, *cbss; const int max_freqs = 10; int *freqs; int num_freqs = 0; freqs = os_zalloc(sizeof(int) * (max_freqs + 1)); if (freqs == NULL) return NULL; cbss = wpa_s->current_bss; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (bss == cbss) continue; if (bss->ssid_len == cbss->ssid_len && os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 && wpa_blacklist_get(wpa_s, bss->bssid) == NULL) { add_freq(freqs, &num_freqs, bss->freq); if (num_freqs == max_freqs) break; } } if (num_freqs == 0) { os_free(freqs); freqs = NULL; } return freqs; } void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid) { int timeout; int count; int *freqs = NULL; wpas_connect_work_done(wpa_s); /* * Remove possible authentication timeout since the connection failed. */ eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); if (wpa_s->disconnected) { /* * There is no point in blacklisting the AP if this event is * generated based on local request to disconnect. */ wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure " "indication since interface has been put into " "disconnected state"); return; } /* * Add the failed BSSID into the blacklist and speed up next scan * attempt if there could be other APs that could accept association. * The current blacklist count indicates how many times we have tried * connecting to this AP and multiple attempts mean that other APs are * either not available or has already been tried, so that we can start * increasing the delay here to avoid constant scanning. */ count = wpa_blacklist_add(wpa_s, bssid); if (count == 1 && wpa_s->current_bss) { /* * This BSS was not in the blacklist before. If there is * another BSS available for the same ESS, we should try that * next. Otherwise, we may as well try this one once more * before allowing other, likely worse, ESSes to be considered. */ freqs = get_bss_freqs_in_ess(wpa_s); if (freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Another BSS in this ESS " "has been seen; try it next"); wpa_blacklist_add(wpa_s, bssid); /* * On the next scan, go through only the known channels * used in this ESS based on previous scans to speed up * common load balancing use case. */ os_free(wpa_s->next_scan_freqs); wpa_s->next_scan_freqs = freqs; } } /* * Add previous failure count in case the temporary blacklist was * cleared due to no other BSSes being available. */ count += wpa_s->extra_blacklist_count; if (count > 3 && wpa_s->current_ssid) { wpa_printf(MSG_DEBUG, "Continuous association failures - " "consider temporary network disabling"); wpas_auth_failed(wpa_s, "CONN_FAILED"); } switch (count) { case 1: timeout = 100; break; case 2: timeout = 500; break; case 3: timeout = 1000; break; case 4: timeout = 5000; break; default: timeout = 10000; break; } wpa_dbg(wpa_s, MSG_DEBUG, "Blacklist count %d --> request scan in %d " "ms", count, timeout); /* * TODO: if more than one possible AP is available in scan results, * could try the other ones before requesting a new scan. */ wpa_supplicant_req_scan(wpa_s, timeout / 1000, 1000 * (timeout % 1000)); } int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s) { return wpa_s->conf->ap_scan == 2 || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION); } #if defined(CONFIG_CTRL_IFACE) || defined(CONFIG_CTRL_IFACE_DBUS_NEW) int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, const char *field, const char *value) { #ifdef IEEE8021X_EAPOL struct eap_peer_config *eap = &ssid->eap; wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field); wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value", (const u8 *) value, os_strlen(value)); switch (wpa_supplicant_ctrl_req_from_string(field)) { case WPA_CTRL_REQ_EAP_IDENTITY: os_free(eap->identity); eap->identity = (u8 *) os_strdup(value); eap->identity_len = os_strlen(value); eap->pending_req_identity = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; break; case WPA_CTRL_REQ_EAP_PASSWORD: os_free(eap->password); eap->password = (u8 *) os_strdup(value); eap->password_len = os_strlen(value); eap->pending_req_password = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; break; case WPA_CTRL_REQ_EAP_NEW_PASSWORD: os_free(eap->new_password); eap->new_password = (u8 *) os_strdup(value); eap->new_password_len = os_strlen(value); eap->pending_req_new_password = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; break; case WPA_CTRL_REQ_EAP_PIN: os_free(eap->pin); eap->pin = os_strdup(value); eap->pending_req_pin = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; break; case WPA_CTRL_REQ_EAP_OTP: os_free(eap->otp); eap->otp = (u8 *) os_strdup(value); eap->otp_len = os_strlen(value); os_free(eap->pending_req_otp); eap->pending_req_otp = NULL; eap->pending_req_otp_len = 0; break; case WPA_CTRL_REQ_EAP_PASSPHRASE: os_free(eap->private_key_passwd); eap->private_key_passwd = (u8 *) os_strdup(value); eap->pending_req_passphrase = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; break; case WPA_CTRL_REQ_SIM: os_free(eap->external_sim_resp); eap->external_sim_resp = os_strdup(value); break; default: wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field); return -1; } return 0; #else /* IEEE8021X_EAPOL */ wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included"); return -1; #endif /* IEEE8021X_EAPOL */ } #endif /* CONFIG_CTRL_IFACE || CONFIG_CTRL_IFACE_DBUS_NEW */ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { int i; unsigned int drv_enc; if (ssid == NULL) return 1; if (ssid->disabled) return 1; if (wpa_s && wpa_s->drv_capa_known) drv_enc = wpa_s->drv_enc; else drv_enc = (unsigned int) -1; for (i = 0; i < NUM_WEP_KEYS; i++) { size_t len = ssid->wep_key_len[i]; if (len == 0) continue; if (len == 5 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP40)) continue; if (len == 13 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP104)) continue; if (len == 16 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP128)) continue; return 1; /* invalid WEP key */ } if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set && (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk) return 1; return 0; } int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s) { if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P) return 1; if (wpa_s->global->conc_pref == WPA_CONC_PREF_STA) return 0; return -1; } void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason) { struct wpa_ssid *ssid = wpa_s->current_ssid; int dur; struct os_reltime now; if (ssid == NULL) { wpa_printf(MSG_DEBUG, "Authentication failure but no known " "SSID block"); return; } if (ssid->key_mgmt == WPA_KEY_MGMT_WPS) return; ssid->auth_failures++; #ifdef CONFIG_P2P if (ssid->p2p_group && (wpa_s->p2p_in_provisioning || wpa_s->show_group_started)) { /* * Skip the wait time since there is a short timeout on the * connection to a P2P group. */ return; } #endif /* CONFIG_P2P */ if (ssid->auth_failures > 50) dur = 300; else if (ssid->auth_failures > 10) dur = 120; else if (ssid->auth_failures > 5) dur = 90; else if (ssid->auth_failures > 3) dur = 60; else if (ssid->auth_failures > 2) dur = 30; else if (ssid->auth_failures > 1) dur = 20; else dur = 10; if (ssid->auth_failures > 1 && wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) dur += os_random() % (ssid->auth_failures * 10); os_get_reltime(&now); if (now.sec + dur <= ssid->disabled_until.sec) return; ssid->disabled_until.sec = now.sec + dur; wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED "id=%d ssid=\"%s\" auth_failures=%u duration=%d reason=%s", ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len), ssid->auth_failures, dur, reason); } void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int clear_failures) { if (ssid == NULL) return; if (ssid->disabled_until.sec) { wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REENABLED "id=%d ssid=\"%s\"", ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); } ssid->disabled_until.sec = 0; ssid->disabled_until.usec = 0; if (clear_failures) ssid->auth_failures = 0; } int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid) { size_t i; if (wpa_s->disallow_aps_bssid == NULL) return 0; for (i = 0; i < wpa_s->disallow_aps_bssid_count; i++) { if (os_memcmp(wpa_s->disallow_aps_bssid + i * ETH_ALEN, bssid, ETH_ALEN) == 0) return 1; } return 0; } int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid, size_t ssid_len) { size_t i; if (wpa_s->disallow_aps_ssid == NULL || ssid == NULL) return 0; for (i = 0; i < wpa_s->disallow_aps_ssid_count; i++) { struct wpa_ssid_value *s = &wpa_s->disallow_aps_ssid[i]; if (ssid_len == s->ssid_len && os_memcmp(ssid, s->ssid, ssid_len) == 0) return 1; } return 0; } /** * wpas_request_connection - Request a new connection * @wpa_s: Pointer to the network interface * * This function is used to request a new connection to be found. It will mark * the interface to allow reassociation and request a new scan to find a * suitable network to connect to. */ void wpas_request_connection(struct wpa_supplicant *wpa_s) { wpa_s->normal_scans = 0; wpa_supplicant_reinit_autoscan(wpa_s); wpa_s->extra_blacklist_count = 0; wpa_s->disconnected = 0; wpa_s->reassociate = 1; if (wpa_supplicant_fast_associate(wpa_s) != 1) wpa_supplicant_req_scan(wpa_s, 0, 0); } void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title, int *freq_array, unsigned int len) { unsigned int i; wpa_dbg(wpa_s, MSG_DEBUG, "Shared frequencies (len=%u): %s", len, title); for (i = 0; i < len; i++) wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d", i, freq_array[i]); } /* * Find the operating frequencies of any of the virtual interfaces that * are using the same radio as the current interface. */ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s, int *freq_array, unsigned int len) { struct wpa_supplicant *ifs; u8 bssid[ETH_ALEN]; int freq; unsigned int idx = 0, i; wpa_dbg(wpa_s, MSG_DEBUG, "Determining shared radio frequencies (max len %u)", len); os_memset(freq_array, 0, sizeof(int) * len); /* First add the frequency of the local interface */ if (wpa_s->current_ssid != NULL && wpa_s->assoc_freq != 0) { if (wpa_s->current_ssid->mode == WPAS_MODE_AP || wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO) freq_array[idx++] = wpa_s->current_ssid->frequency; else if (wpa_drv_get_bssid(wpa_s, bssid) == 0) freq_array[idx++] = wpa_s->assoc_freq; } /* If get_radio_name is not supported, use only the local freq */ if (!wpa_driver_get_radio_name(wpa_s)) { freq = wpa_drv_shared_freq(wpa_s); if (freq > 0 && idx < len && (idx == 0 || freq_array[0] != freq)) freq_array[idx++] = freq; dump_freq_array(wpa_s, "No get_radio_name", freq_array, idx); return idx; } dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant, radio_list) { if (wpa_s == ifs) continue; if (ifs->current_ssid == NULL || ifs->assoc_freq == 0) continue; if (ifs->current_ssid->mode == WPAS_MODE_AP || ifs->current_ssid->mode == WPAS_MODE_P2P_GO) freq = ifs->current_ssid->frequency; else if (wpa_drv_get_bssid(ifs, bssid) == 0) freq = ifs->assoc_freq; else continue; /* Hold only distinct freqs */ for (i = 0; i < idx; i++) if (freq_array[i] == freq) break; if (i == idx) freq_array[idx++] = freq; } dump_freq_array(wpa_s, "completed iteration", freq_array, idx); return idx; } wpa_supplicant-2.2/wpa_supplicant/wpa_supplicant.conf0000664000175000017500000015207412343617166021161 0ustar jmjm##### Example wpa_supplicant configuration file ############################### # # This file describes configuration file format and lists all available option. # Please also take a look at simpler configuration examples in 'examples' # subdirectory. # # Empty lines and lines starting with # are ignored # NOTE! This file may contain password information and should probably be made # readable only by root user on multiuser systems. # Note: All file paths in this configuration file should use full (absolute, # not relative to working directory) path in order to allow working directory # to be changed. This can happen if wpa_supplicant is run in the background. # Whether to allow wpa_supplicant to update (overwrite) configuration # # This option can be used to allow wpa_supplicant to overwrite configuration # file whenever configuration is changed (e.g., new network block is added with # wpa_cli or wpa_gui, or a password is changed). This is required for # wpa_cli/wpa_gui to be able to store the configuration changes permanently. # Please note that overwriting configuration file will remove the comments from # it. #update_config=1 # global configuration (shared by all network blocks) # # Parameters for the control interface. If this is specified, wpa_supplicant # will open a control interface that is available for external programs to # manage wpa_supplicant. The meaning of this string depends on which control # interface mechanism is used. For all cases, the existence of this parameter # in configuration is used to determine whether the control interface is # enabled. # # For UNIX domain sockets (default on Linux and BSD): This is a directory that # will be created for UNIX domain sockets for listening to requests from # external programs (CLI/GUI, etc.) for status information and configuration. # The socket file will be named based on the interface name, so multiple # wpa_supplicant processes can be run at the same time if more than one # interface is used. # /var/run/wpa_supplicant is the recommended directory for sockets and by # default, wpa_cli will use it when trying to connect with wpa_supplicant. # # Access control for the control interface can be configured by setting the # directory to allow only members of a group to use sockets. This way, it is # possible to run wpa_supplicant as root (since it needs to change network # configuration and open raw sockets) and still allow GUI/CLI components to be # run as non-root users. However, since the control interface can be used to # change the network configuration, this access needs to be protected in many # cases. By default, wpa_supplicant is configured to use gid 0 (root). If you # want to allow non-root users to use the control interface, add a new group # and change this value to match with that group. Add users that should have # control interface access to this group. If this variable is commented out or # not included in the configuration file, group will not be changed from the # value it got by default when the directory or socket was created. # # When configuring both the directory and group, use following format: # DIR=/var/run/wpa_supplicant GROUP=wheel # DIR=/var/run/wpa_supplicant GROUP=0 # (group can be either group name or gid) # # For UDP connections (default on Windows): The value will be ignored. This # variable is just used to select that the control interface is to be created. # The value can be set to, e.g., udp (ctrl_interface=udp) # # For Windows Named Pipe: This value can be used to set the security descriptor # for controlling access to the control interface. Security descriptor can be # set using Security Descriptor String Format (see http://msdn.microsoft.com/ # library/default.asp?url=/library/en-us/secauthz/security/ # security_descriptor_string_format.asp). The descriptor string needs to be # prefixed with SDDL=. For example, ctrl_interface=SDDL=D: would set an empty # DACL (which will reject all connections). See README-Windows.txt for more # information about SDDL string format. # ctrl_interface=/var/run/wpa_supplicant # IEEE 802.1X/EAPOL version # wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which defines # EAPOL version 2. However, there are many APs that do not handle the new # version number correctly (they seem to drop the frames completely). In order # to make wpa_supplicant interoperate with these APs, the version number is set # to 1 by default. This configuration value can be used to set it to the new # version (2). # Note: When using MACsec, eapol_version shall be set to 3, which is # defined in IEEE Std 802.1X-2010. eapol_version=1 # AP scanning/selection # By default, wpa_supplicant requests driver to perform AP scanning and then # uses the scan results to select a suitable AP. Another alternative is to # allow the driver to take care of AP scanning and selection and use # wpa_supplicant just to process EAPOL frames based on IEEE 802.11 association # information from the driver. # 1: wpa_supplicant initiates scanning and AP selection; if no APs matching to # the currently enabled networks are found, a new network (IBSS or AP mode # operation) may be initialized (if configured) (default) # 0: driver takes care of scanning, AP selection, and IEEE 802.11 association # parameters (e.g., WPA IE generation); this mode can also be used with # non-WPA drivers when using IEEE 802.1X mode; do not try to associate with # APs (i.e., external program needs to control association). This mode must # also be used when using wired Ethernet drivers. # Note: macsec_qca driver is one type of Ethernet driver which implements # macsec feature. # 2: like 0, but associate with APs using security policy and SSID (but not # BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to # enable operation with hidden SSIDs and optimized roaming; in this mode, # the network blocks in the configuration file are tried one by one until # the driver reports successful association; each network block should have # explicit security policy (i.e., only one option in the lists) for # key_mgmt, pairwise, group, proto variables # When using IBSS or AP mode, ap_scan=2 mode can force the new network to be # created immediately regardless of scan results. ap_scan=1 mode will first try # to scan for existing networks and only if no matches with the enabled # networks are found, a new IBSS or AP mode network is created. ap_scan=1 # EAP fast re-authentication # By default, fast re-authentication is enabled for all EAP methods that # support it. This variable can be used to disable fast re-authentication. # Normally, there is no need to disable this. fast_reauth=1 # OpenSSL Engine support # These options can be used to load OpenSSL engines. # The two engines that are supported currently are shown below: # They are both from the opensc project (http://www.opensc.org/) # By default no engines are loaded. # make the opensc engine available #opensc_engine_path=/usr/lib/opensc/engine_opensc.so # make the pkcs11 engine available #pkcs11_engine_path=/usr/lib/opensc/engine_pkcs11.so # configure the path to the pkcs11 module required by the pkcs11 engine #pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so # Dynamic EAP methods # If EAP methods were built dynamically as shared object files, they need to be # loaded here before being used in the network blocks. By default, EAP methods # are included statically in the build, so these lines are not needed #load_dynamic_eap=/usr/lib/wpa_supplicant/eap_tls.so #load_dynamic_eap=/usr/lib/wpa_supplicant/eap_md5.so # Driver interface parameters # This field can be used to configure arbitrary driver interace parameters. The # format is specific to the selected driver interface. This field is not used # in most cases. #driver_param="field=value" # Country code # The ISO/IEC alpha2 country code for the country in which this device is # currently operating. #country=US # Maximum lifetime for PMKSA in seconds; default 43200 #dot11RSNAConfigPMKLifetime=43200 # Threshold for reauthentication (percentage of PMK lifetime); default 70 #dot11RSNAConfigPMKReauthThreshold=70 # Timeout for security association negotiation in seconds; default 60 #dot11RSNAConfigSATimeout=60 # Wi-Fi Protected Setup (WPS) parameters # Universally Unique IDentifier (UUID; see RFC 4122) of the device # If not configured, UUID will be generated based on the local MAC address. #uuid=12345678-9abc-def0-1234-56789abcdef0 # Device Name # User-friendly description of device; up to 32 octets encoded in UTF-8 #device_name=Wireless Client # Manufacturer # The manufacturer of the device (up to 64 ASCII characters) #manufacturer=Company # Model Name # Model of the device (up to 32 ASCII characters) #model_name=cmodel # Model Number # Additional device description (up to 32 ASCII characters) #model_number=123 # Serial Number # Serial number of the device (up to 32 characters) #serial_number=12345 # Primary Device Type # Used format: -- # categ = Category as an integer value # OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for # default WPS OUI # subcateg = OUI-specific Sub Category as an integer value # Examples: # 1-0050F204-1 (Computer / PC) # 1-0050F204-2 (Computer / Server) # 5-0050F204-1 (Storage / NAS) # 6-0050F204-1 (Network Infrastructure / AP) #device_type=1-0050F204-1 # OS Version # 4-octet operating system version number (hex string) #os_version=01020300 # Config Methods # List of the supported configuration methods # Available methods: usba ethernet label display ext_nfc_token int_nfc_token # nfc_interface push_button keypad virtual_display physical_display # virtual_push_button physical_push_button # For WSC 1.0: #config_methods=label display push_button keypad # For WSC 2.0: #config_methods=label virtual_display virtual_push_button keypad # Credential processing # 0 = process received credentials internally (default) # 1 = do not process received credentials; just pass them over ctrl_iface to # external program(s) # 2 = process received credentials internally and pass them over ctrl_iface # to external program(s) #wps_cred_processing=0 # Vendor attribute in WPS M1, e.g., Windows 7 Vertical Pairing # The vendor attribute contents to be added in M1 (hex string) #wps_vendor_ext_m1=000137100100020001 # NFC password token for WPS # These parameters can be used to configure a fixed NFC password token for the # station. This can be generated, e.g., with nfc_pw_token. When these # parameters are used, the station is assumed to be deployed with a NFC tag # that includes the matching NFC password token (e.g., written based on the # NDEF record from nfc_pw_token). # #wps_nfc_dev_pw_id: Device Password ID (16..65535) #wps_nfc_dh_pubkey: Hexdump of DH Public Key #wps_nfc_dh_privkey: Hexdump of DH Private Key #wps_nfc_dev_pw: Hexdump of Device Password # Maximum number of BSS entries to keep in memory # Default: 200 # This can be used to limit memory use on the BSS entries (cached scan # results). A larger value may be needed in environments that have huge number # of APs when using ap_scan=1 mode. #bss_max_count=200 # Automatic scan # This is an optional set of parameters for automatic scanning # within an interface in following format: #autoscan=: # autoscan is like bgscan but on disconnected or inactive state. # For instance, on exponential module parameters would be : #autoscan=exponential:3:300 # Which means a delay between scans on a base exponential of 3, # up to the limit of 300 seconds (3, 9, 27 ... 300) # For periodic module, parameters would be #autoscan=periodic:30 # So a delay of 30 seconds will be applied between each scan # filter_ssids - SSID-based scan result filtering # 0 = do not filter scan results (default) # 1 = only include configured SSIDs in scan results/BSS table #filter_ssids=0 # Password (and passphrase, etc.) backend for external storage # format: [:] #ext_password_backend=test:pw1=password|pw2=testing # Timeout in seconds to detect STA inactivity (default: 300 seconds) # # This timeout value is used in P2P GO mode to clean up # inactive stations. #p2p_go_max_inactivity=300 # Opportunistic Key Caching (also known as Proactive Key Caching) default # This parameter can be used to set the default behavior for the # proactive_key_caching parameter. By default, OKC is disabled unless enabled # with the global okc=1 parameter or with the per-network # proactive_key_caching=1 parameter. With okc=1, OKC is enabled by default, but # can be disabled with per-network proactive_key_caching=0 parameter. #okc=0 # Protected Management Frames default # This parameter can be used to set the default behavior for the ieee80211w # parameter. By default, PMF is disabled unless enabled with the global pmf=1/2 # parameter or with the per-network ieee80211w=1/2 parameter. With pmf=1/2, PMF # is enabled/required by default, but can be disabled with the per-network # ieee80211w parameter. #pmf=0 # Enabled SAE finite cyclic groups in preference order # By default (if this parameter is not set), the mandatory group 19 (ECC group # defined over a 256-bit prime order field) is preferred, but other groups are # also enabled. If this parameter is set, the groups will be tried in the # indicated order. The group values are listed in the IANA registry: # http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9 #sae_groups=21 20 19 26 25 # Default value for DTIM period (if not overridden in network block) #dtim_period=2 # Default value for Beacon interval (if not overridden in network block) #beacon_int=100 # Additional vendor specific elements for Beacon and Probe Response frames # This parameter can be used to add additional vendor specific element(s) into # the end of the Beacon and Probe Response frames. The format for these # element(s) is a hexdump of the raw information elements (id+len+payload for # one or more elements). This is used in AP and P2P GO modes. #ap_vendor_elements=dd0411223301 # Ignore scan results older than request # # The driver may have a cache of scan results that makes it return # information that is older than our scan trigger. This parameter can # be used to configure such old information to be ignored instead of # allowing it to update the internal BSS table. #ignore_old_scan_res=0 # scan_cur_freq: Whether to scan only the current frequency # 0: Scan all available frequencies. (Default) # 1: Scan current operating frequency if another VIF on the same radio # is already associated. # Interworking (IEEE 802.11u) # Enable Interworking # interworking=1 # Homogenous ESS identifier # If this is set, scans will be used to request response only from BSSes # belonging to the specified Homogeneous ESS. This is used only if interworking # is enabled. # hessid=00:11:22:33:44:55 # Automatic network selection behavior # 0 = do not automatically go through Interworking network selection # (i.e., require explicit interworking_select command for this; default) # 1 = perform Interworking network selection if one or more # credentials have been configured and scan did not find a # matching network block #auto_interworking=0 # credential block # # Each credential used for automatic network selection is configured as a set # of parameters that are compared to the information advertised by the APs when # interworking_select and interworking_connect commands are used. # # credential fields: # # temporary: Whether this credential is temporary and not to be saved # # priority: Priority group # By default, all networks and credentials get the same priority group # (0). This field can be used to give higher priority for credentials # (and similarly in struct wpa_ssid for network blocks) to change the # Interworking automatic networking selection behavior. The matching # network (based on either an enabled network block or a credential) # with the highest priority value will be selected. # # pcsc: Use PC/SC and SIM/USIM card # # realm: Home Realm for Interworking # # username: Username for Interworking network selection # # password: Password for Interworking network selection # # ca_cert: CA certificate for Interworking network selection # # client_cert: File path to client certificate file (PEM/DER) # This field is used with Interworking networking selection for a case # where client certificate/private key is used for authentication # (EAP-TLS). Full path to the file should be used since working # directory may change when wpa_supplicant is run in the background. # # Alternatively, a named configuration blob can be used by setting # this to blob://blob_name. # # private_key: File path to client private key file (PEM/DER/PFX) # When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be # commented out. Both the private key and certificate will be read # from the PKCS#12 file in this case. Full path to the file should be # used since working directory may change when wpa_supplicant is run # in the background. # # Windows certificate store can be used by leaving client_cert out and # configuring private_key in one of the following formats: # # cert://substring_to_match # # hash://certificate_thumbprint_in_hex # # For example: private_key="hash://63093aa9c47f56ae88334c7b65a4" # # Note that when running wpa_supplicant as an application, the user # certificate store (My user account) is used, whereas computer store # (Computer account) is used when running wpasvc as a service. # # Alternatively, a named configuration blob can be used by setting # this to blob://blob_name. # # private_key_passwd: Password for private key file # # imsi: IMSI in | | '-' | format # # milenage: Milenage parameters for SIM/USIM simulator in :: # format # # domain: Home service provider FQDN(s) # This is used to compare against the Domain Name List to figure out # whether the AP is operated by the Home SP. Multiple domain entries can # be used to configure alternative FQDNs that will be considered home # networks. # # roaming_consortium: Roaming Consortium OI # If roaming_consortium_len is non-zero, this field contains the # Roaming Consortium OI that can be used to determine which access # points support authentication with this credential. This is an # alternative to the use of the realm parameter. When using Roaming # Consortium to match the network, the EAP parameters need to be # pre-configured with the credential since the NAI Realm information # may not be available or fetched. # # eap: Pre-configured EAP method # This optional field can be used to specify which EAP method will be # used with this credential. If not set, the EAP method is selected # automatically based on ANQP information (e.g., NAI Realm). # # phase1: Pre-configure Phase 1 (outer authentication) parameters # This optional field is used with like the 'eap' parameter. # # phase2: Pre-configure Phase 2 (inner authentication) parameters # This optional field is used with like the 'eap' parameter. # # excluded_ssid: Excluded SSID # This optional field can be used to excluded specific SSID(s) from # matching with the network. Multiple entries can be used to specify more # than one SSID. # # roaming_partner: Roaming partner information # This optional field can be used to configure preferences between roaming # partners. The field is a string in following format: # ,<0/1 exact match>,,<* or country code> # (non-exact match means any subdomain matches the entry; priority is in # 0..255 range with 0 being the highest priority) # # update_identifier: PPS MO ID # (Hotspot 2.0 PerProviderSubscription/UpdateIdentifier) # # provisioning_sp: FQDN of the SP that provisioned the credential # This optional field can be used to keep track of the SP that provisioned # the credential to find the PPS MO (./Wi-Fi/). # # Minimum backhaul threshold (PPS//Policy/MinBackhauldThreshold/*) # These fields can be used to specify minimum download/upload backhaul # bandwidth that is preferred for the credential. This constraint is # ignored if the AP does not advertise WAN Metrics information or if the # limit would prevent any connection. Values are in kilobits per second. # min_dl_bandwidth_home # min_ul_bandwidth_home # min_dl_bandwidth_roaming # min_ul_bandwidth_roaming # # max_bss_load: Maximum BSS Load Channel Utilization (1..255) # (PPS//Policy/MaximumBSSLoadValue) # This value is used as the maximum channel utilization for network # selection purposes for home networks. If the AP does not advertise # BSS Load or if the limit would prevent any connection, this constraint # will be ignored. # # req_conn_capab: Required connection capability # (PPS//Policy/RequiredProtoPortTuple) # This value is used to configure set of required protocol/port pairs that # a roaming network shall support (include explicitly in Connection # Capability ANQP element). This constraint is ignored if the AP does not # advertise Connection Capability or if this constraint would prevent any # network connection. This policy is not used in home networks. # Format: [:" # # scan_ssid: # 0 = do not scan this SSID with specific Probe Request frames (default) # 1 = scan with SSID-specific Probe Request frames (this can be used to # find APs that do not accept broadcast SSID or use multiple SSIDs; # this will add latency to scanning, so enable this only when needed) # # bssid: BSSID (optional); if set, this network block is used only when # associating with the AP using the configured BSSID # # priority: priority group (integer) # By default, all networks will get same priority group (0). If some of the # networks are more desirable, this field can be used to change the order in # which wpa_supplicant goes through the networks when selecting a BSS. The # priority groups will be iterated in decreasing priority (i.e., the larger the # priority value, the sooner the network is matched against the scan results). # Within each priority group, networks will be selected based on security # policy, signal strength, etc. # Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are not # using this priority to select the order for scanning. Instead, they try the # networks in the order that used in the configuration file. # # mode: IEEE 802.11 operation mode # 0 = infrastructure (Managed) mode, i.e., associate with an AP (default) # 1 = IBSS (ad-hoc, peer-to-peer) # 2 = AP (access point) # Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP) and # WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE (fixed group key # TKIP/CCMP) is available for backwards compatibility, but its use is # deprecated. WPA-None requires following network block options: # proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or CCMP, but not # both), and psk must also be set. # # frequency: Channel frequency in megahertz (MHz) for IBSS, e.g., # 2412 = IEEE 802.11b/g channel 1. This value is used to configure the initial # channel for IBSS (adhoc) networks. It is ignored in the infrastructure mode. # In addition, this value is only used by the station that creates the IBSS. If # an IBSS network with the configured SSID is already present, the frequency of # the network will be used instead of this configured value. # # scan_freq: List of frequencies to scan # Space-separated list of frequencies in MHz to scan when searching for this # BSS. If the subset of channels used by the network is known, this option can # be used to optimize scanning to not occur on channels that the network does # not use. Example: scan_freq=2412 2437 2462 # # freq_list: Array of allowed frequencies # Space-separated list of frequencies in MHz to allow for selecting the BSS. If # set, scan results that do not match any of the specified frequencies are not # considered when selecting a BSS. # # This can also be set on the outside of the network block. In this case, # it limits the frequencies that will be scanned. # # bgscan: Background scanning # wpa_supplicant behavior for background scanning can be specified by # configuring a bgscan module. These modules are responsible for requesting # background scans for the purpose of roaming within an ESS (i.e., within a # single network block with all the APs using the same SSID). The bgscan # parameter uses following format: ":" # Following bgscan modules are available: # simple - Periodic background scans based on signal strength # bgscan="simple::: # " # bgscan="simple:30:-45:300" # learn - Learn channels used by the network and try to avoid bgscans on other # channels (experimental) # bgscan="learn::: # [:]" # bgscan="learn:30:-45:300:/etc/wpa_supplicant/network1.bgscan" # Explicitly disable bgscan by setting # bgscan="" # # This option can also be set outside of all network blocks for the bgscan # parameter to apply for all the networks that have no specific bgscan # parameter. # # proto: list of accepted protocols # WPA = WPA/IEEE 802.11i/D3.0 # RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN) # If not set, this defaults to: WPA RSN # # key_mgmt: list of accepted authenticated key management protocols # WPA-PSK = WPA pre-shared key (this requires 'psk' field) # WPA-EAP = WPA using EAP authentication # IEEE8021X = IEEE 802.1X using EAP authentication and (optionally) dynamically # generated WEP keys # NONE = WPA is not used; plaintext or static WEP could be used # WPA-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms # WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms # If not set, this defaults to: WPA-PSK WPA-EAP # # ieee80211w: whether management frame protection is enabled # 0 = disabled (default unless changed with the global pmf parameter) # 1 = optional # 2 = required # The most common configuration options for this based on the PMF (protected # management frames) certification program are: # PMF enabled: ieee80211w=1 and key_mgmt=WPA-EAP WPA-EAP-SHA256 # PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256 # (and similarly for WPA-PSK and WPA-WPSK-SHA256 if WPA2-Personal is used) # # auth_alg: list of allowed IEEE 802.11 authentication algorithms # OPEN = Open System authentication (required for WPA/WPA2) # SHARED = Shared Key authentication (requires static WEP keys) # LEAP = LEAP/Network EAP (only used with LEAP) # If not set, automatic selection is used (Open System with LEAP enabled if # LEAP is allowed as one of the EAP methods). # # pairwise: list of accepted pairwise (unicast) ciphers for WPA # CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] # TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] # NONE = Use only Group Keys (deprecated, should not be included if APs support # pairwise keys) # If not set, this defaults to: CCMP TKIP # # group: list of accepted group (broadcast/multicast) ciphers for WPA # CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] # TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] # WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key # WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key [IEEE 802.11] # If not set, this defaults to: CCMP TKIP WEP104 WEP40 # # psk: WPA preshared key; 256-bit pre-shared key # The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e., # 32 bytes or as an ASCII passphrase (in which case, the real PSK will be # generated using the passphrase and SSID). ASCII passphrase must be between # 8 and 63 characters (inclusive). ext: format can # be used to indicate that the PSK/passphrase is stored in external storage. # This field is not needed, if WPA-EAP is used. # Note: Separate tool, wpa_passphrase, can be used to generate 256-bit keys # from ASCII passphrase. This process uses lot of CPU and wpa_supplicant # startup and reconfiguration time can be optimized by generating the PSK only # only when the passphrase or SSID has actually changed. # # eapol_flags: IEEE 802.1X/EAPOL options (bit field) # Dynamic WEP key required for non-WPA mode # bit0 (1): require dynamically generated unicast WEP key # bit1 (2): require dynamically generated broadcast WEP key # (3 = require both keys; default) # Note: When using wired authentication (including macsec_qca driver), # eapol_flags must be set to 0 for the authentication to be completed # successfully. # # macsec_policy: IEEE 802.1X/MACsec options # This determines how sessions are secured with MACsec. It is currently # applicable only when using the macsec_qca driver interface. # 0: MACsec not in use (default) # 1: MACsec enabled - Should secure, accept key server's advice to # determine whether to use a secure session or not. # # mixed_cell: This option can be used to configure whether so called mixed # cells, i.e., networks that use both plaintext and encryption in the same # SSID, are allowed when selecting a BSS from scan results. # 0 = disabled (default) # 1 = enabled # # proactive_key_caching: # Enable/disable opportunistic PMKSA caching for WPA2. # 0 = disabled (default unless changed with the global okc parameter) # 1 = enabled # # wep_key0..3: Static WEP key (ASCII in double quotation, e.g. "abcde" or # hex without quotation, e.g., 0102030405) # wep_tx_keyidx: Default WEP key index (TX) (0..3) # # peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e DLS) is # allowed. This is only used with RSN/WPA2. # 0 = disabled (default) # 1 = enabled #peerkey=1 # # wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to # enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies. # # Following fields are only used with internal EAP implementation. # eap: space-separated list of accepted EAP methods # MD5 = EAP-MD5 (unsecure and does not generate keying material -> # cannot be used with WPA; to be used as a Phase 2 method # with EAP-PEAP or EAP-TTLS) # MSCHAPV2 = EAP-MSCHAPv2 (cannot be used separately with WPA; to be used # as a Phase 2 method with EAP-PEAP or EAP-TTLS) # OTP = EAP-OTP (cannot be used separately with WPA; to be used # as a Phase 2 method with EAP-PEAP or EAP-TTLS) # GTC = EAP-GTC (cannot be used separately with WPA; to be used # as a Phase 2 method with EAP-PEAP or EAP-TTLS) # TLS = EAP-TLS (client and server certificate) # PEAP = EAP-PEAP (with tunnelled EAP authentication) # TTLS = EAP-TTLS (with tunnelled EAP or PAP/CHAP/MSCHAP/MSCHAPV2 # authentication) # If not set, all compiled in methods are allowed. # # identity: Identity string for EAP # This field is also used to configure user NAI for # EAP-PSK/PAX/SAKE/GPSK. # anonymous_identity: Anonymous identity string for EAP (to be used as the # unencrypted identity with EAP types that support different tunnelled # identity, e.g., EAP-TTLS). This field can also be used with # EAP-SIM/AKA/AKA' to store the pseudonym identity. # password: Password string for EAP. This field can include either the # plaintext password (using ASCII or hex string) or a NtPasswordHash # (16-byte MD4 hash of password) in hash:<32 hex digits> format. # NtPasswordHash can only be used when the password is for MSCHAPv2 or # MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP). # EAP-PSK (128-bit PSK), EAP-PAX (128-bit PSK), and EAP-SAKE (256-bit # PSK) is also configured using this field. For EAP-GPSK, this is a # variable length PSK. ext: format can # be used to indicate that the password is stored in external storage. # ca_cert: File path to CA certificate file (PEM/DER). This file can have one # or more trusted CA certificates. If ca_cert and ca_path are not # included, server certificate will not be verified. This is insecure and # a trusted CA certificate should always be configured when using # EAP-TLS/TTLS/PEAP. Full path should be used since working directory may # change when wpa_supplicant is run in the background. # # Alternatively, this can be used to only perform matching of the server # certificate (SHA-256 hash of the DER encoded X.509 certificate). In # this case, the possible CA certificates in the server certificate chain # are ignored and only the server certificate is verified. This is # configured with the following format: # hash:://server/sha256/cert_hash_in_hex # For example: "hash://server/sha256/ # 5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a" # # On Windows, trusted CA certificates can be loaded from the system # certificate store by setting this to cert_store://, e.g., # ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT". # Note that when running wpa_supplicant as an application, the user # certificate store (My user account) is used, whereas computer store # (Computer account) is used when running wpasvc as a service. # ca_path: Directory path for CA certificate files (PEM). This path may # contain multiple CA certificates in OpenSSL format. Common use for this # is to point to system trusted CA list which is often installed into # directory like /etc/ssl/certs. If configured, these certificates are # added to the list of trusted CAs. ca_cert may also be included in that # case, but it is not required. # client_cert: File path to client certificate file (PEM/DER) # Full path should be used since working directory may change when # wpa_supplicant is run in the background. # Alternatively, a named configuration blob can be used by setting this # to blob://. # private_key: File path to client private key file (PEM/DER/PFX) # When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be # commented out. Both the private key and certificate will be read from # the PKCS#12 file in this case. Full path should be used since working # directory may change when wpa_supplicant is run in the background. # Windows certificate store can be used by leaving client_cert out and # configuring private_key in one of the following formats: # cert://substring_to_match # hash://certificate_thumbprint_in_hex # for example: private_key="hash://63093aa9c47f56ae88334c7b65a4" # Note that when running wpa_supplicant as an application, the user # certificate store (My user account) is used, whereas computer store # (Computer account) is used when running wpasvc as a service. # Alternatively, a named configuration blob can be used by setting this # to blob://. # private_key_passwd: Password for private key file (if left out, this will be # asked through control interface) # dh_file: File path to DH/DSA parameters file (in PEM format) # This is an optional configuration file for setting parameters for an # ephemeral DH key exchange. In most cases, the default RSA # authentication does not use this configuration. However, it is possible # setup RSA to use ephemeral DH key exchange. In addition, ciphers with # DSA keys always use ephemeral DH keys. This can be used to achieve # forward secrecy. If the file is in DSA parameters format, it will be # automatically converted into DH params. # subject_match: Substring to be matched against the subject of the # authentication server certificate. If this string is set, the server # sertificate is only accepted if it contains this string in the subject. # The subject string is in following format: # /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com # altsubject_match: Semicolon separated string of entries to be matched against # the alternative subject name of the authentication server certificate. # If this string is set, the server sertificate is only accepted if it # contains one of the entries in an alternative subject name extension. # altSubjectName string is in following format: TYPE:VALUE # Example: EMAIL:server@example.com # Example: DNS:server.example.com;DNS:server2.example.com # Following types are supported: EMAIL, DNS, URI # phase1: Phase1 (outer authentication, i.e., TLS tunnel) parameters # (string with field-value pairs, e.g., "peapver=0" or # "peapver=1 peaplabel=1") # 'peapver' can be used to force which PEAP version (0 or 1) is used. # 'peaplabel=1' can be used to force new label, "client PEAP encryption", # to be used during key derivation when PEAPv1 or newer. Most existing # PEAPv1 implementation seem to be using the old label, "client EAP # encryption", and wpa_supplicant is now using that as the default value. # Some servers, e.g., Radiator, may require peaplabel=1 configuration to # interoperate with PEAPv1; see eap_testing.txt for more details. # 'peap_outer_success=0' can be used to terminate PEAP authentication on # tunneled EAP-Success. This is required with some RADIUS servers that # implement draft-josefsson-pppext-eap-tls-eap-05.txt (e.g., # Lucent NavisRadius v4.4.0 with PEAP in "IETF Draft 5" mode) # include_tls_length=1 can be used to force wpa_supplicant to include # TLS Message Length field in all TLS messages even if they are not # fragmented. # sim_min_num_chal=3 can be used to configure EAP-SIM to require three # challenges (by default, it accepts 2 or 3) # result_ind=1 can be used to enable EAP-SIM and EAP-AKA to use # protected result indication. # 'crypto_binding' option can be used to control PEAPv0 cryptobinding # behavior: # * 0 = do not use cryptobinding (default) # * 1 = use cryptobinding if server supports it # * 2 = require cryptobinding # EAP-WSC (WPS) uses following options: pin= or # pbc=1. # phase2: Phase2 (inner authentication with TLS tunnel) parameters # (string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or # "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS) # # TLS-based methods can use the following parameters to control TLS behavior # (these are normally in the phase1 parameter, but can be used also in the # phase2 parameter when EAP-TLS is used within the inner tunnel): # tls_allow_md5=1 - allow MD5-based certificate signatures (depending on the # TLS library, these may be disabled by default to enforce stronger # security) # tls_disable_time_checks=1 - ignore certificate validity time (this requests # the TLS library to accept certificates even if they are not currently # valid, i.e., have expired or have not yet become valid; this should be # used only for testing purposes) # tls_disable_session_ticket=1 - disable TLS Session Ticket extension # tls_disable_session_ticket=0 - allow TLS Session Ticket extension to be used # Note: If not set, this is automatically set to 1 for EAP-TLS/PEAP/TTLS # as a workaround for broken authentication server implementations unless # EAP workarounds are disabled with eap_workarounds=0. # For EAP-FAST, this must be set to 0 (or left unconfigured for the # default value to be used automatically). # tls_disable_tlsv1_1=1 - disable use of TLSv1.1 (a workaround for AAA servers # that have issues interoperating with updated TLS version) # tls_disable_tlsv1_2=1 - disable use of TLSv1.2 (a workaround for AAA servers # that have issues interoperating with updated TLS version) # # Following certificate/private key fields are used in inner Phase2 # authentication when using EAP-TTLS or EAP-PEAP. # ca_cert2: File path to CA certificate file. This file can have one or more # trusted CA certificates. If ca_cert2 and ca_path2 are not included, # server certificate will not be verified. This is insecure and a trusted # CA certificate should always be configured. # ca_path2: Directory path for CA certificate files (PEM) # client_cert2: File path to client certificate file # private_key2: File path to client private key file # private_key2_passwd: Password for private key file # dh_file2: File path to DH/DSA parameters file (in PEM format) # subject_match2: Substring to be matched against the subject of the # authentication server certificate. # altsubject_match2: Substring to be matched against the alternative subject # name of the authentication server certificate. # # fragment_size: Maximum EAP fragment size in bytes (default 1398). # This value limits the fragment size for EAP methods that support # fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set # small enough to make the EAP messages fit in MTU of the network # interface used for EAPOL. The default value is suitable for most # cases. # # ocsp: Whether to use/require OCSP to check server certificate # 0 = do not use OCSP stapling (TLS certificate status extension) # 1 = try to use OCSP stapling, but not require response # 2 = require valid OCSP stapling response # # EAP-FAST variables: # pac_file: File path for the PAC entries. wpa_supplicant will need to be able # to create this file and write updates to it when PAC is being # provisioned or refreshed. Full path to the file should be used since # working directory may change when wpa_supplicant is run in the # background. Alternatively, a named configuration blob can be used by # setting this to blob:// # phase1: fast_provisioning option can be used to enable in-line provisioning # of EAP-FAST credentials (PAC): # 0 = disabled, # 1 = allow unauthenticated provisioning, # 2 = allow authenticated provisioning, # 3 = allow both unauthenticated and authenticated provisioning # fast_max_pac_list_len= option can be used to set the maximum # number of PAC entries to store in a PAC list (default: 10) # fast_pac_format=binary option can be used to select binary format for # storing PAC entries in order to save some space (the default # text format uses about 2.5 times the size of minimal binary # format) # # wpa_supplicant supports number of "EAP workarounds" to work around # interoperability issues with incorrectly behaving authentication servers. # These are enabled by default because some of the issues are present in large # number of authentication servers. Strict EAP conformance mode can be # configured by disabling workarounds with eap_workaround=0. # Station inactivity limit # # If a station does not send anything in ap_max_inactivity seconds, an # empty data frame is sent to it in order to verify whether it is # still in range. If this frame is not ACKed, the station will be # disassociated and then deauthenticated. This feature is used to # clear station table of old entries when the STAs move out of the # range. # # The station can associate again with the AP if it is still in range; # this inactivity poll is just used as a nicer way of verifying # inactivity; i.e., client will not report broken connection because # disassociation frame is not sent immediately without first polling # the STA with a data frame. # default: 300 (i.e., 5 minutes) #ap_max_inactivity=300 # DTIM period in Beacon intervals for AP mode (default: 2) #dtim_period=2 # Beacon interval (default: 100 TU) #beacon_int=100 # disable_ht: Whether HT (802.11n) should be disabled. # 0 = HT enabled (if AP supports it) # 1 = HT disabled # # disable_ht40: Whether HT-40 (802.11n) should be disabled. # 0 = HT-40 enabled (if AP supports it) # 1 = HT-40 disabled # # disable_sgi: Whether SGI (short guard interval) should be disabled. # 0 = SGI enabled (if AP supports it) # 1 = SGI disabled # # disable_ldpc: Whether LDPC should be disabled. # 0 = LDPC enabled (if AP supports it) # 1 = LDPC disabled # # ht40_intolerant: Whether 40 MHz intolerant should be indicated. # 0 = 40 MHz tolerant (default) # 1 = 40 MHz intolerant # # ht_mcs: Configure allowed MCS rates. # Parsed as an array of bytes, in base-16 (ascii-hex) # ht_mcs="" // Use all available (default) # ht_mcs="0xff 00 00 00 00 00 00 00 00 00 " // Use MCS 0-7 only # ht_mcs="0xff ff 00 00 00 00 00 00 00 00 " // Use MCS 0-15 only # # disable_max_amsdu: Whether MAX_AMSDU should be disabled. # -1 = Do not make any changes. # 0 = Enable MAX-AMSDU if hardware supports it. # 1 = Disable AMSDU # # ampdu_factor: Maximum A-MPDU Length Exponent # Value: 0-3, see 7.3.2.56.3 in IEEE Std 802.11n-2009. # # ampdu_density: Allow overriding AMPDU density configuration. # Treated as hint by the kernel. # -1 = Do not make any changes. # 0-3 = Set AMPDU density (aka factor) to specified value. # disable_vht: Whether VHT should be disabled. # 0 = VHT enabled (if AP supports it) # 1 = VHT disabled # # vht_capa: VHT capabilities to set in the override # vht_capa_mask: mask of VHT capabilities # # vht_rx_mcs_nss_1/2/3/4/5/6/7/8: override the MCS set for RX NSS 1-8 # vht_tx_mcs_nss_1/2/3/4/5/6/7/8: override the MCS set for TX NSS 1-8 # 0: MCS 0-7 # 1: MCS 0-8 # 2: MCS 0-9 # 3: not supported # Example blocks: # Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers network={ ssid="simple" psk="very secret passphrase" priority=5 } # Same as previous, but request SSID-specific scanning (for APs that reject # broadcast SSID) network={ ssid="second ssid" scan_ssid=1 psk="very secret passphrase" priority=2 } # Only WPA-PSK is used. Any valid cipher combination is accepted. network={ ssid="example" proto=WPA key_mgmt=WPA-PSK pairwise=CCMP TKIP group=CCMP TKIP WEP104 WEP40 psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb priority=2 } # WPA-Personal(PSK) with TKIP and enforcement for frequent PTK rekeying network={ ssid="example" proto=WPA key_mgmt=WPA-PSK pairwise=TKIP group=TKIP psk="not so secure passphrase" wpa_ptk_rekey=600 } # Only WPA-EAP is used. Both CCMP and TKIP is accepted. An AP that used WEP104 # or WEP40 as the group cipher will not be accepted. network={ ssid="example" proto=RSN key_mgmt=WPA-EAP pairwise=CCMP TKIP group=CCMP TKIP eap=TLS identity="user@example.com" ca_cert="/etc/cert/ca.pem" client_cert="/etc/cert/user.pem" private_key="/etc/cert/user.prv" private_key_passwd="password" priority=1 } # EAP-PEAP/MSCHAPv2 configuration for RADIUS servers that use the new peaplabel # (e.g., Radiator) network={ ssid="example" key_mgmt=WPA-EAP eap=PEAP identity="user@example.com" password="foobar" ca_cert="/etc/cert/ca.pem" phase1="peaplabel=1" phase2="auth=MSCHAPV2" priority=10 } # EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the # unencrypted use. Real identity is sent only within an encrypted TLS tunnel. network={ ssid="example" key_mgmt=WPA-EAP eap=TTLS identity="user@example.com" anonymous_identity="anonymous@example.com" password="foobar" ca_cert="/etc/cert/ca.pem" priority=2 } # EAP-TTLS/MSCHAPv2 configuration with anonymous identity for the unencrypted # use. Real identity is sent only within an encrypted TLS tunnel. network={ ssid="example" key_mgmt=WPA-EAP eap=TTLS identity="user@example.com" anonymous_identity="anonymous@example.com" password="foobar" ca_cert="/etc/cert/ca.pem" phase2="auth=MSCHAPV2" } # WPA-EAP, EAP-TTLS with different CA certificate used for outer and inner # authentication. network={ ssid="example" key_mgmt=WPA-EAP eap=TTLS # Phase1 / outer authentication anonymous_identity="anonymous@example.com" ca_cert="/etc/cert/ca.pem" # Phase 2 / inner authentication phase2="autheap=TLS" ca_cert2="/etc/cert/ca2.pem" client_cert2="/etc/cer/user.pem" private_key2="/etc/cer/user.prv" private_key2_passwd="password" priority=2 } # Both WPA-PSK and WPA-EAP is accepted. Only CCMP is accepted as pairwise and # group cipher. network={ ssid="example" bssid=00:11:22:33:44:55 proto=WPA RSN key_mgmt=WPA-PSK WPA-EAP pairwise=CCMP group=CCMP psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb } # Special characters in SSID, so use hex string. Default to WPA-PSK, WPA-EAP # and all valid ciphers. network={ ssid=00010203 psk=000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f } # EAP-SIM with a GSM SIM or USIM network={ ssid="eap-sim-test" key_mgmt=WPA-EAP eap=SIM pin="1234" pcsc="" } # EAP-PSK network={ ssid="eap-psk-test" key_mgmt=WPA-EAP eap=PSK anonymous_identity="eap_psk_user" password=06b4be19da289f475aa46a33cb793029 identity="eap_psk_user@example.com" } # IEEE 802.1X/EAPOL with dynamically generated WEP keys (i.e., no WPA) using # EAP-TLS for authentication and key generation; require both unicast and # broadcast WEP keys. network={ ssid="1x-test" key_mgmt=IEEE8021X eap=TLS identity="user@example.com" ca_cert="/etc/cert/ca.pem" client_cert="/etc/cert/user.pem" private_key="/etc/cert/user.prv" private_key_passwd="password" eapol_flags=3 } # LEAP with dynamic WEP keys network={ ssid="leap-example" key_mgmt=IEEE8021X eap=LEAP identity="user" password="foobar" } # EAP-IKEv2 using shared secrets for both server and peer authentication network={ ssid="ikev2-example" key_mgmt=WPA-EAP eap=IKEV2 identity="user" password="foobar" } # EAP-FAST with WPA (WPA or WPA2) network={ ssid="eap-fast-test" key_mgmt=WPA-EAP eap=FAST anonymous_identity="FAST-000102030405" identity="username" password="password" phase1="fast_provisioning=1" pac_file="/etc/wpa_supplicant.eap-fast-pac" } network={ ssid="eap-fast-test" key_mgmt=WPA-EAP eap=FAST anonymous_identity="FAST-000102030405" identity="username" password="password" phase1="fast_provisioning=1" pac_file="blob://eap-fast-pac" } # Plaintext connection (no WPA, no IEEE 802.1X) network={ ssid="plaintext-test" key_mgmt=NONE } # Shared WEP key connection (no WPA, no IEEE 802.1X) network={ ssid="static-wep-test" key_mgmt=NONE wep_key0="abcde" wep_key1=0102030405 wep_key2="1234567890123" wep_tx_keyidx=0 priority=5 } # Shared WEP key connection (no WPA, no IEEE 802.1X) using Shared Key # IEEE 802.11 authentication network={ ssid="static-wep-test2" key_mgmt=NONE wep_key0="abcde" wep_key1=0102030405 wep_key2="1234567890123" wep_tx_keyidx=0 priority=5 auth_alg=SHARED } # IBSS/ad-hoc network with RSN network={ ssid="ibss-rsn" key_mgmt=WPA-PSK proto=RSN psk="12345678" mode=1 frequency=2412 pairwise=CCMP group=CCMP } # IBSS/ad-hoc network with WPA-None/TKIP (deprecated) network={ ssid="test adhoc" mode=1 frequency=2412 proto=WPA key_mgmt=WPA-NONE pairwise=NONE group=TKIP psk="secret passphrase" } # Catch all example that allows more or less all configuration modes network={ ssid="example" scan_ssid=1 key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE pairwise=CCMP TKIP group=CCMP TKIP WEP104 WEP40 psk="very secret passphrase" eap=TTLS PEAP TLS identity="user@example.com" password="foobar" ca_cert="/etc/cert/ca.pem" client_cert="/etc/cert/user.pem" private_key="/etc/cert/user.prv" private_key_passwd="password" phase1="peaplabel=0" } # Example of EAP-TLS with smartcard (openssl engine) network={ ssid="example" key_mgmt=WPA-EAP eap=TLS proto=RSN pairwise=CCMP TKIP group=CCMP TKIP identity="user@example.com" ca_cert="/etc/cert/ca.pem" client_cert="/etc/cert/user.pem" engine=1 # The engine configured here must be available. Look at # OpenSSL engine support in the global section. # The key available through the engine must be the private key # matching the client certificate configured above. # use the opensc engine #engine_id="opensc" #key_id="45" # use the pkcs11 engine engine_id="pkcs11" key_id="id_45" # Optional PIN configuration; this can be left out and PIN will be # asked through the control interface pin="1234" } # Example configuration showing how to use an inlined blob as a CA certificate # data instead of using external file network={ ssid="example" key_mgmt=WPA-EAP eap=TTLS identity="user@example.com" anonymous_identity="anonymous@example.com" password="foobar" ca_cert="blob://exampleblob" priority=20 } blob-base64-exampleblob={ SGVsbG8gV29ybGQhCg== } # Wildcard match for SSID (plaintext APs only). This example select any # open AP regardless of its SSID. network={ key_mgmt=NONE } # Example config file that will only scan on channel 36. freq_list=5180 network={ key_mgmt=NONE } # Example MACsec configuration #network={ # key_mgmt=IEEE8021X # eap=TTLS # phase2="auth=PAP" # anonymous_identity="anonymous@example.com" # identity="user@example.com" # password="secretr" # ca_cert="/etc/cert/ca.pem" # eapol_flags=0 # macsec_policy=1 #} wpa_supplicant-2.2/wpa_supplicant/p2p_supplicant.c0000664000175000017500000065244112343617166020373 0ustar jmjm/* * wpa_supplicant - P2P * Copyright (c) 2009-2010, Atheros Communications * Copyright (c) 2010-2014, 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 "eloop.h" #include "common/ieee802_11_common.h" #include "common/ieee802_11_defs.h" #include "common/wpa_ctrl.h" #include "wps/wps_i.h" #include "p2p/p2p.h" #include "ap/hostapd.h" #include "ap/ap_config.h" #include "ap/sta_info.h" #include "ap/ap_drv_ops.h" #include "ap/wps_hostapd.h" #include "ap/p2p_hostapd.h" #include "eapol_supp/eapol_supp_sm.h" #include "rsn_supp/wpa.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "ap.h" #include "config_ssid.h" #include "config.h" #include "notify.h" #include "scan.h" #include "bss.h" #include "offchannel.h" #include "wps_supplicant.h" #include "p2p_supplicant.h" #include "wifi_display.h" /* * How many times to try to scan to find the GO before giving up on join * request. */ #define P2P_MAX_JOIN_SCAN_ATTEMPTS 10 #define P2P_AUTO_PD_SCAN_ATTEMPTS 5 #ifndef P2P_MAX_CLIENT_IDLE /* * How many seconds to try to reconnect to the GO when connection in P2P client * role has been lost. */ #define P2P_MAX_CLIENT_IDLE 10 #endif /* P2P_MAX_CLIENT_IDLE */ #ifndef P2P_MAX_INITIAL_CONN_WAIT /* * How many seconds to wait for initial 4-way handshake to get completed after * WPS provisioning step or after the re-invocation of a persistent group on a * P2P Client. */ #define P2P_MAX_INITIAL_CONN_WAIT 10 #endif /* P2P_MAX_INITIAL_CONN_WAIT */ #ifndef P2P_MAX_INITIAL_CONN_WAIT_GO /* * How many seconds to wait for initial 4-way handshake to get completed after * WPS provisioning step on the GO. This controls the extra time the P2P * operation is considered to be in progress (e.g., to delay other scans) after * WPS provisioning has been completed on the GO during group formation. */ #define P2P_MAX_INITIAL_CONN_WAIT_GO 10 #endif /* P2P_MAX_INITIAL_CONN_WAIT_GO */ #ifndef P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE /* * How many seconds to wait for initial 4-way handshake to get completed after * re-invocation of a persistent group on the GO when the client is expected * to connect automatically (no user interaction). */ #define P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE 15 #endif /* P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE */ #ifndef P2P_CONCURRENT_SEARCH_DELAY #define P2P_CONCURRENT_SEARCH_DELAY 500 #endif /* P2P_CONCURRENT_SEARCH_DELAY */ #define P2P_MGMT_DEVICE_PREFIX "p2p-dev-" enum p2p_group_removal_reason { P2P_GROUP_REMOVAL_UNKNOWN, P2P_GROUP_REMOVAL_SILENT, P2P_GROUP_REMOVAL_FORMATION_FAILED, P2P_GROUP_REMOVAL_REQUESTED, P2P_GROUP_REMOVAL_IDLE_TIMEOUT, P2P_GROUP_REMOVAL_UNAVAILABLE, P2P_GROUP_REMOVAL_GO_ENDING_SESSION, P2P_GROUP_REMOVAL_PSK_FAILURE, P2P_GROUP_REMOVAL_FREQ_CONFLICT }; static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx); static struct wpa_supplicant * wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, int go); static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq, const u8 *ssid, size_t ssid_len); static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, const u8 *ssid, size_t ssid_len); static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx); static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr, const u8 *dev_addr, enum p2p_wps_method wps_method, int auto_join, int freq, const u8 *ssid, size_t ssid_len); static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s); static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s); static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx); static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s); static void wpas_p2p_group_formation_timeout(void *eloop_ctx, void *timeout_ctx); static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx); static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, int group_added); static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s); static void wpas_stop_listen(void *ctx); static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx); /* * Get the number of concurrent channels that the HW can operate, but that are * currently not in use by any of the wpa_supplicant interfaces. */ static int wpas_p2p_num_unused_channels(struct wpa_supplicant *wpa_s) { int *freqs; int num, unused; freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int)); if (!freqs) return -1; num = get_shared_radio_freqs(wpa_s, freqs, wpa_s->num_multichan_concurrent); os_free(freqs); unused = wpa_s->num_multichan_concurrent - num; wpa_dbg(wpa_s, MSG_DEBUG, "P2P: num_unused_channels: %d", unused); return unused; } /* * Get the frequencies that are currently in use by one or more of the virtual * interfaces, and that are also valid for P2P operation. */ static int wpas_p2p_valid_oper_freqs(struct wpa_supplicant *wpa_s, int *p2p_freqs, unsigned int len) { int *freqs; unsigned int num, i, j; freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int)); if (!freqs) return -1; num = get_shared_radio_freqs(wpa_s, freqs, wpa_s->num_multichan_concurrent); os_memset(p2p_freqs, 0, sizeof(int) * len); for (i = 0, j = 0; i < num && j < len; i++) { if (p2p_supported_freq(wpa_s->global->p2p, freqs[i])) p2p_freqs[j++] = freqs[i]; } os_free(freqs); dump_freq_array(wpa_s, "valid for P2P", p2p_freqs, j); return j; } static void wpas_p2p_set_own_freq_preference(struct wpa_supplicant *wpa_s, int freq) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; if (wpa_s->parent->conf->p2p_ignore_shared_freq && freq > 0 && wpa_s->num_multichan_concurrent > 1 && wpas_p2p_num_unused_channels(wpa_s) > 0) { wpa_printf(MSG_DEBUG, "P2P: Ignore own channel preference %d MHz due to p2p_ignore_shared_freq=1 configuration", freq); freq = 0; } p2p_set_own_freq_preference(wpa_s->global->p2p, freq); } static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { size_t i; if (wpa_s->p2p_scan_work) { struct wpa_radio_work *work = wpa_s->p2p_scan_work; wpa_s->p2p_scan_work = NULL; radio_work_done(work); } if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS)", (int) scan_res->num); for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *bss = scan_res->res[i]; struct os_reltime time_tmp_age, entry_ts; const u8 *ies; size_t ies_len; time_tmp_age.sec = bss->age / 1000; time_tmp_age.usec = (bss->age % 1000) * 1000; os_reltime_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts); ies = (const u8 *) (bss + 1); ies_len = bss->ie_len; if (bss->beacon_ie_len > 0 && !wpa_scan_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) && wpa_scan_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) { wpa_printf(MSG_DEBUG, "P2P: Use P2P IE(s) from Beacon frame since no P2P IE(s) in Probe Response frames received for " MACSTR, MAC2STR(bss->bssid)); ies = ies + ies_len; ies_len = bss->beacon_ie_len; } if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid, bss->freq, &entry_ts, bss->level, ies, ies_len) > 0) break; } p2p_scan_res_handled(wpa_s->global->p2p); } static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit) { struct wpa_supplicant *wpa_s = work->wpa_s; struct wpa_driver_scan_params *params = work->ctx; int ret; if (deinit) { if (!work->started) { wpa_scan_free_params(params); return; } wpa_s->p2p_scan_work = NULL; return; } ret = wpa_drv_scan(wpa_s, params); wpa_scan_free_params(params); work->ctx = NULL; if (ret) { radio_work_done(work); return; } os_get_reltime(&wpa_s->scan_trigger_time); wpa_s->scan_res_handler = wpas_p2p_scan_res_handler; wpa_s->own_scan_requested = 1; wpa_s->p2p_scan_work = work; } static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id, u16 pw_id) { struct wpa_supplicant *wpa_s = ctx; struct wpa_driver_scan_params *params = NULL; struct wpabuf *wps_ie, *ies; size_t ielen; u8 *n; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; if (wpa_s->p2p_scan_work) { wpa_dbg(wpa_s, MSG_INFO, "P2P: Reject scan trigger since one is already pending"); return -1; } params = os_zalloc(sizeof(*params)); if (params == NULL) return -1; /* P2P Wildcard SSID */ params->num_ssids = 1; n = os_malloc(P2P_WILDCARD_SSID_LEN); if (n == NULL) goto fail; os_memcpy(n, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN); params->ssids[0].ssid = n; params->ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN; wpa_s->wps->dev.p2p = 1; wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev, wpa_s->wps->uuid, WPS_REQ_ENROLLEE, num_req_dev_types, req_dev_types); if (wps_ie == NULL) goto fail; ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); if (ies == NULL) { wpabuf_free(wps_ie); goto fail; } wpabuf_put_buf(ies, wps_ie); wpabuf_free(wps_ie); p2p_scan_ie(wpa_s->global->p2p, ies, dev_id); params->p2p_probe = 1; n = os_malloc(wpabuf_len(ies)); if (n == NULL) { wpabuf_free(ies); goto fail; } os_memcpy(n, wpabuf_head(ies), wpabuf_len(ies)); params->extra_ies = n; params->extra_ies_len = wpabuf_len(ies); wpabuf_free(ies); switch (type) { case P2P_SCAN_SOCIAL: params->freqs = os_malloc(4 * sizeof(int)); if (params->freqs == NULL) goto fail; params->freqs[0] = 2412; params->freqs[1] = 2437; params->freqs[2] = 2462; params->freqs[3] = 0; break; case P2P_SCAN_FULL: break; case P2P_SCAN_SOCIAL_PLUS_ONE: params->freqs = os_malloc(5 * sizeof(int)); if (params->freqs == NULL) goto fail; params->freqs[0] = 2412; params->freqs[1] = 2437; params->freqs[2] = 2462; params->freqs[3] = freq; params->freqs[4] = 0; break; } radio_remove_works(wpa_s, "p2p-scan", 0); if (radio_add_work(wpa_s, 0, "p2p-scan", 0, wpas_p2p_trigger_scan_cb, params) < 0) goto fail; return 0; fail: wpa_scan_free_params(params); return -1; } static enum wpa_driver_if_type wpas_p2p_if_type(int p2p_group_interface) { switch (p2p_group_interface) { case P2P_GROUP_INTERFACE_PENDING: return WPA_IF_P2P_GROUP; case P2P_GROUP_INTERFACE_GO: return WPA_IF_P2P_GO; case P2P_GROUP_INTERFACE_CLIENT: return WPA_IF_P2P_CLIENT; } return WPA_IF_P2P_GROUP; } static struct wpa_supplicant * wpas_get_p2p_group(struct wpa_supplicant *wpa_s, const u8 *ssid, size_t ssid_len, int *go) { struct wpa_ssid *s; for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) { for (s = wpa_s->conf->ssid; s; s = s->next) { if (s->disabled != 0 || !s->p2p_group || s->ssid_len != ssid_len || os_memcmp(ssid, s->ssid, ssid_len) != 0) continue; if (s->mode == WPAS_MODE_P2P_GO && s != wpa_s->current_ssid) continue; if (go) *go = s->mode == WPAS_MODE_P2P_GO; return wpa_s; } } return NULL; } static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, enum p2p_group_removal_reason removal_reason) { struct wpa_ssid *ssid; char *gtype; const char *reason; ssid = wpa_s->current_ssid; if (ssid == NULL) { /* * The current SSID was not known, but there may still be a * pending P2P group interface waiting for provisioning or a * P2P group that is trying to reconnect. */ ssid = wpa_s->conf->ssid; while (ssid) { if (ssid->p2p_group && ssid->disabled != 2) break; ssid = ssid->next; } if (ssid == NULL && wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE) { wpa_printf(MSG_ERROR, "P2P: P2P group interface " "not found"); return -1; } } if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO) gtype = "GO"; else if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT || (ssid && ssid->mode == WPAS_MODE_INFRA)) { wpa_s->reassociate = 0; wpa_s->disconnected = 1; wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); gtype = "client"; } else gtype = "GO"; if (wpa_s->cross_connect_in_use) { wpa_s->cross_connect_in_use = 0; wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s", wpa_s->ifname, wpa_s->cross_connect_uplink); } switch (removal_reason) { case P2P_GROUP_REMOVAL_REQUESTED: reason = " reason=REQUESTED"; break; case P2P_GROUP_REMOVAL_FORMATION_FAILED: reason = " reason=FORMATION_FAILED"; break; case P2P_GROUP_REMOVAL_IDLE_TIMEOUT: reason = " reason=IDLE"; break; case P2P_GROUP_REMOVAL_UNAVAILABLE: reason = " reason=UNAVAILABLE"; break; case P2P_GROUP_REMOVAL_GO_ENDING_SESSION: reason = " reason=GO_ENDING_SESSION"; break; case P2P_GROUP_REMOVAL_PSK_FAILURE: reason = " reason=PSK_FAILURE"; break; case P2P_GROUP_REMOVAL_FREQ_CONFLICT: reason = " reason=FREQ_CONFLICT"; break; default: reason = ""; break; } if (removal_reason != P2P_GROUP_REMOVAL_SILENT) { wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s%s", wpa_s->ifname, gtype, reason); } if (eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL) > 0) wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group freq_conflict timeout"); if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0) wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout"); if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL) > 0) { wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group formation " "timeout"); wpa_s->p2p_in_provisioning = 0; } wpa_s->p2p_in_invitation = 0; /* * Make sure wait for the first client does not remain active after the * group has been removed. */ wpa_s->global->p2p_go_wait_client.sec = 0; if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid) wpas_notify_p2p_group_removed(wpa_s, ssid, gtype); if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) { struct wpa_global *global; char *ifname; enum wpa_driver_if_type type; wpa_printf(MSG_DEBUG, "P2P: Remove group interface %s", wpa_s->ifname); global = wpa_s->global; ifname = os_strdup(wpa_s->ifname); type = wpas_p2p_if_type(wpa_s->p2p_group_interface); wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0); wpa_s = global->ifaces; if (wpa_s && ifname) wpa_drv_if_remove(wpa_s, type, ifname); os_free(ifname); return 1; } if (!wpa_s->p2p_go_group_formation_completed) { wpa_s->global->p2p_group_formation = NULL; wpa_s->p2p_in_provisioning = 0; } wpa_s->show_group_started = 0; os_free(wpa_s->go_params); wpa_s->go_params = NULL; wpa_s->waiting_presence_resp = 0; wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network"); if (ssid && (ssid->p2p_group || ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION || (ssid->key_mgmt & WPA_KEY_MGMT_WPS))) { int id = ssid->id; if (ssid == wpa_s->current_ssid) { wpa_sm_set_config(wpa_s->wpa, NULL); eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_s->current_ssid = NULL; } /* * Networks objects created during any P2P activities are not * exposed out as they might/will confuse certain non-P2P aware * applications since these network objects won't behave like * regular ones. * * Likewise, we don't send out network removed signals for such * network objects. */ wpa_config_remove_network(wpa_s->conf, id); wpa_supplicant_clear_status(wpa_s); wpa_supplicant_cancel_sched_scan(wpa_s); } else { wpa_printf(MSG_DEBUG, "P2P: Temporary group network not " "found"); } if (wpa_s->ap_iface) wpa_supplicant_ap_deinit(wpa_s); else wpa_drv_deinit_p2p_cli(wpa_s); return 0; } static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s, u8 *go_dev_addr, const u8 *ssid, size_t ssid_len) { struct wpa_bss *bss; const u8 *bssid; struct wpabuf *p2p; u8 group_capab; const u8 *addr; if (wpa_s->go_params) bssid = wpa_s->go_params->peer_interface_addr; else bssid = wpa_s->bssid; bss = wpa_bss_get(wpa_s, bssid, ssid, ssid_len); if (bss == NULL && wpa_s->go_params && !is_zero_ether_addr(wpa_s->go_params->peer_device_addr)) bss = wpa_bss_get_p2p_dev_addr( wpa_s, wpa_s->go_params->peer_device_addr); if (bss == NULL) { u8 iface_addr[ETH_ALEN]; if (p2p_get_interface_addr(wpa_s->global->p2p, bssid, iface_addr) == 0) bss = wpa_bss_get(wpa_s, iface_addr, ssid, ssid_len); } if (bss == NULL) { wpa_printf(MSG_DEBUG, "P2P: Could not figure out whether " "group is persistent - BSS " MACSTR " not found", MAC2STR(bssid)); return 0; } p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE); if (p2p == NULL) p2p = wpa_bss_get_vendor_ie_multi_beacon(bss, P2P_IE_VENDOR_TYPE); if (p2p == NULL) { wpa_printf(MSG_DEBUG, "P2P: Could not figure out whether " "group is persistent - BSS " MACSTR " did not include P2P IE", MAC2STR(bssid)); wpa_hexdump(MSG_DEBUG, "P2P: Probe Response IEs", (u8 *) (bss + 1), bss->ie_len); wpa_hexdump(MSG_DEBUG, "P2P: Beacon IEs", ((u8 *) bss + 1) + bss->ie_len, bss->beacon_ie_len); return 0; } group_capab = p2p_get_group_capab(p2p); addr = p2p_get_go_dev_addr(p2p); wpa_printf(MSG_DEBUG, "P2P: Checking whether group is persistent: " "group_capab=0x%x", group_capab); if (addr) { os_memcpy(go_dev_addr, addr, ETH_ALEN); wpa_printf(MSG_DEBUG, "P2P: GO Device Address " MACSTR, MAC2STR(addr)); } else os_memset(go_dev_addr, 0, ETH_ALEN); wpabuf_free(p2p); wpa_printf(MSG_DEBUG, "P2P: BSS " MACSTR " group_capab=0x%x " "go_dev_addr=" MACSTR, MAC2STR(bssid), group_capab, MAC2STR(go_dev_addr)); return group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP; } static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, const u8 *go_dev_addr) { struct wpa_ssid *s; int changed = 0; wpa_printf(MSG_DEBUG, "P2P: Storing credentials for a persistent " "group (GO Dev Addr " MACSTR ")", MAC2STR(go_dev_addr)); for (s = wpa_s->conf->ssid; s; s = s->next) { if (s->disabled == 2 && os_memcmp(go_dev_addr, s->bssid, ETH_ALEN) == 0 && s->ssid_len == ssid->ssid_len && os_memcmp(ssid->ssid, s->ssid, ssid->ssid_len) == 0) break; } if (s) { wpa_printf(MSG_DEBUG, "P2P: Update existing persistent group " "entry"); if (ssid->passphrase && !s->passphrase) changed = 1; else if (ssid->passphrase && s->passphrase && os_strcmp(ssid->passphrase, s->passphrase) != 0) changed = 1; } else { wpa_printf(MSG_DEBUG, "P2P: Create a new persistent group " "entry"); changed = 1; s = wpa_config_add_network(wpa_s->conf); if (s == NULL) return -1; /* * Instead of network_added we emit persistent_group_added * notification. Also to keep the defense checks in * persistent_group obj registration method, we set the * relevant flags in s to designate it as a persistent group. */ s->p2p_group = 1; s->p2p_persistent_group = 1; wpas_notify_persistent_group_added(wpa_s, s); wpa_config_set_network_defaults(s); } s->p2p_group = 1; s->p2p_persistent_group = 1; s->disabled = 2; s->bssid_set = 1; os_memcpy(s->bssid, go_dev_addr, ETH_ALEN); s->mode = ssid->mode; s->auth_alg = WPA_AUTH_ALG_OPEN; s->key_mgmt = WPA_KEY_MGMT_PSK; s->proto = WPA_PROTO_RSN; s->pairwise_cipher = WPA_CIPHER_CCMP; s->export_keys = 1; if (ssid->passphrase) { os_free(s->passphrase); s->passphrase = os_strdup(ssid->passphrase); } if (ssid->psk_set) { s->psk_set = 1; os_memcpy(s->psk, ssid->psk, 32); } if (s->passphrase && !s->psk_set) wpa_config_update_psk(s); if (s->ssid == NULL || s->ssid_len < ssid->ssid_len) { os_free(s->ssid); s->ssid = os_malloc(ssid->ssid_len); } if (s->ssid) { s->ssid_len = ssid->ssid_len; os_memcpy(s->ssid, ssid->ssid, s->ssid_len); } if (ssid->mode == WPAS_MODE_P2P_GO && wpa_s->global->add_psk) { dl_list_add(&s->psk_list, &wpa_s->global->add_psk->list); wpa_s->global->add_psk = NULL; changed = 1; } if (changed && wpa_s->conf->update_config && wpa_config_write(wpa_s->confname, wpa_s->conf)) { wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration"); } return s->id; } static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s, const u8 *addr) { struct wpa_ssid *ssid, *s; u8 *n; size_t i; int found = 0; ssid = wpa_s->current_ssid; if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO || !ssid->p2p_persistent_group) return; for (s = wpa_s->parent->conf->ssid; s; s = s->next) { if (s->disabled != 2 || s->mode != WPAS_MODE_P2P_GO) continue; if (s->ssid_len == ssid->ssid_len && os_memcmp(s->ssid, ssid->ssid, s->ssid_len) == 0) break; } if (s == NULL) return; for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) { if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, addr, ETH_ALEN) != 0) continue; if (i == s->num_p2p_clients - 1) return; /* already the most recent entry */ /* move the entry to mark it most recent */ os_memmove(s->p2p_client_list + i * ETH_ALEN, s->p2p_client_list + (i + 1) * ETH_ALEN, (s->num_p2p_clients - i - 1) * ETH_ALEN); os_memcpy(s->p2p_client_list + (s->num_p2p_clients - 1) * ETH_ALEN, addr, ETH_ALEN); found = 1; break; } if (!found && s->num_p2p_clients < P2P_MAX_STORED_CLIENTS) { n = os_realloc_array(s->p2p_client_list, s->num_p2p_clients + 1, ETH_ALEN); if (n == NULL) return; os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN); s->p2p_client_list = n; s->num_p2p_clients++; } else if (!found) { /* Not enough room for an additional entry - drop the oldest * entry */ os_memmove(s->p2p_client_list, s->p2p_client_list + ETH_ALEN, (s->num_p2p_clients - 1) * ETH_ALEN); os_memcpy(s->p2p_client_list + (s->num_p2p_clients - 1) * ETH_ALEN, addr, ETH_ALEN); } if (wpa_s->parent->conf->update_config && wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf)) wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration"); } static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, int success) { struct wpa_ssid *ssid; const char *ssid_txt; int client; int persistent; u8 go_dev_addr[ETH_ALEN]; int network_id = -1; /* * This callback is likely called for the main interface. Update wpa_s * to use the group interface if a new interface was created for the * group. */ if (wpa_s->global->p2p_group_formation) wpa_s = wpa_s->global->p2p_group_formation; if (wpa_s->p2p_go_group_formation_completed) { wpa_s->global->p2p_group_formation = NULL; wpa_s->p2p_in_provisioning = 0; } wpa_s->p2p_in_invitation = 0; if (!success) { wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_FORMATION_FAILURE); wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_FORMATION_FAILED); return; } wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_FORMATION_SUCCESS); ssid = wpa_s->current_ssid; if (ssid && ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) { ssid->mode = WPAS_MODE_P2P_GO; p2p_group_notif_formation_done(wpa_s->p2p_group); wpa_supplicant_ap_mac_addr_filter(wpa_s, NULL); } persistent = 0; if (ssid) { ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len); client = ssid->mode == WPAS_MODE_INFRA; if (ssid->mode == WPAS_MODE_P2P_GO) { persistent = ssid->p2p_persistent_group; os_memcpy(go_dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN); } else persistent = wpas_p2p_persistent_group(wpa_s, go_dev_addr, ssid->ssid, ssid->ssid_len); } else { ssid_txt = ""; client = wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT; os_memset(go_dev_addr, 0, ETH_ALEN); } wpa_s->show_group_started = 0; if (client) { /* * Indicate event only after successfully completed 4-way * handshake, i.e., when the interface is ready for data * packets. */ wpa_s->show_group_started = 1; } else if (ssid && ssid->passphrase == NULL && ssid->psk_set) { char psk[65]; wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32); wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED "%s GO ssid=\"%s\" freq=%d psk=%s go_dev_addr=" MACSTR "%s", wpa_s->ifname, ssid_txt, ssid->frequency, psk, MAC2STR(go_dev_addr), persistent ? " [PERSISTENT]" : ""); wpas_p2p_cross_connect_setup(wpa_s); wpas_p2p_set_group_idle_timeout(wpa_s); } else { wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" " "go_dev_addr=" MACSTR "%s", wpa_s->ifname, ssid_txt, ssid ? ssid->frequency : 0, ssid && ssid->passphrase ? ssid->passphrase : "", MAC2STR(go_dev_addr), persistent ? " [PERSISTENT]" : ""); wpas_p2p_cross_connect_setup(wpa_s); wpas_p2p_set_group_idle_timeout(wpa_s); } if (persistent) network_id = wpas_p2p_store_persistent_group(wpa_s->parent, ssid, go_dev_addr); else { os_free(wpa_s->global->add_psk); wpa_s->global->add_psk = NULL; } if (network_id < 0 && ssid) network_id = ssid->id; if (!client) { wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0); os_get_reltime(&wpa_s->global->p2p_go_wait_client); } } struct send_action_work { unsigned int freq; u8 dst[ETH_ALEN]; u8 src[ETH_ALEN]; u8 bssid[ETH_ALEN]; size_t len; unsigned int wait_time; u8 buf[0]; }; static void wpas_p2p_send_action_work_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; if (!wpa_s->p2p_send_action_work) return; wpa_printf(MSG_DEBUG, "P2P: Send Action frame radio work timed out"); os_free(wpa_s->p2p_send_action_work->ctx); radio_work_done(wpa_s->p2p_send_action_work); wpa_s->p2p_send_action_work = NULL; } static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *data, size_t data_len, enum offchannel_send_action_result result) { enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS; if (wpa_s->p2p_send_action_work) { struct send_action_work *awork; awork = wpa_s->p2p_send_action_work->ctx; if (awork->wait_time == 0) { os_free(awork); radio_work_done(wpa_s->p2p_send_action_work); wpa_s->p2p_send_action_work = NULL; } else { /* * In theory, this should not be needed, but number of * places in the P2P code is still using non-zero wait * time for the last Action frame in the sequence and * some of these do not call send_action_done(). */ eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, wpa_s, NULL); eloop_register_timeout( 0, awork->wait_time * 1000, wpas_p2p_send_action_work_timeout, wpa_s, NULL); } } if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) return; switch (result) { case OFFCHANNEL_SEND_ACTION_SUCCESS: res = P2P_SEND_ACTION_SUCCESS; break; case OFFCHANNEL_SEND_ACTION_NO_ACK: res = P2P_SEND_ACTION_NO_ACK; break; case OFFCHANNEL_SEND_ACTION_FAILED: res = P2P_SEND_ACTION_FAILED; break; } p2p_send_action_cb(wpa_s->global->p2p, freq, dst, src, bssid, res); if (result != OFFCHANNEL_SEND_ACTION_SUCCESS && wpa_s->pending_pd_before_join && (os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 || os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0) && wpa_s->p2p_fallback_to_go_neg) { wpa_s->pending_pd_before_join = 0; wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req " "during p2p_connect-auto"); wpas_p2p_fallback_to_go_neg(wpa_s, 0); return; } } static void wpas_send_action_cb(struct wpa_radio_work *work, int deinit) { struct wpa_supplicant *wpa_s = work->wpa_s; struct send_action_work *awork = work->ctx; if (deinit) { if (work->started) { eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, wpa_s, NULL); wpa_s->p2p_send_action_work = NULL; offchannel_send_action_done(wpa_s); } os_free(awork); return; } if (offchannel_send_action(wpa_s, awork->freq, awork->dst, awork->src, awork->bssid, awork->buf, awork->len, awork->wait_time, wpas_p2p_send_action_tx_status, 1) < 0) { os_free(awork); radio_work_done(work); return; } wpa_s->p2p_send_action_work = work; } static int wpas_send_action_work(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *buf, size_t len, unsigned int wait_time) { struct send_action_work *awork; if (wpa_s->p2p_send_action_work) { wpa_printf(MSG_DEBUG, "P2P: Cannot schedule new p2p-send-action work since one is already pending"); return -1; } awork = os_zalloc(sizeof(*awork) + len); if (awork == NULL) return -1; awork->freq = freq; os_memcpy(awork->dst, dst, ETH_ALEN); os_memcpy(awork->src, src, ETH_ALEN); os_memcpy(awork->bssid, bssid, ETH_ALEN); awork->len = len; awork->wait_time = wait_time; os_memcpy(awork->buf, buf, len); if (radio_add_work(wpa_s, freq, "p2p-send-action", 0, wpas_send_action_cb, awork) < 0) { os_free(awork); return -1; } return 0; } static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *buf, size_t len, unsigned int wait_time) { struct wpa_supplicant *wpa_s = ctx; int listen_freq = -1, send_freq = -1; if (wpa_s->p2p_listen_work) listen_freq = wpa_s->p2p_listen_work->freq; if (wpa_s->p2p_send_action_work) send_freq = wpa_s->p2p_send_action_work->freq; if (listen_freq != (int) freq && send_freq != (int) freq) { wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d)", listen_freq, send_freq); return wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf, len, wait_time); } wpa_printf(MSG_DEBUG, "P2P: Use ongoing radio work for Action frame TX"); return offchannel_send_action(wpa_s, freq, dst, src, bssid, buf, len, wait_time, wpas_p2p_send_action_tx_status, 1); } static void wpas_send_action_done(void *ctx) { struct wpa_supplicant *wpa_s = ctx; if (wpa_s->p2p_send_action_work) { eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, wpa_s, NULL); os_free(wpa_s->p2p_send_action_work->ctx); radio_work_done(wpa_s->p2p_send_action_work); wpa_s->p2p_send_action_work = NULL; } offchannel_send_action_done(wpa_s); } static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *params) { if (wpa_s->go_params == NULL) { wpa_s->go_params = os_malloc(sizeof(*params)); if (wpa_s->go_params == NULL) return -1; } os_memcpy(wpa_s->go_params, params, sizeof(*params)); return 0; } static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *res) { wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR " dev_addr " MACSTR " wps_method %d", MAC2STR(res->peer_interface_addr), MAC2STR(res->peer_device_addr), res->wps_method); wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start WPS Enrollee for SSID", res->ssid, res->ssid_len); wpa_supplicant_ap_deinit(wpa_s); wpas_copy_go_neg_results(wpa_s, res); if (res->wps_method == WPS_PBC) { wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1); #ifdef CONFIG_WPS_NFC } else if (res->wps_method == WPS_NFC) { wpas_wps_start_nfc(wpa_s, res->peer_device_addr, res->peer_interface_addr, wpa_s->parent->p2p_oob_dev_pw, wpa_s->parent->p2p_oob_dev_pw_id, 1, wpa_s->parent->p2p_oob_dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER ? wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL, NULL, 0, 0); #endif /* CONFIG_WPS_NFC */ } else { u16 dev_pw_id = DEV_PW_DEFAULT; if (wpa_s->p2p_wps_method == WPS_PIN_KEYPAD) dev_pw_id = DEV_PW_REGISTRAR_SPECIFIED; wpas_wps_start_pin(wpa_s, res->peer_interface_addr, wpa_s->p2p_pin, 1, dev_pw_id); } } static void wpas_p2p_add_psk_list(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct wpa_ssid *persistent; struct psk_list_entry *psk; struct hostapd_data *hapd; if (!wpa_s->ap_iface) return; persistent = wpas_p2p_get_persistent(wpa_s->parent, NULL, ssid->ssid, ssid->ssid_len); if (persistent == NULL) return; hapd = wpa_s->ap_iface->bss[0]; dl_list_for_each(psk, &persistent->psk_list, struct psk_list_entry, list) { struct hostapd_wpa_psk *hpsk; wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Add persistent group PSK entry for " MACSTR " psk=%d", MAC2STR(psk->addr), psk->p2p); hpsk = os_zalloc(sizeof(*hpsk)); if (hpsk == NULL) break; os_memcpy(hpsk->psk, psk->psk, PMK_LEN); if (psk->p2p) os_memcpy(hpsk->p2p_dev_addr, psk->addr, ETH_ALEN); else os_memcpy(hpsk->addr, psk->addr, ETH_ALEN); hpsk->next = hapd->conf->ssid.wpa_psk; hapd->conf->ssid.wpa_psk = hpsk; } } static void p2p_go_configured(void *ctx, void *data) { struct wpa_supplicant *wpa_s = ctx; struct p2p_go_neg_results *params = data; struct wpa_ssid *ssid; int network_id = -1; ssid = wpa_s->current_ssid; if (ssid && ssid->mode == WPAS_MODE_P2P_GO) { wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning"); if (wpa_s->global->p2p_group_formation == wpa_s) wpa_s->global->p2p_group_formation = NULL; if (os_strlen(params->passphrase) > 0) { wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED "%s GO ssid=\"%s\" freq=%d " "passphrase=\"%s\" go_dev_addr=" MACSTR "%s", wpa_s->ifname, wpa_ssid_txt(ssid->ssid, ssid->ssid_len), ssid->frequency, params->passphrase, MAC2STR(wpa_s->global->p2p_dev_addr), params->persistent_group ? " [PERSISTENT]" : ""); } else { char psk[65]; wpa_snprintf_hex(psk, sizeof(psk), params->psk, sizeof(params->psk)); wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED "%s GO ssid=\"%s\" freq=%d psk=%s " "go_dev_addr=" MACSTR "%s", wpa_s->ifname, wpa_ssid_txt(ssid->ssid, ssid->ssid_len), ssid->frequency, psk, MAC2STR(wpa_s->global->p2p_dev_addr), params->persistent_group ? " [PERSISTENT]" : ""); } os_get_reltime(&wpa_s->global->p2p_go_wait_client); if (params->persistent_group) { network_id = wpas_p2p_store_persistent_group( wpa_s->parent, ssid, wpa_s->global->p2p_dev_addr); wpas_p2p_add_psk_list(wpa_s, ssid); } if (network_id < 0) network_id = ssid->id; wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0); wpas_p2p_cross_connect_setup(wpa_s); wpas_p2p_set_group_idle_timeout(wpa_s); if (wpa_s->p2p_first_connection_timeout) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Start group formation timeout of %d seconds until first data connection on GO", wpa_s->p2p_first_connection_timeout); wpa_s->p2p_go_group_formation_completed = 0; wpa_s->global->p2p_group_formation = wpa_s; eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); eloop_register_timeout( wpa_s->p2p_first_connection_timeout, 0, wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); } return; } wpa_printf(MSG_DEBUG, "P2P: Setting up WPS for GO provisioning"); if (wpa_supplicant_ap_mac_addr_filter(wpa_s, params->peer_interface_addr)) { wpa_printf(MSG_DEBUG, "P2P: Failed to setup MAC address " "filtering"); return; } if (params->wps_method == WPS_PBC) { wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr, params->peer_device_addr); #ifdef CONFIG_WPS_NFC } else if (params->wps_method == WPS_NFC) { if (wpa_s->parent->p2p_oob_dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && !wpa_s->parent->p2p_oob_dev_pw) { wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known"); return; } wpas_ap_wps_add_nfc_pw( wpa_s, wpa_s->parent->p2p_oob_dev_pw_id, wpa_s->parent->p2p_oob_dev_pw, wpa_s->parent->p2p_peer_oob_pk_hash_known ? wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL); #endif /* CONFIG_WPS_NFC */ } else if (wpa_s->p2p_pin[0]) wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr, wpa_s->p2p_pin, NULL, 0, 0); os_free(wpa_s->go_params); wpa_s->go_params = NULL; } static void wpas_start_wps_go(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *params, int group_formation) { struct wpa_ssid *ssid; wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Starting GO"); if (wpas_copy_go_neg_results(wpa_s, params) < 0) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not copy GO Negotiation " "results"); return; } ssid = wpa_config_add_network(wpa_s->conf); if (ssid == NULL) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not add network for GO"); return; } wpa_s->show_group_started = 0; wpa_config_set_network_defaults(ssid); ssid->temporary = 1; ssid->p2p_group = 1; ssid->p2p_persistent_group = params->persistent_group; ssid->mode = group_formation ? WPAS_MODE_P2P_GROUP_FORMATION : WPAS_MODE_P2P_GO; ssid->frequency = params->freq; ssid->ht40 = params->ht40; ssid->vht = params->vht; ssid->ssid = os_zalloc(params->ssid_len + 1); if (ssid->ssid) { os_memcpy(ssid->ssid, params->ssid, params->ssid_len); ssid->ssid_len = params->ssid_len; } ssid->auth_alg = WPA_AUTH_ALG_OPEN; ssid->key_mgmt = WPA_KEY_MGMT_PSK; ssid->proto = WPA_PROTO_RSN; ssid->pairwise_cipher = WPA_CIPHER_CCMP; if (os_strlen(params->passphrase) > 0) { ssid->passphrase = os_strdup(params->passphrase); if (ssid->passphrase == NULL) { wpa_msg_global(wpa_s, MSG_ERROR, "P2P: Failed to copy passphrase for GO"); wpa_config_remove_network(wpa_s->conf, ssid->id); return; } } else ssid->passphrase = NULL; ssid->psk_set = params->psk_set; if (ssid->psk_set) os_memcpy(ssid->psk, params->psk, sizeof(ssid->psk)); else if (ssid->passphrase) wpa_config_update_psk(ssid); ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity; wpa_s->ap_configured_cb = p2p_go_configured; wpa_s->ap_configured_cb_ctx = wpa_s; wpa_s->ap_configured_cb_data = wpa_s->go_params; wpa_s->scan_req = NORMAL_SCAN_REQ; wpa_s->connect_without_scan = ssid; wpa_s->reassociate = 1; wpa_s->disconnected = 0; wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Request scan (that will be skipped) to " "start GO)"); wpa_supplicant_req_scan(wpa_s, 0, 0); } static void wpas_p2p_clone_config(struct wpa_supplicant *dst, const struct wpa_supplicant *src) { struct wpa_config *d; const struct wpa_config *s; d = dst->conf; s = src->conf; #define C(n) if (s->n) d->n = os_strdup(s->n) C(device_name); C(manufacturer); C(model_name); C(model_number); C(serial_number); C(config_methods); #undef C os_memcpy(d->device_type, s->device_type, WPS_DEV_TYPE_LEN); os_memcpy(d->sec_device_type, s->sec_device_type, sizeof(d->sec_device_type)); d->num_sec_device_types = s->num_sec_device_types; d->p2p_group_idle = s->p2p_group_idle; d->p2p_intra_bss = s->p2p_intra_bss; d->persistent_reconnect = s->persistent_reconnect; d->max_num_sta = s->max_num_sta; d->pbc_in_m1 = s->pbc_in_m1; d->ignore_old_scan_res = s->ignore_old_scan_res; d->beacon_int = s->beacon_int; d->dtim_period = s->dtim_period; d->disassoc_low_ack = s->disassoc_low_ack; d->disable_scan_offload = s->disable_scan_offload; if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey) { d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey); d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey); } } static void wpas_p2p_get_group_ifname(struct wpa_supplicant *wpa_s, char *ifname, size_t len) { char *ifname_ptr = wpa_s->ifname; if (os_strncmp(wpa_s->ifname, P2P_MGMT_DEVICE_PREFIX, os_strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) { ifname_ptr = os_strrchr(wpa_s->ifname, '-') + 1; } os_snprintf(ifname, len, "p2p-%s-%d", ifname_ptr, wpa_s->p2p_group_idx); if (os_strlen(ifname) >= IFNAMSIZ && os_strlen(wpa_s->ifname) < IFNAMSIZ) { /* Try to avoid going over the IFNAMSIZ length limit */ os_snprintf(ifname, len, "p2p-%d", wpa_s->p2p_group_idx); } } static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s, enum wpa_driver_if_type type) { char ifname[120], force_ifname[120]; if (wpa_s->pending_interface_name[0]) { wpa_printf(MSG_DEBUG, "P2P: Pending virtual interface exists " "- skip creation of a new one"); if (is_zero_ether_addr(wpa_s->pending_interface_addr)) { wpa_printf(MSG_DEBUG, "P2P: Pending virtual address " "unknown?! ifname='%s'", wpa_s->pending_interface_name); return -1; } return 0; } wpas_p2p_get_group_ifname(wpa_s, ifname, sizeof(ifname)); force_ifname[0] = '\0'; wpa_printf(MSG_DEBUG, "P2P: Create a new interface %s for the group", ifname); wpa_s->p2p_group_idx++; wpa_s->pending_interface_type = type; if (wpa_drv_if_add(wpa_s, type, ifname, NULL, NULL, force_ifname, wpa_s->pending_interface_addr, NULL) < 0) { wpa_printf(MSG_ERROR, "P2P: Failed to create new group " "interface"); return -1; } if (force_ifname[0]) { wpa_printf(MSG_DEBUG, "P2P: Driver forced interface name %s", force_ifname); os_strlcpy(wpa_s->pending_interface_name, force_ifname, sizeof(wpa_s->pending_interface_name)); } else os_strlcpy(wpa_s->pending_interface_name, ifname, sizeof(wpa_s->pending_interface_name)); wpa_printf(MSG_DEBUG, "P2P: Created pending virtual interface %s addr " MACSTR, wpa_s->pending_interface_name, MAC2STR(wpa_s->pending_interface_addr)); return 0; } static void wpas_p2p_remove_pending_group_interface( struct wpa_supplicant *wpa_s) { if (!wpa_s->pending_interface_name[0] || is_zero_ether_addr(wpa_s->pending_interface_addr)) return; /* No pending virtual interface */ wpa_printf(MSG_DEBUG, "P2P: Removing pending group interface %s", wpa_s->pending_interface_name); wpa_drv_if_remove(wpa_s, wpa_s->pending_interface_type, wpa_s->pending_interface_name); os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN); wpa_s->pending_interface_name[0] = '\0'; } static struct wpa_supplicant * wpas_p2p_init_group_interface(struct wpa_supplicant *wpa_s, int go) { struct wpa_interface iface; struct wpa_supplicant *group_wpa_s; if (!wpa_s->pending_interface_name[0]) { wpa_printf(MSG_ERROR, "P2P: No pending group interface"); if (!wpas_p2p_create_iface(wpa_s)) return NULL; /* * Something has forced us to remove the pending interface; try * to create a new one and hope for the best that we will get * the same local address. */ if (wpas_p2p_add_group_interface(wpa_s, go ? WPA_IF_P2P_GO : WPA_IF_P2P_CLIENT) < 0) return NULL; } os_memset(&iface, 0, sizeof(iface)); iface.ifname = wpa_s->pending_interface_name; iface.driver = wpa_s->driver->name; if (wpa_s->conf->ctrl_interface == NULL && wpa_s->parent != wpa_s && wpa_s->p2p_mgmt && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) iface.ctrl_interface = wpa_s->parent->conf->ctrl_interface; else iface.ctrl_interface = wpa_s->conf->ctrl_interface; iface.driver_param = wpa_s->conf->driver_param; group_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface); if (group_wpa_s == NULL) { wpa_printf(MSG_ERROR, "P2P: Failed to create new " "wpa_supplicant interface"); return NULL; } wpa_s->pending_interface_name[0] = '\0'; group_wpa_s->parent = wpa_s; group_wpa_s->p2p_group_interface = go ? P2P_GROUP_INTERFACE_GO : P2P_GROUP_INTERFACE_CLIENT; wpa_s->global->p2p_group_formation = group_wpa_s; wpas_p2p_clone_config(group_wpa_s, wpa_s); return group_wpa_s; } static void wpas_p2p_group_formation_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out"); wpas_p2p_group_formation_failed(wpa_s); } void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s) { eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); if (wpa_s->global->p2p) p2p_group_formation_failed(wpa_s->global->p2p); wpas_group_formation_completed(wpa_s, 0); } static void wpas_p2p_grpform_fail_after_wps(struct wpa_supplicant *wpa_s) { wpa_printf(MSG_DEBUG, "P2P: Reject group formation due to WPS provisioning failure"); eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); wpa_s->global->p2p_fail_on_wps_complete = 0; } void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s) { if (wpa_s->global->p2p_group_formation != wpa_s) return; /* Speed up group formation timeout since this cannot succeed */ eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); } static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) { struct wpa_supplicant *wpa_s = ctx; if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) { wpa_drv_cancel_remain_on_channel(wpa_s); wpa_s->off_channel_freq = 0; wpa_s->roc_waiting_drv_freq = 0; } if (res->status) { wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_FAILURE "status=%d", res->status); wpas_notify_p2p_go_neg_completed(wpa_s, res); wpas_p2p_remove_pending_group_interface(wpa_s); return; } if (wpa_s->p2p_go_ht40) res->ht40 = 1; if (wpa_s->p2p_go_vht) res->vht = 1; wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS "role=%s " "freq=%d ht40=%d peer_dev=" MACSTR " peer_iface=" MACSTR " wps_method=%s", res->role_go ? "GO" : "client", res->freq, res->ht40, MAC2STR(res->peer_device_addr), MAC2STR(res->peer_interface_addr), p2p_wps_method_text(res->wps_method)); wpas_notify_p2p_go_neg_completed(wpa_s, res); if (res->role_go && wpa_s->p2p_persistent_id >= 0) { struct wpa_ssid *ssid; ssid = wpa_config_get_network(wpa_s->conf, wpa_s->p2p_persistent_id); if (ssid && ssid->disabled == 2 && ssid->mode == WPAS_MODE_P2P_GO && ssid->passphrase) { size_t len = os_strlen(ssid->passphrase); wpa_printf(MSG_DEBUG, "P2P: Override passphrase based " "on requested persistent group"); os_memcpy(res->passphrase, ssid->passphrase, len); res->passphrase[len] = '\0'; } } if (wpa_s->create_p2p_iface) { struct wpa_supplicant *group_wpa_s = wpas_p2p_init_group_interface(wpa_s, res->role_go); if (group_wpa_s == NULL) { wpas_p2p_remove_pending_group_interface(wpa_s); eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); wpas_p2p_group_formation_failed(wpa_s); return; } if (group_wpa_s != wpa_s) { os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin, sizeof(group_wpa_s->p2p_pin)); group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method; } os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN); wpa_s->pending_interface_name[0] = '\0'; group_wpa_s->p2p_in_provisioning = 1; if (res->role_go) wpas_start_wps_go(group_wpa_s, res, 1); else wpas_start_wps_enrollee(group_wpa_s, res); } else { wpa_s->p2p_in_provisioning = 1; wpa_s->global->p2p_group_formation = wpa_s; if (res->role_go) wpas_start_wps_go(wpa_s, res, 1); else wpas_start_wps_enrollee(ctx, res); } wpa_s->p2p_long_listen = 0; eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL); eloop_register_timeout(15 + res->peer_config_timeout / 100, (res->peer_config_timeout % 100) * 10000, wpas_p2p_group_formation_timeout, wpa_s, NULL); } static void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id) { struct wpa_supplicant *wpa_s = ctx; wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR " dev_passwd_id=%u", MAC2STR(src), dev_passwd_id); wpas_notify_p2p_go_neg_req(wpa_s, src, dev_passwd_id); } static void wpas_dev_found(void *ctx, const u8 *addr, const struct p2p_peer_info *info, int new_device) { #ifndef CONFIG_NO_STDOUT_DEBUG struct wpa_supplicant *wpa_s = ctx; char devtype[WPS_DEV_TYPE_BUFSIZE]; char *wfd_dev_info_hex = NULL; #ifdef CONFIG_WIFI_DISPLAY wfd_dev_info_hex = wifi_display_subelem_hex(info->wfd_subelems, WFD_SUBELEM_DEVICE_INFO); #endif /* CONFIG_WIFI_DISPLAY */ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR " p2p_dev_addr=" MACSTR " pri_dev_type=%s name='%s' config_methods=0x%x " "dev_capab=0x%x group_capab=0x%x%s%s", MAC2STR(addr), MAC2STR(info->p2p_device_addr), wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype)), info->device_name, info->config_methods, info->dev_capab, info->group_capab, wfd_dev_info_hex ? " wfd_dev_info=0x" : "", wfd_dev_info_hex ? wfd_dev_info_hex : ""); os_free(wfd_dev_info_hex); #endif /* CONFIG_NO_STDOUT_DEBUG */ wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device); } static void wpas_dev_lost(void *ctx, const u8 *dev_addr) { struct wpa_supplicant *wpa_s = ctx; wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_LOST "p2p_dev_addr=" MACSTR, MAC2STR(dev_addr)); wpas_notify_p2p_device_lost(wpa_s, dev_addr); } static void wpas_find_stopped(void *ctx) { struct wpa_supplicant *wpa_s = ctx; wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_FIND_STOPPED); } struct wpas_p2p_listen_work { unsigned int freq; unsigned int duration; struct wpabuf *probe_resp_ie; }; static void wpas_p2p_listen_work_free(struct wpas_p2p_listen_work *lwork) { if (lwork == NULL) return; wpabuf_free(lwork->probe_resp_ie); os_free(lwork); } static void wpas_p2p_listen_work_done(struct wpa_supplicant *wpa_s) { struct wpas_p2p_listen_work *lwork; if (!wpa_s->p2p_listen_work) return; lwork = wpa_s->p2p_listen_work->ctx; wpas_p2p_listen_work_free(lwork); radio_work_done(wpa_s->p2p_listen_work); wpa_s->p2p_listen_work = NULL; } static void wpas_start_listen_cb(struct wpa_radio_work *work, int deinit) { struct wpa_supplicant *wpa_s = work->wpa_s; struct wpas_p2p_listen_work *lwork = work->ctx; if (deinit) { if (work->started) { wpa_s->p2p_listen_work = NULL; wpas_stop_listen(wpa_s); } wpas_p2p_listen_work_free(lwork); return; } wpa_s->p2p_listen_work = work; wpa_drv_set_ap_wps_ie(wpa_s, NULL, lwork->probe_resp_ie, NULL); if (wpa_drv_probe_req_report(wpa_s, 1) < 0) { wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to " "report received Probe Request frames"); wpas_p2p_listen_work_done(wpa_s); return; } wpa_s->pending_listen_freq = lwork->freq; wpa_s->pending_listen_duration = lwork->duration; if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, lwork->duration) < 0) { wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver " "to remain on channel (%u MHz) for Listen " "state", lwork->freq); wpas_p2p_listen_work_done(wpa_s); wpa_s->pending_listen_freq = 0; return; } wpa_s->off_channel_freq = 0; wpa_s->roc_waiting_drv_freq = lwork->freq; } static int wpas_start_listen(void *ctx, unsigned int freq, unsigned int duration, const struct wpabuf *probe_resp_ie) { struct wpa_supplicant *wpa_s = ctx; struct wpas_p2p_listen_work *lwork; if (wpa_s->p2p_listen_work) { wpa_printf(MSG_DEBUG, "P2P: Reject start_listen since p2p_listen_work already exists"); return -1; } lwork = os_zalloc(sizeof(*lwork)); if (lwork == NULL) return -1; lwork->freq = freq; lwork->duration = duration; if (probe_resp_ie) { lwork->probe_resp_ie = wpabuf_dup(probe_resp_ie); if (lwork->probe_resp_ie == NULL) { wpas_p2p_listen_work_free(lwork); return -1; } } if (radio_add_work(wpa_s, freq, "p2p-listen", 0, wpas_start_listen_cb, lwork) < 0) { wpas_p2p_listen_work_free(lwork); return -1; } return 0; } static void wpas_stop_listen(void *ctx) { struct wpa_supplicant *wpa_s = ctx; if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) { wpa_drv_cancel_remain_on_channel(wpa_s); wpa_s->off_channel_freq = 0; wpa_s->roc_waiting_drv_freq = 0; } wpa_drv_set_ap_wps_ie(wpa_s, NULL, NULL, NULL); wpa_drv_probe_req_report(wpa_s, 0); wpas_p2p_listen_work_done(wpa_s); } static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf) { struct wpa_supplicant *wpa_s = ctx; return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1); } /* * DNS Header section is used only to calculate compression pointers, so the * contents of this data does not matter, but the length needs to be reserved * in the virtual packet. */ #define DNS_HEADER_LEN 12 /* * 27-octet in-memory packet from P2P specification containing two implied * queries for _tcp.lcoal. PTR IN and _udp.local. PTR IN */ #define P2P_SD_IN_MEMORY_LEN 27 static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start, u8 **spos, const u8 *end) { while (*spos < end) { u8 val = ((*spos)[0] & 0xc0) >> 6; int len; if (val == 1 || val == 2) { /* These are reserved values in RFC 1035 */ wpa_printf(MSG_DEBUG, "P2P: Invalid domain name " "sequence starting with 0x%x", val); return -1; } if (val == 3) { u16 offset; u8 *spos_tmp; /* Offset */ if (*spos + 2 > end) { wpa_printf(MSG_DEBUG, "P2P: No room for full " "DNS offset field"); return -1; } offset = (((*spos)[0] & 0x3f) << 8) | (*spos)[1]; if (offset >= *spos - start) { wpa_printf(MSG_DEBUG, "P2P: Invalid DNS " "pointer offset %u", offset); return -1; } (*spos) += 2; spos_tmp = start + offset; return p2p_sd_dns_uncompress_label(upos, uend, start, &spos_tmp, *spos - 2); } /* Label */ len = (*spos)[0] & 0x3f; if (len == 0) return 0; (*spos)++; if (*spos + len > end) { wpa_printf(MSG_DEBUG, "P2P: Invalid domain name " "sequence - no room for label with length " "%u", len); return -1; } if (*upos + len + 2 > uend) return -2; os_memcpy(*upos, *spos, len); *spos += len; *upos += len; (*upos)[0] = '.'; (*upos)++; (*upos)[0] = '\0'; } return 0; } /* Uncompress domain names per RFC 1035 using the P2P SD in-memory packet. * Returns -1 on parsing error (invalid input sequence), -2 if output buffer is * not large enough */ static int p2p_sd_dns_uncompress(char *buf, size_t buf_len, const u8 *msg, size_t msg_len, size_t offset) { /* 27-octet in-memory packet from P2P specification */ const char *prefix = "\x04_tcp\x05local\x00\x00\x0C\x00\x01" "\x04_udp\xC0\x11\x00\x0C\x00\x01"; u8 *tmp, *end, *spos; char *upos, *uend; int ret = 0; if (buf_len < 2) return -1; if (offset > msg_len) return -1; tmp = os_malloc(DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN + msg_len); if (tmp == NULL) return -1; spos = tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN; end = spos + msg_len; spos += offset; os_memset(tmp, 0, DNS_HEADER_LEN); os_memcpy(tmp + DNS_HEADER_LEN, prefix, P2P_SD_IN_MEMORY_LEN); os_memcpy(tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN, msg, msg_len); upos = buf; uend = buf + buf_len; ret = p2p_sd_dns_uncompress_label(&upos, uend, tmp, &spos, end); if (ret) { os_free(tmp); return ret; } if (upos == buf) { upos[0] = '.'; upos[1] = '\0'; } else if (upos[-1] == '.') upos[-1] = '\0'; os_free(tmp); return 0; } static struct p2p_srv_bonjour * wpas_p2p_service_get_bonjour(struct wpa_supplicant *wpa_s, const struct wpabuf *query) { struct p2p_srv_bonjour *bsrv; size_t len; len = wpabuf_len(query); dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour, struct p2p_srv_bonjour, list) { if (len == wpabuf_len(bsrv->query) && os_memcmp(wpabuf_head(query), wpabuf_head(bsrv->query), len) == 0) return bsrv; } return NULL; } static struct p2p_srv_upnp * wpas_p2p_service_get_upnp(struct wpa_supplicant *wpa_s, u8 version, const char *service) { struct p2p_srv_upnp *usrv; dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp, struct p2p_srv_upnp, list) { if (version == usrv->version && os_strcmp(service, usrv->service) == 0) return usrv; } return NULL; } static void wpas_sd_add_proto_not_avail(struct wpabuf *resp, u8 srv_proto, u8 srv_trans_id) { u8 *len_pos; if (wpabuf_tailroom(resp) < 5) return; /* Length (to be filled) */ len_pos = wpabuf_put(resp, 2); wpabuf_put_u8(resp, srv_proto); wpabuf_put_u8(resp, srv_trans_id); /* Status Code */ wpabuf_put_u8(resp, P2P_SD_PROTO_NOT_AVAILABLE); /* Response Data: empty */ WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2); } static void wpas_sd_all_bonjour(struct wpa_supplicant *wpa_s, struct wpabuf *resp, u8 srv_trans_id) { struct p2p_srv_bonjour *bsrv; u8 *len_pos; wpa_printf(MSG_DEBUG, "P2P: SD Request for all Bonjour services"); if (dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) { wpa_printf(MSG_DEBUG, "P2P: Bonjour protocol not available"); return; } dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour, struct p2p_srv_bonjour, list) { if (wpabuf_tailroom(resp) < 5 + wpabuf_len(bsrv->query) + wpabuf_len(bsrv->resp)) return; /* Length (to be filled) */ len_pos = wpabuf_put(resp, 2); wpabuf_put_u8(resp, P2P_SERV_BONJOUR); wpabuf_put_u8(resp, srv_trans_id); /* Status Code */ wpabuf_put_u8(resp, P2P_SD_SUCCESS); wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service", wpabuf_head(bsrv->resp), wpabuf_len(bsrv->resp)); /* Response Data */ wpabuf_put_buf(resp, bsrv->query); /* Key */ wpabuf_put_buf(resp, bsrv->resp); /* Value */ WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2); } } static int match_bonjour_query(struct p2p_srv_bonjour *bsrv, const u8 *query, size_t query_len) { char str_rx[256], str_srv[256]; if (query_len < 3 || wpabuf_len(bsrv->query) < 3) return 0; /* Too short to include DNS Type and Version */ if (os_memcmp(query + query_len - 3, wpabuf_head_u8(bsrv->query) + wpabuf_len(bsrv->query) - 3, 3) != 0) return 0; /* Mismatch in DNS Type or Version */ if (query_len == wpabuf_len(bsrv->query) && os_memcmp(query, wpabuf_head(bsrv->query), query_len - 3) == 0) return 1; /* Binary match */ if (p2p_sd_dns_uncompress(str_rx, sizeof(str_rx), query, query_len - 3, 0)) return 0; /* Failed to uncompress query */ if (p2p_sd_dns_uncompress(str_srv, sizeof(str_srv), wpabuf_head(bsrv->query), wpabuf_len(bsrv->query) - 3, 0)) return 0; /* Failed to uncompress service */ return os_strcmp(str_rx, str_srv) == 0; } static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s, struct wpabuf *resp, u8 srv_trans_id, const u8 *query, size_t query_len) { struct p2p_srv_bonjour *bsrv; u8 *len_pos; int matches = 0; wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for Bonjour", query, query_len); if (dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) { wpa_printf(MSG_DEBUG, "P2P: Bonjour protocol not available"); wpas_sd_add_proto_not_avail(resp, P2P_SERV_BONJOUR, srv_trans_id); return; } if (query_len == 0) { wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id); return; } dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour, struct p2p_srv_bonjour, list) { if (!match_bonjour_query(bsrv, query, query_len)) continue; if (wpabuf_tailroom(resp) < 5 + query_len + wpabuf_len(bsrv->resp)) return; matches++; /* Length (to be filled) */ len_pos = wpabuf_put(resp, 2); wpabuf_put_u8(resp, P2P_SERV_BONJOUR); wpabuf_put_u8(resp, srv_trans_id); /* Status Code */ wpabuf_put_u8(resp, P2P_SD_SUCCESS); wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service", wpabuf_head(bsrv->resp), wpabuf_len(bsrv->resp)); /* Response Data */ wpabuf_put_data(resp, query, query_len); /* Key */ wpabuf_put_buf(resp, bsrv->resp); /* Value */ WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2); } if (matches == 0) { wpa_printf(MSG_DEBUG, "P2P: Requested Bonjour service not " "available"); if (wpabuf_tailroom(resp) < 5) return; /* Length (to be filled) */ len_pos = wpabuf_put(resp, 2); wpabuf_put_u8(resp, P2P_SERV_BONJOUR); wpabuf_put_u8(resp, srv_trans_id); /* Status Code */ wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE); /* Response Data: empty */ WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2); } } static void wpas_sd_all_upnp(struct wpa_supplicant *wpa_s, struct wpabuf *resp, u8 srv_trans_id) { struct p2p_srv_upnp *usrv; u8 *len_pos; wpa_printf(MSG_DEBUG, "P2P: SD Request for all UPnP services"); if (dl_list_empty(&wpa_s->global->p2p_srv_upnp)) { wpa_printf(MSG_DEBUG, "P2P: UPnP protocol not available"); return; } dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp, struct p2p_srv_upnp, list) { if (wpabuf_tailroom(resp) < 5 + 1 + os_strlen(usrv->service)) return; /* Length (to be filled) */ len_pos = wpabuf_put(resp, 2); wpabuf_put_u8(resp, P2P_SERV_UPNP); wpabuf_put_u8(resp, srv_trans_id); /* Status Code */ wpabuf_put_u8(resp, P2P_SD_SUCCESS); /* Response Data */ wpabuf_put_u8(resp, usrv->version); wpa_printf(MSG_DEBUG, "P2P: Matching UPnP Service: %s", usrv->service); wpabuf_put_str(resp, usrv->service); WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2); } } static void wpas_sd_req_upnp(struct wpa_supplicant *wpa_s, struct wpabuf *resp, u8 srv_trans_id, const u8 *query, size_t query_len) { struct p2p_srv_upnp *usrv; u8 *len_pos; u8 version; char *str; int count = 0; wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for UPnP", query, query_len); if (dl_list_empty(&wpa_s->global->p2p_srv_upnp)) { wpa_printf(MSG_DEBUG, "P2P: UPnP protocol not available"); wpas_sd_add_proto_not_avail(resp, P2P_SERV_UPNP, srv_trans_id); return; } if (query_len == 0) { wpas_sd_all_upnp(wpa_s, resp, srv_trans_id); return; } if (wpabuf_tailroom(resp) < 5) return; /* Length (to be filled) */ len_pos = wpabuf_put(resp, 2); wpabuf_put_u8(resp, P2P_SERV_UPNP); wpabuf_put_u8(resp, srv_trans_id); version = query[0]; str = os_malloc(query_len); if (str == NULL) return; os_memcpy(str, query + 1, query_len - 1); str[query_len - 1] = '\0'; dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp, struct p2p_srv_upnp, list) { if (version != usrv->version) continue; if (os_strcmp(str, "ssdp:all") != 0 && os_strstr(usrv->service, str) == NULL) continue; if (wpabuf_tailroom(resp) < 2) break; if (count == 0) { /* Status Code */ wpabuf_put_u8(resp, P2P_SD_SUCCESS); /* Response Data */ wpabuf_put_u8(resp, version); } else wpabuf_put_u8(resp, ','); count++; wpa_printf(MSG_DEBUG, "P2P: Matching UPnP Service: %s", usrv->service); if (wpabuf_tailroom(resp) < os_strlen(usrv->service)) break; wpabuf_put_str(resp, usrv->service); } os_free(str); if (count == 0) { wpa_printf(MSG_DEBUG, "P2P: Requested UPnP service not " "available"); /* Status Code */ wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE); /* Response Data: empty */ } WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2); } #ifdef CONFIG_WIFI_DISPLAY static void wpas_sd_req_wfd(struct wpa_supplicant *wpa_s, struct wpabuf *resp, u8 srv_trans_id, const u8 *query, size_t query_len) { const u8 *pos; u8 role; u8 *len_pos; wpa_hexdump(MSG_DEBUG, "P2P: SD Request for WFD", query, query_len); if (!wpa_s->global->wifi_display) { wpa_printf(MSG_DEBUG, "P2P: WFD protocol not available"); wpas_sd_add_proto_not_avail(resp, P2P_SERV_WIFI_DISPLAY, srv_trans_id); return; } if (query_len < 1) { wpa_printf(MSG_DEBUG, "P2P: Missing WFD Requested Device " "Role"); return; } if (wpabuf_tailroom(resp) < 5) return; pos = query; role = *pos++; wpa_printf(MSG_DEBUG, "P2P: WSD for device role 0x%x", role); /* TODO: role specific handling */ /* Length (to be filled) */ len_pos = wpabuf_put(resp, 2); wpabuf_put_u8(resp, P2P_SERV_WIFI_DISPLAY); wpabuf_put_u8(resp, srv_trans_id); wpabuf_put_u8(resp, P2P_SD_SUCCESS); /* Status Code */ while (pos < query + query_len) { if (*pos < MAX_WFD_SUBELEMS && wpa_s->global->wfd_subelem[*pos] && wpabuf_tailroom(resp) >= wpabuf_len(wpa_s->global->wfd_subelem[*pos])) { wpa_printf(MSG_DEBUG, "P2P: Add WSD response " "subelement %u", *pos); wpabuf_put_buf(resp, wpa_s->global->wfd_subelem[*pos]); } pos++; } WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2); } #endif /* CONFIG_WIFI_DISPLAY */ static void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token, u16 update_indic, const u8 *tlvs, size_t tlvs_len) { struct wpa_supplicant *wpa_s = ctx; const u8 *pos = tlvs; const u8 *end = tlvs + tlvs_len; const u8 *tlv_end; u16 slen; struct wpabuf *resp; u8 srv_proto, srv_trans_id; size_t buf_len; char *buf; wpa_hexdump(MSG_MSGDUMP, "P2P: Service Discovery Request TLVs", tlvs, tlvs_len); buf_len = 2 * tlvs_len + 1; buf = os_malloc(buf_len); if (buf) { wpa_snprintf_hex(buf, buf_len, tlvs, tlvs_len); wpa_msg_ctrl(wpa_s, MSG_INFO, P2P_EVENT_SERV_DISC_REQ "%d " MACSTR " %u %u %s", freq, MAC2STR(sa), dialog_token, update_indic, buf); os_free(buf); } if (wpa_s->p2p_sd_over_ctrl_iface) { wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token, update_indic, tlvs, tlvs_len); return; /* to be processed by an external program */ } resp = wpabuf_alloc(10000); if (resp == NULL) return; while (pos + 1 < end) { wpa_printf(MSG_DEBUG, "P2P: Service Request TLV"); slen = WPA_GET_LE16(pos); pos += 2; if (pos + slen > end || slen < 2) { wpa_printf(MSG_DEBUG, "P2P: Unexpected Query Data " "length"); wpabuf_free(resp); return; } tlv_end = pos + slen; srv_proto = *pos++; wpa_printf(MSG_DEBUG, "P2P: Service Protocol Type %u", srv_proto); srv_trans_id = *pos++; wpa_printf(MSG_DEBUG, "P2P: Service Transaction ID %u", srv_trans_id); wpa_hexdump(MSG_MSGDUMP, "P2P: Query Data", pos, tlv_end - pos); if (wpa_s->force_long_sd) { wpa_printf(MSG_DEBUG, "P2P: SD test - force long " "response"); wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id); wpas_sd_all_upnp(wpa_s, resp, srv_trans_id); goto done; } switch (srv_proto) { case P2P_SERV_ALL_SERVICES: wpa_printf(MSG_DEBUG, "P2P: Service Discovery Request " "for all services"); if (dl_list_empty(&wpa_s->global->p2p_srv_upnp) && dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) { wpa_printf(MSG_DEBUG, "P2P: No service " "discovery protocols available"); wpas_sd_add_proto_not_avail( resp, P2P_SERV_ALL_SERVICES, srv_trans_id); break; } wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id); wpas_sd_all_upnp(wpa_s, resp, srv_trans_id); break; case P2P_SERV_BONJOUR: wpas_sd_req_bonjour(wpa_s, resp, srv_trans_id, pos, tlv_end - pos); break; case P2P_SERV_UPNP: wpas_sd_req_upnp(wpa_s, resp, srv_trans_id, pos, tlv_end - pos); break; #ifdef CONFIG_WIFI_DISPLAY case P2P_SERV_WIFI_DISPLAY: wpas_sd_req_wfd(wpa_s, resp, srv_trans_id, pos, tlv_end - pos); break; #endif /* CONFIG_WIFI_DISPLAY */ default: wpa_printf(MSG_DEBUG, "P2P: Unavailable service " "protocol %u", srv_proto); wpas_sd_add_proto_not_avail(resp, srv_proto, srv_trans_id); break; } pos = tlv_end; } done: wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token, update_indic, tlvs, tlvs_len); wpas_p2p_sd_response(wpa_s, freq, sa, dialog_token, resp); wpabuf_free(resp); } static void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic, const u8 *tlvs, size_t tlvs_len) { struct wpa_supplicant *wpa_s = ctx; const u8 *pos = tlvs; const u8 *end = tlvs + tlvs_len; const u8 *tlv_end; u16 slen; size_t buf_len; char *buf; wpa_hexdump(MSG_MSGDUMP, "P2P: Service Discovery Response TLVs", tlvs, tlvs_len); if (tlvs_len > 1500) { /* TODO: better way for handling this */ wpa_msg_ctrl(wpa_s, MSG_INFO, P2P_EVENT_SERV_DISC_RESP MACSTR " %u ", MAC2STR(sa), update_indic, (unsigned int) tlvs_len); } else { buf_len = 2 * tlvs_len + 1; buf = os_malloc(buf_len); if (buf) { wpa_snprintf_hex(buf, buf_len, tlvs, tlvs_len); wpa_msg_ctrl(wpa_s, MSG_INFO, P2P_EVENT_SERV_DISC_RESP MACSTR " %u %s", MAC2STR(sa), update_indic, buf); os_free(buf); } } while (pos < end) { u8 srv_proto, srv_trans_id, status; wpa_printf(MSG_DEBUG, "P2P: Service Response TLV"); slen = WPA_GET_LE16(pos); pos += 2; if (pos + slen > end || slen < 3) { wpa_printf(MSG_DEBUG, "P2P: Unexpected Response Data " "length"); return; } tlv_end = pos + slen; srv_proto = *pos++; wpa_printf(MSG_DEBUG, "P2P: Service Protocol Type %u", srv_proto); srv_trans_id = *pos++; wpa_printf(MSG_DEBUG, "P2P: Service Transaction ID %u", srv_trans_id); status = *pos++; wpa_printf(MSG_DEBUG, "P2P: Status Code ID %u", status); wpa_hexdump(MSG_MSGDUMP, "P2P: Response Data", pos, tlv_end - pos); pos = tlv_end; } wpas_notify_p2p_sd_response(wpa_s, sa, update_indic, tlvs, tlvs_len); } u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *tlvs) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return 0; return (uintptr_t) p2p_sd_request(wpa_s->global->p2p, dst, tlvs); } u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst, u8 version, const char *query) { struct wpabuf *tlvs; u64 ret; tlvs = wpabuf_alloc(2 + 1 + 1 + 1 + os_strlen(query)); if (tlvs == NULL) return 0; wpabuf_put_le16(tlvs, 1 + 1 + 1 + os_strlen(query)); wpabuf_put_u8(tlvs, P2P_SERV_UPNP); /* Service Protocol Type */ wpabuf_put_u8(tlvs, 1); /* Service Transaction ID */ wpabuf_put_u8(tlvs, version); wpabuf_put_str(tlvs, query); ret = wpas_p2p_sd_request(wpa_s, dst, tlvs); wpabuf_free(tlvs); return ret; } #ifdef CONFIG_WIFI_DISPLAY static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *tlvs) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return 0; return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs); } #define MAX_WFD_SD_SUBELEMS 20 static void wfd_add_sd_req_role(struct wpabuf *tlvs, u8 id, u8 role, const char *subelems) { u8 *len; const char *pos; int val; int count = 0; len = wpabuf_put(tlvs, 2); wpabuf_put_u8(tlvs, P2P_SERV_WIFI_DISPLAY); /* Service Protocol Type */ wpabuf_put_u8(tlvs, id); /* Service Transaction ID */ wpabuf_put_u8(tlvs, role); pos = subelems; while (*pos) { val = atoi(pos); if (val >= 0 && val < 256) { wpabuf_put_u8(tlvs, val); count++; if (count == MAX_WFD_SD_SUBELEMS) break; } pos = os_strchr(pos + 1, ','); if (pos == NULL) break; pos++; } WPA_PUT_LE16(len, (u8 *) wpabuf_put(tlvs, 0) - len - 2); } u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s, const u8 *dst, const char *role) { struct wpabuf *tlvs; u64 ret; const char *subelems; u8 id = 1; subelems = os_strchr(role, ' '); if (subelems == NULL) return 0; subelems++; tlvs = wpabuf_alloc(4 * (2 + 1 + 1 + 1 + MAX_WFD_SD_SUBELEMS)); if (tlvs == NULL) return 0; if (os_strstr(role, "[source]")) wfd_add_sd_req_role(tlvs, id++, 0x00, subelems); if (os_strstr(role, "[pri-sink]")) wfd_add_sd_req_role(tlvs, id++, 0x01, subelems); if (os_strstr(role, "[sec-sink]")) wfd_add_sd_req_role(tlvs, id++, 0x02, subelems); if (os_strstr(role, "[source+sink]")) wfd_add_sd_req_role(tlvs, id++, 0x03, subelems); ret = wpas_p2p_sd_request_wfd(wpa_s, dst, tlvs); wpabuf_free(tlvs); return ret; } #endif /* CONFIG_WIFI_DISPLAY */ int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; return p2p_sd_cancel_request(wpa_s->global->p2p, (void *) (uintptr_t) req); } void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq, const u8 *dst, u8 dialog_token, const struct wpabuf *resp_tlvs) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token, resp_tlvs); } void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s) { if (wpa_s->global->p2p) p2p_sd_service_update(wpa_s->global->p2p); } static void wpas_p2p_srv_bonjour_free(struct p2p_srv_bonjour *bsrv) { dl_list_del(&bsrv->list); wpabuf_free(bsrv->query); wpabuf_free(bsrv->resp); os_free(bsrv); } static void wpas_p2p_srv_upnp_free(struct p2p_srv_upnp *usrv) { dl_list_del(&usrv->list); os_free(usrv->service); os_free(usrv); } void wpas_p2p_service_flush(struct wpa_supplicant *wpa_s) { struct p2p_srv_bonjour *bsrv, *bn; struct p2p_srv_upnp *usrv, *un; dl_list_for_each_safe(bsrv, bn, &wpa_s->global->p2p_srv_bonjour, struct p2p_srv_bonjour, list) wpas_p2p_srv_bonjour_free(bsrv); dl_list_for_each_safe(usrv, un, &wpa_s->global->p2p_srv_upnp, struct p2p_srv_upnp, list) wpas_p2p_srv_upnp_free(usrv); wpas_p2p_sd_service_update(wpa_s); } int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s, struct wpabuf *query, struct wpabuf *resp) { struct p2p_srv_bonjour *bsrv; bsrv = os_zalloc(sizeof(*bsrv)); if (bsrv == NULL) return -1; bsrv->query = query; bsrv->resp = resp; dl_list_add(&wpa_s->global->p2p_srv_bonjour, &bsrv->list); wpas_p2p_sd_service_update(wpa_s); return 0; } int wpas_p2p_service_del_bonjour(struct wpa_supplicant *wpa_s, const struct wpabuf *query) { struct p2p_srv_bonjour *bsrv; bsrv = wpas_p2p_service_get_bonjour(wpa_s, query); if (bsrv == NULL) return -1; wpas_p2p_srv_bonjour_free(bsrv); wpas_p2p_sd_service_update(wpa_s); return 0; } int wpas_p2p_service_add_upnp(struct wpa_supplicant *wpa_s, u8 version, const char *service) { struct p2p_srv_upnp *usrv; if (wpas_p2p_service_get_upnp(wpa_s, version, service)) return 0; /* Already listed */ usrv = os_zalloc(sizeof(*usrv)); if (usrv == NULL) return -1; usrv->version = version; usrv->service = os_strdup(service); if (usrv->service == NULL) { os_free(usrv); return -1; } dl_list_add(&wpa_s->global->p2p_srv_upnp, &usrv->list); wpas_p2p_sd_service_update(wpa_s); return 0; } int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version, const char *service) { struct p2p_srv_upnp *usrv; usrv = wpas_p2p_service_get_upnp(wpa_s, version, service); if (usrv == NULL) return -1; wpas_p2p_srv_upnp_free(usrv); wpas_p2p_sd_service_update(wpa_s); return 0; } static void wpas_prov_disc_local_display(struct wpa_supplicant *wpa_s, const u8 *peer, const char *params, unsigned int generated_pin) { wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_SHOW_PIN MACSTR " %08d%s", MAC2STR(peer), generated_pin, params); } static void wpas_prov_disc_local_keypad(struct wpa_supplicant *wpa_s, const u8 *peer, const char *params) { wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_ENTER_PIN MACSTR "%s", MAC2STR(peer), params); } static void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, const u8 *dev_addr, const u8 *pri_dev_type, const char *dev_name, u16 supp_config_methods, u8 dev_capab, u8 group_capab, const u8 *group_id, size_t group_id_len) { struct wpa_supplicant *wpa_s = ctx; char devtype[WPS_DEV_TYPE_BUFSIZE]; char params[300]; u8 empty_dev_type[8]; unsigned int generated_pin = 0; struct wpa_supplicant *group = NULL; if (group_id) { for (group = wpa_s->global->ifaces; group; group = group->next) { struct wpa_ssid *s = group->current_ssid; if (s != NULL && s->mode == WPAS_MODE_P2P_GO && group_id_len - ETH_ALEN == s->ssid_len && os_memcmp(group_id + ETH_ALEN, s->ssid, s->ssid_len) == 0) break; } } if (pri_dev_type == NULL) { os_memset(empty_dev_type, 0, sizeof(empty_dev_type)); pri_dev_type = empty_dev_type; } os_snprintf(params, sizeof(params), " p2p_dev_addr=" MACSTR " pri_dev_type=%s name='%s' config_methods=0x%x " "dev_capab=0x%x group_capab=0x%x%s%s", MAC2STR(dev_addr), wps_dev_type_bin2str(pri_dev_type, devtype, sizeof(devtype)), dev_name, supp_config_methods, dev_capab, group_capab, group ? " group=" : "", group ? group->ifname : ""); params[sizeof(params) - 1] = '\0'; if (config_methods & WPS_CONFIG_DISPLAY) { generated_pin = wps_generate_pin(); wpas_prov_disc_local_display(wpa_s, peer, params, generated_pin); } else if (config_methods & WPS_CONFIG_KEYPAD) wpas_prov_disc_local_keypad(wpa_s, peer, params); else if (config_methods & WPS_CONFIG_PUSHBUTTON) wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_REQ MACSTR "%s", MAC2STR(peer), params); wpas_notify_p2p_provision_discovery(wpa_s, peer, 1 /* request */, P2P_PROV_DISC_SUCCESS, config_methods, generated_pin); } static void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) { struct wpa_supplicant *wpa_s = ctx; unsigned int generated_pin = 0; char params[20]; if (wpa_s->pending_pd_before_join && (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 || os_memcmp(peer, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) { wpa_s->pending_pd_before_join = 0; wpa_printf(MSG_DEBUG, "P2P: Starting pending " "join-existing-group operation"); wpas_p2p_join_start(wpa_s, 0, NULL, 0); return; } if (wpa_s->pending_pd_use == AUTO_PD_JOIN || wpa_s->pending_pd_use == AUTO_PD_GO_NEG) os_snprintf(params, sizeof(params), " peer_go=%d", wpa_s->pending_pd_use == AUTO_PD_JOIN); else params[0] = '\0'; if (config_methods & WPS_CONFIG_DISPLAY) wpas_prov_disc_local_keypad(wpa_s, peer, params); else if (config_methods & WPS_CONFIG_KEYPAD) { generated_pin = wps_generate_pin(); wpas_prov_disc_local_display(wpa_s, peer, params, generated_pin); } else if (config_methods & WPS_CONFIG_PUSHBUTTON) wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR "%s", MAC2STR(peer), params); wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */, P2P_PROV_DISC_SUCCESS, config_methods, generated_pin); } static void wpas_prov_disc_fail(void *ctx, const u8 *peer, enum p2p_prov_disc_status status) { struct wpa_supplicant *wpa_s = ctx; if (wpa_s->p2p_fallback_to_go_neg) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: PD for p2p_connect-auto " "failed - fall back to GO Negotiation"); wpas_p2p_fallback_to_go_neg(wpa_s, 0); return; } if (status == P2P_PROV_DISC_TIMEOUT_JOIN) { wpa_s->pending_pd_before_join = 0; wpa_printf(MSG_DEBUG, "P2P: Starting pending " "join-existing-group operation (no ACK for PD " "Req attempts)"); wpas_p2p_join_start(wpa_s, 0, NULL, 0); return; } wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE " p2p_dev_addr=" MACSTR " status=%d", MAC2STR(peer), status); wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */, status, 0, 0); } static int freq_included(const struct p2p_channels *channels, unsigned int freq) { if (channels == NULL) return 1; /* Assume no restrictions */ return p2p_channels_includes_freq(channels, freq); } static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid, const u8 *go_dev_addr, const u8 *ssid, size_t ssid_len, int *go, u8 *group_bssid, int *force_freq, int persistent_group, const struct p2p_channels *channels, int dev_pw_id) { struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *s; int res; struct wpa_supplicant *grp; if (!persistent_group) { wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR " to join an active group (SSID: %s)", MAC2STR(sa), wpa_ssid_txt(ssid, ssid_len)); if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) && (os_memcmp(go_dev_addr, wpa_s->p2p_auth_invite, ETH_ALEN) == 0 || os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0)) { wpa_printf(MSG_DEBUG, "P2P: Accept previously " "authorized invitation"); goto accept_inv; } #ifdef CONFIG_WPS_NFC if (dev_pw_id >= 0 && wpa_s->parent->p2p_nfc_tag_enabled && dev_pw_id == wpa_s->parent->p2p_oob_dev_pw_id) { wpa_printf(MSG_DEBUG, "P2P: Accept invitation based on local enabled NFC Tag"); wpa_s->parent->p2p_wps_method = WPS_NFC; wpa_s->parent->pending_join_wps_method = WPS_NFC; os_memcpy(wpa_s->parent->pending_join_dev_addr, go_dev_addr, ETH_ALEN); os_memcpy(wpa_s->parent->pending_join_iface_addr, bssid, ETH_ALEN); goto accept_inv; } #endif /* CONFIG_WPS_NFC */ /* * Do not accept the invitation automatically; notify user and * request approval. */ return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; } grp = wpas_get_p2p_group(wpa_s, ssid, ssid_len, go); if (grp) { wpa_printf(MSG_DEBUG, "P2P: Accept invitation to already " "running persistent group"); if (*go) os_memcpy(group_bssid, grp->own_addr, ETH_ALEN); goto accept_inv; } if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) && os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0) { wpa_printf(MSG_DEBUG, "P2P: Accept previously initiated " "invitation to re-invoke a persistent group"); os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); } else if (!wpa_s->conf->persistent_reconnect) return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; for (s = wpa_s->conf->ssid; s; s = s->next) { if (s->disabled == 2 && os_memcmp(s->bssid, go_dev_addr, ETH_ALEN) == 0 && s->ssid_len == ssid_len && os_memcmp(ssid, s->ssid, ssid_len) == 0) break; } if (!s) { wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR " requested reinvocation of an unknown group", MAC2STR(sa)); return P2P_SC_FAIL_UNKNOWN_GROUP; } if (s->mode == WPAS_MODE_P2P_GO && !wpas_p2p_create_iface(wpa_s)) { *go = 1; if (wpa_s->wpa_state >= WPA_AUTHENTICATING) { wpa_printf(MSG_DEBUG, "P2P: The only available " "interface is already in use - reject " "invitation"); return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; } os_memcpy(group_bssid, wpa_s->own_addr, ETH_ALEN); } else if (s->mode == WPAS_MODE_P2P_GO) { *go = 1; if (wpas_p2p_add_group_interface(wpa_s, WPA_IF_P2P_GO) < 0) { wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new " "interface address for the group"); return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; } os_memcpy(group_bssid, wpa_s->pending_interface_addr, ETH_ALEN); } accept_inv: wpas_p2p_set_own_freq_preference(wpa_s, 0); /* Get one of the frequencies currently in use */ if (wpas_p2p_valid_oper_freqs(wpa_s, &res, 1) > 0) { wpa_printf(MSG_DEBUG, "P2P: Trying to prefer a channel already used by one of the interfaces"); wpas_p2p_set_own_freq_preference(wpa_s, res); if (wpa_s->num_multichan_concurrent < 2 || wpas_p2p_num_unused_channels(wpa_s) < 1) { wpa_printf(MSG_DEBUG, "P2P: No extra channels available - trying to force channel to match a channel already used by one of the interfaces"); *force_freq = res; } } if (*force_freq > 0 && wpa_s->num_multichan_concurrent > 1 && wpas_p2p_num_unused_channels(wpa_s) > 0) { if (*go == 0) { /* We are the client */ wpa_printf(MSG_DEBUG, "P2P: Peer was found to be " "running a GO but we are capable of MCC, " "figure out the best channel to use"); *force_freq = 0; } else if (!freq_included(channels, *force_freq)) { /* We are the GO, and *force_freq is not in the * intersection */ wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not " "in intersection but we are capable of MCC, " "figure out the best channel to use", *force_freq); *force_freq = 0; } } return P2P_SC_SUCCESS; } static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid, const u8 *ssid, size_t ssid_len, const u8 *go_dev_addr, u8 status, int op_freq) { struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *s; for (s = wpa_s->conf->ssid; s; s = s->next) { if (s->disabled == 2 && s->ssid_len == ssid_len && os_memcmp(ssid, s->ssid, ssid_len) == 0) break; } if (status == P2P_SC_SUCCESS) { wpa_printf(MSG_DEBUG, "P2P: Invitation from peer " MACSTR " was accepted; op_freq=%d MHz, SSID=%s", MAC2STR(sa), op_freq, wpa_ssid_txt(ssid, ssid_len)); if (s) { int go = s->mode == WPAS_MODE_P2P_GO; wpas_p2p_group_add_persistent( wpa_s, s, go, 0, op_freq, 0, 0, NULL, go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0); } else if (bssid) { wpa_s->user_initiated_pd = 0; wpas_p2p_join(wpa_s, bssid, go_dev_addr, wpa_s->p2p_wps_method, 0, op_freq, ssid, ssid_len); } return; } if (status != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { wpa_printf(MSG_DEBUG, "P2P: Invitation from peer " MACSTR " was rejected (status %u)", MAC2STR(sa), status); return; } if (!s) { if (bssid) { wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa=" MACSTR " go_dev_addr=" MACSTR " bssid=" MACSTR " unknown-network", MAC2STR(sa), MAC2STR(go_dev_addr), MAC2STR(bssid)); } else { wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa=" MACSTR " go_dev_addr=" MACSTR " unknown-network", MAC2STR(sa), MAC2STR(go_dev_addr)); } return; } if (s->mode == WPAS_MODE_P2P_GO && op_freq) { wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa=" MACSTR " persistent=%d freq=%d", MAC2STR(sa), s->id, op_freq); } else { wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa=" MACSTR " persistent=%d", MAC2STR(sa), s->id); } } static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, const u8 *peer, int inv) { size_t i; if (ssid == NULL) return; for (i = 0; ssid->p2p_client_list && i < ssid->num_p2p_clients; i++) { if (os_memcmp(ssid->p2p_client_list + i * ETH_ALEN, peer, ETH_ALEN) == 0) break; } if (i >= ssid->num_p2p_clients) { if (ssid->mode != WPAS_MODE_P2P_GO && os_memcmp(ssid->bssid, peer, ETH_ALEN) == 0) { wpa_printf(MSG_DEBUG, "P2P: Remove persistent group %d " "due to invitation result", ssid->id); wpas_notify_network_removed(wpa_s, ssid); wpa_config_remove_network(wpa_s->conf, ssid->id); return; } return; /* Peer not found in client list */ } wpa_printf(MSG_DEBUG, "P2P: Remove peer " MACSTR " from persistent " "group %d client list%s", MAC2STR(peer), ssid->id, inv ? " due to invitation result" : ""); os_memmove(ssid->p2p_client_list + i * ETH_ALEN, ssid->p2p_client_list + (i + 1) * ETH_ALEN, (ssid->num_p2p_clients - i - 1) * ETH_ALEN); ssid->num_p2p_clients--; if (wpa_s->parent->conf->update_config && wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf)) wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration"); } static void wpas_remove_persistent_client(struct wpa_supplicant *wpa_s, const u8 *peer) { struct wpa_ssid *ssid; wpa_s = wpa_s->global->p2p_invite_group; if (wpa_s == NULL) return; /* No known invitation group */ ssid = wpa_s->current_ssid; if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO || !ssid->p2p_persistent_group) return; /* Not operating as a GO in persistent group */ ssid = wpas_p2p_get_persistent(wpa_s->parent, peer, ssid->ssid, ssid->ssid_len); wpas_remove_persistent_peer(wpa_s, ssid, peer, 1); } static void wpas_invitation_result(void *ctx, int status, const u8 *bssid, const struct p2p_channels *channels, const u8 *peer, int neg_freq, int peer_oper_freq) { struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *ssid; int freq; if (bssid) { wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT "status=%d " MACSTR, status, MAC2STR(bssid)); } else { wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT "status=%d ", status); } wpas_notify_p2p_invitation_result(wpa_s, status, bssid); wpa_printf(MSG_DEBUG, "P2P: Invitation result - status=%d peer=" MACSTR, status, MAC2STR(peer)); if (wpa_s->pending_invite_ssid_id == -1) { if (status == P2P_SC_FAIL_UNKNOWN_GROUP) wpas_remove_persistent_client(wpa_s, peer); return; /* Invitation to active group */ } if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { wpa_printf(MSG_DEBUG, "P2P: Waiting for peer to start another " "invitation exchange to indicate readiness for " "re-invocation"); } if (status != P2P_SC_SUCCESS) { if (status == P2P_SC_FAIL_UNKNOWN_GROUP) { ssid = wpa_config_get_network( wpa_s->conf, wpa_s->pending_invite_ssid_id); wpas_remove_persistent_peer(wpa_s, ssid, peer, 1); } wpas_p2p_remove_pending_group_interface(wpa_s); return; } ssid = wpa_config_get_network(wpa_s->conf, wpa_s->pending_invite_ssid_id); if (ssid == NULL) { wpa_printf(MSG_ERROR, "P2P: Could not find persistent group " "data matching with invitation"); return; } /* * The peer could have missed our ctrl::ack frame for Invitation * Response and continue retransmitting the frame. To reduce the * likelihood of the peer not getting successful TX status for the * Invitation Response frame, wait a short time here before starting * the persistent group so that we will remain on the current channel to * acknowledge any possible retransmission from the peer. */ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: 50 ms wait on current channel before " "starting persistent group"); os_sleep(0, 50000); if (neg_freq > 0 && ssid->mode == WPAS_MODE_P2P_GO && freq_included(channels, neg_freq)) freq = neg_freq; else if (peer_oper_freq > 0 && ssid->mode != WPAS_MODE_P2P_GO && freq_included(channels, peer_oper_freq)) freq = peer_oper_freq; else freq = 0; wpa_printf(MSG_DEBUG, "P2P: Persistent group invitation success - op_freq=%d MHz SSID=%s", freq, wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); wpas_p2p_group_add_persistent(wpa_s, ssid, ssid->mode == WPAS_MODE_P2P_GO, wpa_s->p2p_persistent_go_freq, freq, wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht, channels, ssid->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0); } static int wpas_p2p_disallowed_freq(struct wpa_global *global, unsigned int freq) { if (freq_range_list_includes(&global->p2p_go_avoid_freq, freq)) return 1; return freq_range_list_includes(&global->p2p_disallow_freq, freq); } static void wpas_p2p_add_chan(struct p2p_reg_class *reg, u8 chan) { reg->channel[reg->channels] = chan; reg->channels++; } static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s, struct p2p_channels *chan, struct p2p_channels *cli_chan) { int i, cla = 0; os_memset(cli_chan, 0, sizeof(*cli_chan)); wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz " "band"); /* Operating class 81 - 2.4 GHz band channels 1..13 */ chan->reg_class[cla].reg_class = 81; chan->reg_class[cla].channels = 0; for (i = 0; i < 11; i++) { if (!wpas_p2p_disallowed_freq(wpa_s->global, 2412 + i * 5)) wpas_p2p_add_chan(&chan->reg_class[cla], i + 1); } if (chan->reg_class[cla].channels) cla++; wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for lower 5 GHz " "band"); /* Operating class 115 - 5 GHz, channels 36-48 */ chan->reg_class[cla].reg_class = 115; chan->reg_class[cla].channels = 0; if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 36 * 5)) wpas_p2p_add_chan(&chan->reg_class[cla], 36); if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 40 * 5)) wpas_p2p_add_chan(&chan->reg_class[cla], 40); if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 44 * 5)) wpas_p2p_add_chan(&chan->reg_class[cla], 44); if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 48 * 5)) wpas_p2p_add_chan(&chan->reg_class[cla], 48); if (chan->reg_class[cla].channels) cla++; wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for higher 5 GHz " "band"); /* Operating class 124 - 5 GHz, channels 149,153,157,161 */ chan->reg_class[cla].reg_class = 124; chan->reg_class[cla].channels = 0; if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 149 * 5)) wpas_p2p_add_chan(&chan->reg_class[cla], 149); if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 153 * 5)) wpas_p2p_add_chan(&chan->reg_class[cla], 153); if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 156 * 5)) wpas_p2p_add_chan(&chan->reg_class[cla], 157); if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 161 * 5)) wpas_p2p_add_chan(&chan->reg_class[cla], 161); if (chan->reg_class[cla].channels) cla++; chan->reg_classes = cla; return 0; } static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, u16 num_modes, enum hostapd_hw_mode mode) { u16 i; for (i = 0; i < num_modes; i++) { if (modes[i].mode == mode) return &modes[i]; } return NULL; } enum chan_allowed { NOT_ALLOWED, PASSIVE_ONLY, ALLOWED }; static int has_channel(struct wpa_global *global, struct hostapd_hw_modes *mode, u8 chan, int *flags) { int i; unsigned int freq; freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) + chan * 5; if (wpas_p2p_disallowed_freq(global, freq)) return NOT_ALLOWED; for (i = 0; i < mode->num_channels; i++) { if (mode->channels[i].chan == chan) { if (flags) *flags = mode->channels[i].flag; if (mode->channels[i].flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_RADAR)) return NOT_ALLOWED; if (mode->channels[i].flag & (HOSTAPD_CHAN_PASSIVE_SCAN | HOSTAPD_CHAN_NO_IBSS)) return PASSIVE_ONLY; return ALLOWED; } } return NOT_ALLOWED; } struct p2p_oper_class_map { enum hostapd_hw_mode mode; u8 op_class; u8 min_chan; u8 max_chan; u8 inc; enum { BW20, BW40PLUS, BW40MINUS, BW80 } bw; }; static struct p2p_oper_class_map op_class[] = { { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 }, #if 0 /* Do not enable HT40 on 2 GHz for now */ { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS }, { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS }, #endif { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 }, { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 }, { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS }, { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS }, { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS }, { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS }, /* * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of * 80 MHz, but currently use the following definition for simplicity * (these center frequencies are not actual channels, which makes * has_channel() fail). wpas_p2p_verify_80mhz() should take care of * removing invalid channels. */ { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80 }, { -1, 0, 0, 0, 0, BW20 } }; static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel) { u8 center_channels[] = { 42, 58, 106, 122, 138, 155 }; unsigned int i; if (mode->mode != HOSTAPD_MODE_IEEE80211A) return 0; for (i = 0; i < ARRAY_SIZE(center_channels); i++) /* * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48), * so the center channel is 6 channels away from the start/end. */ if (channel >= center_channels[i] - 6 && channel <= center_channels[i] + 6) return center_channels[i]; return 0; } static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel, u8 bw) { u8 center_chan; int i, flags; enum chan_allowed res, ret = ALLOWED; center_chan = wpas_p2p_get_center_80mhz(wpa_s, mode, channel); if (!center_chan) return NOT_ALLOWED; if (center_chan >= 58 && center_chan <= 138) return NOT_ALLOWED; /* Do not allow DFS channels for P2P */ /* check all the channels are available */ for (i = 0; i < 4; i++) { int adj_chan = center_chan - 6 + i * 4; res = has_channel(wpa_s->global, mode, adj_chan, &flags); if (res == NOT_ALLOWED) return NOT_ALLOWED; if (res == PASSIVE_ONLY) ret = PASSIVE_ONLY; if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) return NOT_ALLOWED; if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) return NOT_ALLOWED; if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) return NOT_ALLOWED; if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)) return NOT_ALLOWED; } return ret; } static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel, u8 bw) { int flag = 0; enum chan_allowed res, res2; res2 = res = has_channel(wpa_s->global, mode, channel, &flag); if (bw == BW40MINUS) { if (!(flag & HOSTAPD_CHAN_HT40MINUS)) return NOT_ALLOWED; res2 = has_channel(wpa_s->global, mode, channel - 4, NULL); } else if (bw == BW40PLUS) { if (!(flag & HOSTAPD_CHAN_HT40PLUS)) return NOT_ALLOWED; res2 = has_channel(wpa_s->global, mode, channel + 4, NULL); } else if (bw == BW80) { res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw); } if (res == NOT_ALLOWED || res2 == NOT_ALLOWED) return NOT_ALLOWED; if (res == PASSIVE_ONLY || res2 == PASSIVE_ONLY) return PASSIVE_ONLY; return res; } static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s, struct p2p_channels *chan, struct p2p_channels *cli_chan) { struct hostapd_hw_modes *mode; int cla, op, cli_cla; if (wpa_s->hw.modes == NULL) { wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching " "of all supported channels; assume dualband " "support"); return wpas_p2p_default_channels(wpa_s, chan, cli_chan); } cla = cli_cla = 0; for (op = 0; op_class[op].op_class; op++) { struct p2p_oper_class_map *o = &op_class[op]; u8 ch; struct p2p_reg_class *reg = NULL, *cli_reg = NULL; mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode); if (mode == NULL) continue; for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { enum chan_allowed res; res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw); if (res == ALLOWED) { if (reg == NULL) { wpa_printf(MSG_DEBUG, "P2P: Add operating class %u", o->op_class); reg = &chan->reg_class[cla]; cla++; reg->reg_class = o->op_class; } reg->channel[reg->channels] = ch; reg->channels++; } else if (res == PASSIVE_ONLY && wpa_s->conf->p2p_add_cli_chan) { if (cli_reg == NULL) { wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)", o->op_class); cli_reg = &cli_chan->reg_class[cli_cla]; cli_cla++; cli_reg->reg_class = o->op_class; } cli_reg->channel[cli_reg->channels] = ch; cli_reg->channels++; } } if (reg) { wpa_hexdump(MSG_DEBUG, "P2P: Channels", reg->channel, reg->channels); } if (cli_reg) { wpa_hexdump(MSG_DEBUG, "P2P: Channels (client only)", cli_reg->channel, cli_reg->channels); } } chan->reg_classes = cla; cli_chan->reg_classes = cli_cla; return 0; } int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel) { int op; enum chan_allowed ret; for (op = 0; op_class[op].op_class; op++) { struct p2p_oper_class_map *o = &op_class[op]; u8 ch; for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { if (o->mode != HOSTAPD_MODE_IEEE80211A || o->bw == BW20 || ch != channel) continue; ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw); if (ret == ALLOWED) return (o->bw == BW40MINUS) ? -1 : 1; } } return 0; } int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel) { if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW80)) return 0; return wpas_p2p_get_center_80mhz(wpa_s, mode, channel); } static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf, size_t buf_len) { struct wpa_supplicant *wpa_s = ctx; for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) { if (os_memcmp(wpa_s->own_addr, interface_addr, ETH_ALEN) == 0) break; } if (wpa_s == NULL) return -1; return wpa_drv_get_noa(wpa_s, buf, buf_len); } static int wpas_go_connected(void *ctx, const u8 *dev_addr) { struct wpa_supplicant *wpa_s = ctx; for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) { struct wpa_ssid *ssid = wpa_s->current_ssid; if (ssid == NULL) continue; if (ssid->mode != WPAS_MODE_INFRA) continue; if (wpa_s->wpa_state != WPA_COMPLETED && wpa_s->wpa_state != WPA_GROUP_HANDSHAKE) continue; if (os_memcmp(wpa_s->go_dev_addr, dev_addr, ETH_ALEN) == 0) return 1; } return 0; } static int wpas_is_concurrent_session_active(void *ctx) { struct wpa_supplicant *wpa_s = ctx; struct wpa_supplicant *ifs; for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) { if (ifs == wpa_s) continue; if (ifs->wpa_state > WPA_ASSOCIATED) return 1; } return 0; } static void wpas_p2p_debug_print(void *ctx, int level, const char *msg) { struct wpa_supplicant *wpa_s = ctx; wpa_msg_global(wpa_s, level, "P2P: %s", msg); } int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s) { struct wpa_interface iface; struct wpa_supplicant *p2pdev_wpa_s; char ifname[100]; char force_name[100]; int ret; os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s", wpa_s->ifname); force_name[0] = '\0'; wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE; ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, NULL, NULL, force_name, wpa_s->pending_interface_addr, NULL); if (ret < 0) { wpa_printf(MSG_DEBUG, "P2P: Failed to create P2P Device interface"); return ret; } os_strlcpy(wpa_s->pending_interface_name, ifname, sizeof(wpa_s->pending_interface_name)); os_memset(&iface, 0, sizeof(iface)); iface.p2p_mgmt = 1; iface.ifname = wpa_s->pending_interface_name; iface.driver = wpa_s->driver->name; iface.driver_param = wpa_s->conf->driver_param; /* * If a P2P Device configuration file was given, use it as the interface * configuration file (instead of using parent's configuration file. */ if (wpa_s->conf_p2p_dev) { iface.confname = wpa_s->conf_p2p_dev; iface.ctrl_interface = NULL; } else { iface.confname = wpa_s->confname; iface.ctrl_interface = wpa_s->conf->ctrl_interface; } iface.conf_p2p_dev = NULL; p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface); if (!p2pdev_wpa_s) { wpa_printf(MSG_DEBUG, "P2P: Failed to add P2P Device interface"); return -1; } p2pdev_wpa_s->parent = wpa_s; wpa_s->pending_interface_name[0] = '\0'; return 0; } static void wpas_presence_resp(void *ctx, const u8 *src, u8 status, const u8 *noa, size_t noa_len) { struct wpa_supplicant *wpa_s, *intf = ctx; char hex[100]; for (wpa_s = intf->global->ifaces; wpa_s; wpa_s = wpa_s->next) { if (wpa_s->waiting_presence_resp) break; } if (!wpa_s) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No group interface was waiting for presence response"); return; } wpa_s->waiting_presence_resp = 0; wpa_snprintf_hex(hex, sizeof(hex), noa, noa_len); wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PRESENCE_RESPONSE "src=" MACSTR " status=%u noa=%s", MAC2STR(src), status, hex); } static int _wpas_p2p_in_progress(void *ctx) { struct wpa_supplicant *wpa_s = ctx; return wpas_p2p_in_progress(wpa_s); } /** * wpas_p2p_init - Initialize P2P module for %wpa_supplicant * @global: Pointer to global data from wpa_supplicant_init() * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface() * Returns: 0 on success, -1 on failure */ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) { struct p2p_config p2p; unsigned int r; int i; if (wpa_s->conf->p2p_disabled) return 0; if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE)) return 0; if (global->p2p) return 0; os_memset(&p2p, 0, sizeof(p2p)); p2p.cb_ctx = wpa_s; p2p.debug_print = wpas_p2p_debug_print; p2p.p2p_scan = wpas_p2p_scan; p2p.send_action = wpas_send_action; p2p.send_action_done = wpas_send_action_done; p2p.go_neg_completed = wpas_go_neg_completed; p2p.go_neg_req_rx = wpas_go_neg_req_rx; p2p.dev_found = wpas_dev_found; p2p.dev_lost = wpas_dev_lost; p2p.find_stopped = wpas_find_stopped; p2p.start_listen = wpas_start_listen; p2p.stop_listen = wpas_stop_listen; p2p.send_probe_resp = wpas_send_probe_resp; p2p.sd_request = wpas_sd_request; p2p.sd_response = wpas_sd_response; p2p.prov_disc_req = wpas_prov_disc_req; p2p.prov_disc_resp = wpas_prov_disc_resp; p2p.prov_disc_fail = wpas_prov_disc_fail; p2p.invitation_process = wpas_invitation_process; p2p.invitation_received = wpas_invitation_received; p2p.invitation_result = wpas_invitation_result; p2p.get_noa = wpas_get_noa; p2p.go_connected = wpas_go_connected; p2p.presence_resp = wpas_presence_resp; p2p.is_concurrent_session_active = wpas_is_concurrent_session_active; p2p.is_p2p_in_progress = _wpas_p2p_in_progress; os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN); os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN); p2p.dev_name = wpa_s->conf->device_name; p2p.manufacturer = wpa_s->conf->manufacturer; p2p.model_name = wpa_s->conf->model_name; p2p.model_number = wpa_s->conf->model_number; p2p.serial_number = wpa_s->conf->serial_number; if (wpa_s->wps) { os_memcpy(p2p.uuid, wpa_s->wps->uuid, 16); p2p.config_methods = wpa_s->wps->config_methods; } if (wpa_s->conf->p2p_listen_reg_class && wpa_s->conf->p2p_listen_channel) { p2p.reg_class = wpa_s->conf->p2p_listen_reg_class; p2p.channel = wpa_s->conf->p2p_listen_channel; } else { p2p.reg_class = 81; /* * Pick one of the social channels randomly as the listen * channel. */ os_get_random((u8 *) &r, sizeof(r)); p2p.channel = 1 + (r % 3) * 5; } wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d", p2p.channel); if (wpa_s->conf->p2p_oper_reg_class && wpa_s->conf->p2p_oper_channel) { p2p.op_reg_class = wpa_s->conf->p2p_oper_reg_class; p2p.op_channel = wpa_s->conf->p2p_oper_channel; p2p.cfg_op_channel = 1; wpa_printf(MSG_DEBUG, "P2P: Configured operating channel: " "%d:%d", p2p.op_reg_class, p2p.op_channel); } else { p2p.op_reg_class = 81; /* * Use random operation channel from (1, 6, 11) if no other * preference is indicated. */ os_get_random((u8 *) &r, sizeof(r)); p2p.op_channel = 1 + (r % 3) * 5; p2p.cfg_op_channel = 0; wpa_printf(MSG_DEBUG, "P2P: Random operating channel: " "%d:%d", p2p.op_reg_class, p2p.op_channel); } if (wpa_s->conf->p2p_pref_chan && wpa_s->conf->num_p2p_pref_chan) { p2p.pref_chan = wpa_s->conf->p2p_pref_chan; p2p.num_pref_chan = wpa_s->conf->num_p2p_pref_chan; } if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) { os_memcpy(p2p.country, wpa_s->conf->country, 2); p2p.country[2] = 0x04; } else os_memcpy(p2p.country, "XX\x04", 3); if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) { wpa_printf(MSG_ERROR, "P2P: Failed to configure supported " "channel list"); return -1; } os_memcpy(p2p.pri_dev_type, wpa_s->conf->device_type, WPS_DEV_TYPE_LEN); p2p.num_sec_dev_types = wpa_s->conf->num_sec_device_types; os_memcpy(p2p.sec_dev_type, wpa_s->conf->sec_device_type, p2p.num_sec_dev_types * WPS_DEV_TYPE_LEN); p2p.concurrent_operations = !!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CONCURRENT); p2p.max_peers = 100; if (wpa_s->conf->p2p_ssid_postfix) { p2p.ssid_postfix_len = os_strlen(wpa_s->conf->p2p_ssid_postfix); if (p2p.ssid_postfix_len > sizeof(p2p.ssid_postfix)) p2p.ssid_postfix_len = sizeof(p2p.ssid_postfix); os_memcpy(p2p.ssid_postfix, wpa_s->conf->p2p_ssid_postfix, p2p.ssid_postfix_len); } p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss; p2p.max_listen = wpa_s->max_remain_on_chan; global->p2p = p2p_init(&p2p); if (global->p2p == NULL) return -1; global->p2p_init_wpa_s = wpa_s; for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) { if (wpa_s->conf->wps_vendor_ext[i] == NULL) continue; p2p_add_wps_vendor_extension( global->p2p, wpa_s->conf->wps_vendor_ext[i]); } p2p_set_no_go_freq(global->p2p, &wpa_s->conf->p2p_no_go_freq); return 0; } /** * wpas_p2p_deinit - Deinitialize per-interface P2P data * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface() * * This function deinitialize per-interface P2P data. */ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s) { if (wpa_s->driver && wpa_s->drv_priv) wpa_drv_probe_req_report(wpa_s, 0); if (wpa_s->go_params) { /* Clear any stored provisioning info */ p2p_clear_provisioning_info( wpa_s->global->p2p, wpa_s->go_params->peer_device_addr); } os_free(wpa_s->go_params); wpa_s->go_params = NULL; eloop_cancel_timeout(wpas_p2p_psk_failure_removal, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); wpa_s->p2p_long_listen = 0; eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL); wpas_p2p_remove_pending_group_interface(wpa_s); eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL); wpas_p2p_listen_work_done(wpa_s); if (wpa_s->p2p_send_action_work) { os_free(wpa_s->p2p_send_action_work->ctx); radio_work_done(wpa_s->p2p_send_action_work); wpa_s->p2p_send_action_work = NULL; } eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, wpa_s, NULL); wpabuf_free(wpa_s->p2p_oob_dev_pw); wpa_s->p2p_oob_dev_pw = NULL; /* TODO: remove group interface from the driver if this wpa_s instance * is on top of a P2P group interface */ } /** * wpas_p2p_deinit_global - Deinitialize global P2P module * @global: Pointer to global data from wpa_supplicant_init() * * This function deinitializes the global (per device) P2P module. */ void wpas_p2p_deinit_global(struct wpa_global *global) { struct wpa_supplicant *wpa_s, *tmp; wpa_s = global->ifaces; if (wpa_s) wpas_p2p_service_flush(wpa_s); if (global->p2p == NULL) return; /* Remove remaining P2P group interfaces */ while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) wpa_s = wpa_s->next; while (wpa_s) { tmp = global->ifaces; while (tmp && (tmp == wpa_s || tmp->p2p_group_interface == NOT_P2P_GROUP_INTERFACE)) { tmp = tmp->next; } if (tmp == NULL) break; /* Disconnect from the P2P group and deinit the interface */ wpas_p2p_disconnect(tmp); } /* * Deinit GO data on any possibly remaining interface (if main * interface is used as GO). */ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { if (wpa_s->ap_iface) wpas_p2p_group_deinit(wpa_s); } p2p_deinit(global->p2p); global->p2p = NULL; global->p2p_init_wpa_s = NULL; } static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s) { if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) && wpa_s->conf->p2p_no_group_iface) return 0; /* separate interface disabled per configuration */ if (wpa_s->drv_flags & (WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE | WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P)) return 1; /* P2P group requires a new interface in every case */ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CONCURRENT)) return 0; /* driver does not support concurrent operations */ if (wpa_s->global->ifaces->next) return 1; /* more that one interface already in use */ if (wpa_s->wpa_state >= WPA_AUTHENTICATING) return 1; /* this interface is already in use */ return 0; } static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s, const u8 *peer_addr, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group, struct wpa_ssid *ssid, unsigned int pref_freq) { if (persistent_group && wpa_s->conf->persistent_reconnect) persistent_group = 2; /* * Increase GO config timeout if HT40 is used since it takes some time * to scan channels for coex purposes before the BSS can be started. */ p2p_set_config_timeout(wpa_s->global->p2p, wpa_s->p2p_go_ht40 ? 255 : 100, 20); return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method, go_intent, own_interface_addr, force_freq, persistent_group, ssid ? ssid->ssid : NULL, ssid ? ssid->ssid_len : 0, wpa_s->p2p_pd_before_go_neg, pref_freq, wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id : 0); } static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s, const u8 *peer_addr, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group, struct wpa_ssid *ssid, unsigned int pref_freq) { if (persistent_group && wpa_s->conf->persistent_reconnect) persistent_group = 2; return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method, go_intent, own_interface_addr, force_freq, persistent_group, ssid ? ssid->ssid : NULL, ssid ? ssid->ssid_len : 0, pref_freq, wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id : 0); } static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s) { wpa_s->p2p_join_scan_count++; wpa_printf(MSG_DEBUG, "P2P: Join scan attempt %d", wpa_s->p2p_join_scan_count); if (wpa_s->p2p_join_scan_count > P2P_MAX_JOIN_SCAN_ATTEMPTS) { wpa_printf(MSG_DEBUG, "P2P: Failed to find GO " MACSTR " for join operationg - stop join attempt", MAC2STR(wpa_s->pending_join_iface_addr)); eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); if (wpa_s->p2p_auto_pd) { wpa_s->p2p_auto_pd = 0; wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE " p2p_dev_addr=" MACSTR " status=N/A", MAC2STR(wpa_s->pending_join_dev_addr)); return; } wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_FORMATION_FAILURE); } } static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq) { int *freqs, res, num, i; if (wpas_p2p_num_unused_channels(wpa_s) > 0) { /* Multiple channels are supported and not all are in use */ return 0; } freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int)); if (!freqs) return 1; num = wpas_p2p_valid_oper_freqs(wpa_s, freqs, wpa_s->num_multichan_concurrent); if (num < 0) { res = 1; goto exit_free; } for (i = 0; i < num; i++) { if (freqs[i] == freq) { wpa_printf(MSG_DEBUG, "P2P: Frequency %d MHz in use by another virtual interface and can be used", freq); res = 0; goto exit_free; } } res = 1; exit_free: os_free(freqs); return res; } static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s, const u8 *peer_dev_addr) { struct wpa_bss *bss; int updated; bss = wpa_bss_get_p2p_dev_addr(wpa_s, peer_dev_addr); if (bss == NULL) return -1; if (bss->last_update_idx < wpa_s->bss_update_idx) { wpa_printf(MSG_DEBUG, "P2P: Peer BSS entry not updated in the " "last scan"); return 0; } updated = os_reltime_before(&wpa_s->p2p_auto_started, &bss->last_update); wpa_printf(MSG_DEBUG, "P2P: Current BSS entry for peer updated at " "%ld.%06ld (%supdated in last scan)", bss->last_update.sec, bss->last_update.usec, updated ? "": "not "); return updated; } static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { struct wpa_bss *bss = NULL; int freq; u8 iface_addr[ETH_ALEN]; eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); if (wpa_s->global->p2p_disabled) return; wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for %sjoin", scan_res ? (int) scan_res->num : -1, wpa_s->p2p_auto_join ? "auto_" : ""); if (scan_res) wpas_p2p_scan_res_handler(wpa_s, scan_res); if (wpa_s->p2p_auto_pd) { int join = wpas_p2p_peer_go(wpa_s, wpa_s->pending_join_dev_addr); if (join == 0 && wpa_s->auto_pd_scan_retry < P2P_AUTO_PD_SCAN_ATTEMPTS) { wpa_s->auto_pd_scan_retry++; bss = wpa_bss_get_bssid_latest( wpa_s, wpa_s->pending_join_dev_addr); if (bss) { freq = bss->freq; wpa_printf(MSG_DEBUG, "P2P: Scan retry %d for " "the peer " MACSTR " at %d MHz", wpa_s->auto_pd_scan_retry, MAC2STR(wpa_s-> pending_join_dev_addr), freq); wpas_p2p_join_scan_req(wpa_s, freq, NULL, 0); return; } } if (join < 0) join = 0; wpa_s->p2p_auto_pd = 0; wpa_s->pending_pd_use = join ? AUTO_PD_JOIN : AUTO_PD_GO_NEG; wpa_printf(MSG_DEBUG, "P2P: Auto PD with " MACSTR " join=%d", MAC2STR(wpa_s->pending_join_dev_addr), join); if (p2p_prov_disc_req(wpa_s->global->p2p, wpa_s->pending_join_dev_addr, wpa_s->pending_pd_config_methods, join, 0, wpa_s->user_initiated_pd) < 0) { wpa_s->p2p_auto_pd = 0; wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE " p2p_dev_addr=" MACSTR " status=N/A", MAC2STR(wpa_s->pending_join_dev_addr)); } return; } if (wpa_s->p2p_auto_join) { int join = wpas_p2p_peer_go(wpa_s, wpa_s->pending_join_dev_addr); if (join < 0) { wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be " "running a GO -> use GO Negotiation"); wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin, wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0, 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq, wpa_s->p2p_persistent_id, wpa_s->p2p_pd_before_go_neg, wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht); return; } wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO%s -> " "try to join the group", join ? "" : " in older scan"); if (!join) wpa_s->p2p_fallback_to_go_neg = 1; } freq = p2p_get_oper_freq(wpa_s->global->p2p, wpa_s->pending_join_iface_addr); if (freq < 0 && p2p_get_interface_addr(wpa_s->global->p2p, wpa_s->pending_join_dev_addr, iface_addr) == 0 && os_memcmp(iface_addr, wpa_s->pending_join_dev_addr, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "P2P: Overwrite pending interface " "address for join from " MACSTR " to " MACSTR " based on newly discovered P2P peer entry", MAC2STR(wpa_s->pending_join_iface_addr), MAC2STR(iface_addr)); os_memcpy(wpa_s->pending_join_iface_addr, iface_addr, ETH_ALEN); freq = p2p_get_oper_freq(wpa_s->global->p2p, wpa_s->pending_join_iface_addr); } if (freq >= 0) { wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency " "from P2P peer table: %d MHz", freq); } if (wpa_s->p2p_join_ssid_len) { wpa_printf(MSG_DEBUG, "P2P: Trying to find target GO BSS entry based on BSSID " MACSTR " and SSID %s", MAC2STR(wpa_s->pending_join_iface_addr), wpa_ssid_txt(wpa_s->p2p_join_ssid, wpa_s->p2p_join_ssid_len)); bss = wpa_bss_get(wpa_s, wpa_s->pending_join_iface_addr, wpa_s->p2p_join_ssid, wpa_s->p2p_join_ssid_len); } if (!bss) { wpa_printf(MSG_DEBUG, "P2P: Trying to find target GO BSS entry based on BSSID " MACSTR, MAC2STR(wpa_s->pending_join_iface_addr)); bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->pending_join_iface_addr); } if (bss) { freq = bss->freq; wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency " "from BSS table: %d MHz (SSID %s)", freq, wpa_ssid_txt(bss->ssid, bss->ssid_len)); } if (freq > 0) { u16 method; if (wpas_check_freq_conflict(wpa_s, freq) > 0) { wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_FORMATION_FAILURE "reason=FREQ_CONFLICT"); return; } wpa_printf(MSG_DEBUG, "P2P: Send Provision Discovery Request " "prior to joining an existing group (GO " MACSTR " freq=%u MHz)", MAC2STR(wpa_s->pending_join_dev_addr), freq); wpa_s->pending_pd_before_join = 1; switch (wpa_s->pending_join_wps_method) { case WPS_PIN_DISPLAY: method = WPS_CONFIG_KEYPAD; break; case WPS_PIN_KEYPAD: method = WPS_CONFIG_DISPLAY; break; case WPS_PBC: method = WPS_CONFIG_PUSHBUTTON; break; default: method = 0; break; } if ((p2p_get_provisioning_info(wpa_s->global->p2p, wpa_s->pending_join_dev_addr) == method)) { /* * We have already performed provision discovery for * joining the group. Proceed directly to join * operation without duplicated provision discovery. */ wpa_printf(MSG_DEBUG, "P2P: Provision discovery " "with " MACSTR " already done - proceed to " "join", MAC2STR(wpa_s->pending_join_dev_addr)); wpa_s->pending_pd_before_join = 0; goto start; } if (p2p_prov_disc_req(wpa_s->global->p2p, wpa_s->pending_join_dev_addr, method, 1, freq, wpa_s->user_initiated_pd) < 0) { wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision " "Discovery Request before joining an " "existing group"); wpa_s->pending_pd_before_join = 0; goto start; } return; } wpa_printf(MSG_DEBUG, "P2P: Failed to find BSS/GO - try again later"); eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); eloop_register_timeout(1, 0, wpas_p2p_join_scan, wpa_s, NULL); wpas_p2p_check_join_scan_limit(wpa_s); return; start: /* Start join operation immediately */ wpas_p2p_join_start(wpa_s, 0, NULL, 0); } static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, const u8 *ssid, size_t ssid_len) { int ret; struct wpa_driver_scan_params params; struct wpabuf *wps_ie, *ies; size_t ielen; int freqs[2] = { 0, 0 }; os_memset(¶ms, 0, sizeof(params)); /* P2P Wildcard SSID */ params.num_ssids = 1; if (ssid && ssid_len) { params.ssids[0].ssid = ssid; params.ssids[0].ssid_len = ssid_len; os_memcpy(wpa_s->p2p_join_ssid, ssid, ssid_len); wpa_s->p2p_join_ssid_len = ssid_len; } else { params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID; params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN; wpa_s->p2p_join_ssid_len = 0; } wpa_s->wps->dev.p2p = 1; wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, &wpa_s->wps->dev, wpa_s->wps->uuid, WPS_REQ_ENROLLEE, 0, NULL); if (wps_ie == NULL) { wpas_p2p_scan_res_join(wpa_s, NULL); return; } ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); if (ies == NULL) { wpabuf_free(wps_ie); wpas_p2p_scan_res_join(wpa_s, NULL); return; } wpabuf_put_buf(ies, wps_ie); wpabuf_free(wps_ie); p2p_scan_ie(wpa_s->global->p2p, ies, NULL); params.p2p_probe = 1; params.extra_ies = wpabuf_head(ies); params.extra_ies_len = wpabuf_len(ies); if (!freq) { int oper_freq; /* * If freq is not provided, check the operating freq of the GO * and use a single channel scan on if possible. */ oper_freq = p2p_get_oper_freq(wpa_s->global->p2p, wpa_s->pending_join_iface_addr); if (oper_freq > 0) freq = oper_freq; } if (freq > 0) { freqs[0] = freq; params.freqs = freqs; } /* * Run a scan to update BSS table and start Provision Discovery once * the new scan results become available. */ ret = wpa_drv_scan(wpa_s, ¶ms); if (!ret) { os_get_reltime(&wpa_s->scan_trigger_time); wpa_s->scan_res_handler = wpas_p2p_scan_res_join; wpa_s->own_scan_requested = 1; } wpabuf_free(ies); if (ret) { wpa_printf(MSG_DEBUG, "P2P: Failed to start scan for join - " "try again later"); eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); eloop_register_timeout(1, 0, wpas_p2p_join_scan, wpa_s, NULL); wpas_p2p_check_join_scan_limit(wpa_s); } } static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; wpas_p2p_join_scan_req(wpa_s, 0, NULL, 0); } static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr, const u8 *dev_addr, enum p2p_wps_method wps_method, int auto_join, int op_freq, const u8 *ssid, size_t ssid_len) { wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface " MACSTR " dev " MACSTR " op_freq=%d)%s", MAC2STR(iface_addr), MAC2STR(dev_addr), op_freq, auto_join ? " (auto_join)" : ""); if (ssid && ssid_len) { wpa_printf(MSG_DEBUG, "P2P: Group SSID specified: %s", wpa_ssid_txt(ssid, ssid_len)); } wpa_s->p2p_auto_pd = 0; wpa_s->p2p_auto_join = !!auto_join; os_memcpy(wpa_s->pending_join_iface_addr, iface_addr, ETH_ALEN); os_memcpy(wpa_s->pending_join_dev_addr, dev_addr, ETH_ALEN); wpa_s->pending_join_wps_method = wps_method; /* Make sure we are not running find during connection establishment */ wpas_p2p_stop_find(wpa_s); wpa_s->p2p_join_scan_count = 0; wpas_p2p_join_scan_req(wpa_s, op_freq, ssid, ssid_len); return 0; } static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq, const u8 *ssid, size_t ssid_len) { struct wpa_supplicant *group; struct p2p_go_neg_results res; struct wpa_bss *bss; group = wpas_p2p_get_group_iface(wpa_s, 0, 0); if (group == NULL) return -1; if (group != wpa_s) { os_memcpy(group->p2p_pin, wpa_s->p2p_pin, sizeof(group->p2p_pin)); group->p2p_wps_method = wpa_s->p2p_wps_method; } else { /* * Need to mark the current interface for p2p_group_formation * when a separate group interface is not used. This is needed * to allow p2p_cancel stop a pending p2p_connect-join. * wpas_p2p_init_group_interface() addresses this for the case * where a separate group interface is used. */ wpa_s->global->p2p_group_formation = wpa_s; } group->p2p_in_provisioning = 1; group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg; os_memset(&res, 0, sizeof(res)); os_memcpy(res.peer_device_addr, wpa_s->pending_join_dev_addr, ETH_ALEN); os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr, ETH_ALEN); res.wps_method = wpa_s->pending_join_wps_method; if (freq && ssid && ssid_len) { res.freq = freq; res.ssid_len = ssid_len; os_memcpy(res.ssid, ssid, ssid_len); } else { bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->pending_join_iface_addr); if (bss) { res.freq = bss->freq; res.ssid_len = bss->ssid_len; os_memcpy(res.ssid, bss->ssid, bss->ssid_len); wpa_printf(MSG_DEBUG, "P2P: Join target GO operating frequency from BSS table: %d MHz (SSID %s)", bss->freq, wpa_ssid_txt(bss->ssid, bss->ssid_len)); } } if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) { wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel prior to " "starting client"); wpa_drv_cancel_remain_on_channel(wpa_s); wpa_s->off_channel_freq = 0; wpa_s->roc_waiting_drv_freq = 0; } wpas_start_wps_enrollee(group, &res); /* * Allow a longer timeout for join-a-running-group than normal 15 * second group formation timeout since the GO may not have authorized * our connection yet. */ eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL); eloop_register_timeout(60, 0, wpas_p2p_group_formation_timeout, wpa_s, NULL); return 0; } static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, int *force_freq, int *pref_freq, int go) { int *freqs, res; unsigned int freq_in_use = 0, num, i; freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int)); if (!freqs) return -1; num = get_shared_radio_freqs(wpa_s, freqs, wpa_s->num_multichan_concurrent); wpa_printf(MSG_DEBUG, "P2P: Setup freqs: freq=%d num_MCC=%d shared_freqs=%u", freq, wpa_s->num_multichan_concurrent, num); if (freq > 0) { int ret; if (go) ret = p2p_supported_freq(wpa_s->global->p2p, freq); else ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq); if (!ret) { wpa_printf(MSG_DEBUG, "P2P: The forced channel " "(%u MHz) is not supported for P2P uses", freq); res = -3; goto exit_free; } for (i = 0; i < num; i++) { if (freqs[i] == freq) freq_in_use = 1; } if (num == wpa_s->num_multichan_concurrent && !freq_in_use) { wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz as there are no available channels", freq); res = -2; goto exit_free; } wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the " "requested channel (%u MHz)", freq); *force_freq = freq; goto exit_ok; } for (i = 0; i < num; i++) { if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i])) continue; if (*pref_freq == 0 && num < wpa_s->num_multichan_concurrent) { wpa_printf(MSG_DEBUG, "P2P: Try to prefer a frequency (%u MHz) we are already using", freqs[i]); *pref_freq = freqs[i]; } else { wpa_printf(MSG_DEBUG, "P2P: Try to force us to use frequency (%u MHz) which is already in use", freqs[i]); *force_freq = freqs[i]; } break; } if (i == num) { if (num < wpa_s->num_multichan_concurrent && num > 0) { wpa_printf(MSG_DEBUG, "P2P: Current operating channels are not available for P2P. Try to use another channel"); *force_freq = 0; } else if (num < wpa_s->num_multichan_concurrent) { wpa_printf(MSG_DEBUG, "P2P: No current operating channels - try to use a new channel"); *force_freq = 0; } else { wpa_printf(MSG_DEBUG, "P2P: All channels are in use and none of them are P2P enabled. Cannot start P2P group"); res = -2; goto exit_free; } } exit_ok: res = 0; exit_free: os_free(freqs); return res; } /** * wpas_p2p_connect - Request P2P Group Formation to be started * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface() * @peer_addr: Address of the peer P2P Device * @pin: PIN to use during provisioning or %NULL to indicate PBC mode * @persistent_group: Whether to create a persistent group * @auto_join: Whether to select join vs. GO Negotiation automatically * @join: Whether to join an existing group (as a client) instead of starting * Group Owner negotiation; @peer_addr is BSSID in that case * @auth: Whether to only authorize the connection instead of doing that and * initiating Group Owner negotiation * @go_intent: GO Intent or -1 to use default * @freq: Frequency for the group or 0 for auto-selection * @persistent_id: Persistent group credentials to use for forcing GO * parameters or -1 to generate new values (SSID/passphrase) * @pd: Whether to send Provision Discovery prior to GO Negotiation as an * interoperability workaround when initiating group formation * @ht40: Start GO with 40 MHz channel width * @vht: Start GO with VHT support * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified * failure, -2 on failure due to channel not currently available, * -3 if forced channel is not supported */ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, const char *pin, enum p2p_wps_method wps_method, int persistent_group, int auto_join, int join, int auth, int go_intent, int freq, int persistent_id, int pd, int ht40, int vht) { int force_freq = 0, pref_freq = 0; int ret = 0, res; enum wpa_driver_if_type iftype; const u8 *if_addr; struct wpa_ssid *ssid = NULL; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; if (persistent_id >= 0) { ssid = wpa_config_get_network(wpa_s->conf, persistent_id); if (ssid == NULL || ssid->disabled != 2 || ssid->mode != WPAS_MODE_P2P_GO) return -1; } os_free(wpa_s->global->add_psk); wpa_s->global->add_psk = NULL; wpa_s->global->p2p_fail_on_wps_complete = 0; if (go_intent < 0) go_intent = wpa_s->conf->p2p_go_intent; if (!auth) wpa_s->p2p_long_listen = 0; wpa_s->p2p_wps_method = wps_method; wpa_s->p2p_persistent_group = !!persistent_group; wpa_s->p2p_persistent_id = persistent_id; wpa_s->p2p_go_intent = go_intent; wpa_s->p2p_connect_freq = freq; wpa_s->p2p_fallback_to_go_neg = 0; wpa_s->p2p_pd_before_go_neg = !!pd; wpa_s->p2p_go_ht40 = !!ht40; wpa_s->p2p_go_vht = !!vht; if (pin) os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin)); else if (wps_method == WPS_PIN_DISPLAY) { ret = wps_generate_pin(); os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin), "%08d", ret); wpa_printf(MSG_DEBUG, "P2P: Randomly generated PIN: %s", wpa_s->p2p_pin); } else wpa_s->p2p_pin[0] = '\0'; if (join || auto_join) { u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN]; if (auth) { wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to " "connect a running group from " MACSTR, MAC2STR(peer_addr)); os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN); return ret; } os_memcpy(dev_addr, peer_addr, ETH_ALEN); if (p2p_get_interface_addr(wpa_s->global->p2p, peer_addr, iface_addr) < 0) { os_memcpy(iface_addr, peer_addr, ETH_ALEN); p2p_get_dev_addr(wpa_s->global->p2p, peer_addr, dev_addr); } if (auto_join) { os_get_reltime(&wpa_s->p2p_auto_started); wpa_printf(MSG_DEBUG, "P2P: Auto join started at " "%ld.%06ld", wpa_s->p2p_auto_started.sec, wpa_s->p2p_auto_started.usec); } wpa_s->user_initiated_pd = 1; if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method, auto_join, freq, NULL, 0) < 0) return -1; return ret; } res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq, go_intent == 15); if (res) return res; wpas_p2p_set_own_freq_preference(wpa_s, force_freq ? force_freq : pref_freq); wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s); if (wpa_s->create_p2p_iface) { /* Prepare to add a new interface for the group */ iftype = WPA_IF_P2P_GROUP; if (go_intent == 15) iftype = WPA_IF_P2P_GO; if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) { wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new " "interface for the group"); return -1; } if_addr = wpa_s->pending_interface_addr; } else if_addr = wpa_s->own_addr; if (auth) { if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method, go_intent, if_addr, force_freq, persistent_group, ssid, pref_freq) < 0) return -1; return ret; } if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method, go_intent, if_addr, force_freq, persistent_group, ssid, pref_freq) < 0) { if (wpa_s->create_p2p_iface) wpas_p2p_remove_pending_group_interface(wpa_s); return -1; } return ret; } /** * wpas_p2p_remain_on_channel_cb - Indication of remain-on-channel start * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface() * @freq: Frequency of the channel in MHz * @duration: Duration of the stay on the channel in milliseconds * * This callback is called when the driver indicates that it has started the * requested remain-on-channel duration. */ void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq, unsigned int duration) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; if (wpa_s->off_channel_freq == wpa_s->pending_listen_freq) { p2p_listen_cb(wpa_s->global->p2p, wpa_s->pending_listen_freq, wpa_s->pending_listen_duration); wpa_s->pending_listen_freq = 0; } else { wpa_printf(MSG_DEBUG, "P2P: Ignore remain-on-channel callback (off_channel_freq=%u pending_listen_freq=%d freq=%u duration=%u)", wpa_s->off_channel_freq, wpa_s->pending_listen_freq, freq, duration); } } static int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s, unsigned int timeout) { /* Limit maximum Listen state time based on driver limitation. */ if (timeout > wpa_s->max_remain_on_chan) timeout = wpa_s->max_remain_on_chan; return p2p_listen(wpa_s->global->p2p, timeout); } /** * wpas_p2p_cancel_remain_on_channel_cb - Remain-on-channel timeout * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface() * @freq: Frequency of the channel in MHz * * This callback is called when the driver indicates that a remain-on-channel * operation has been completed, i.e., the duration on the requested channel * has timed out. */ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq) { wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback " "(p2p_long_listen=%d ms pending_action_tx=%p)", wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s)); wpas_p2p_listen_work_done(wpa_s); if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; if (p2p_listen_end(wpa_s->global->p2p, freq) > 0) return; /* P2P module started a new operation */ if (offchannel_pending_action_tx(wpa_s)) return; if (wpa_s->p2p_long_listen > 0) wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan; if (wpa_s->p2p_long_listen > 0) { wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state"); wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen); } else { /* * When listen duration is over, stop listen & update p2p_state * to IDLE. */ p2p_stop_listen(wpa_s->global->p2p); } } /** * wpas_p2p_group_remove - Remove a P2P group * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface() * @ifname: Network interface name of the group interface or "*" to remove all * groups * Returns: 0 on success, -1 on failure * * This function is used to remove a P2P group. This can be used to disconnect * from a group in which the local end is a P2P Client or to end a P2P Group in * case the local end is the Group Owner. If a virtual network interface was * created for this group, that interface will be removed. Otherwise, only the * configured P2P group network will be removed from the interface. */ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname) { struct wpa_global *global = wpa_s->global; if (os_strcmp(ifname, "*") == 0) { struct wpa_supplicant *prev; wpa_s = global->ifaces; while (wpa_s) { prev = wpa_s; wpa_s = wpa_s->next; if (prev->p2p_group_interface != NOT_P2P_GROUP_INTERFACE || (prev->current_ssid && prev->current_ssid->p2p_group)) wpas_p2p_disconnect(prev); } return 0; } for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { if (os_strcmp(wpa_s->ifname, ifname) == 0) break; } return wpas_p2p_disconnect(wpa_s); } static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq) { unsigned int r; if (freq == 2) { wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz " "band"); if (wpa_s->best_24_freq > 0 && p2p_supported_freq_go(wpa_s->global->p2p, wpa_s->best_24_freq)) { freq = wpa_s->best_24_freq; wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band " "channel: %d MHz", freq); } else { os_get_random((u8 *) &r, sizeof(r)); freq = 2412 + (r % 3) * 25; wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band " "channel: %d MHz", freq); } } if (freq == 5) { wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz " "band"); if (wpa_s->best_5_freq > 0 && p2p_supported_freq_go(wpa_s->global->p2p, wpa_s->best_5_freq)) { freq = wpa_s->best_5_freq; wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band " "channel: %d MHz", freq); } else { os_get_random((u8 *) &r, sizeof(r)); freq = 5180 + (r % 4) * 20; if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) { wpa_printf(MSG_DEBUG, "P2P: Could not select " "5 GHz channel for P2P group"); return -1; } wpa_printf(MSG_DEBUG, "P2P: Use random 5 GHz band " "channel: %d MHz", freq); } } if (freq > 0 && !p2p_supported_freq_go(wpa_s->global->p2p, freq)) { wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO " "(%u MHz) is not supported for P2P uses", freq); return -1; } return freq; } static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *params, int freq, int ht40, int vht, const struct p2p_channels *channels) { int res, *freqs; unsigned int pref_freq; unsigned int num, i; os_memset(params, 0, sizeof(*params)); params->role_go = 1; params->ht40 = ht40; params->vht = vht; if (freq) { if (!freq_included(channels, freq)) { wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not " "accepted", freq); return -1; } wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced " "frequency %d MHz", freq); params->freq = freq; } else if (wpa_s->conf->p2p_oper_reg_class == 81 && wpa_s->conf->p2p_oper_channel >= 1 && wpa_s->conf->p2p_oper_channel <= 11 && freq_included(channels, 2407 + 5 * wpa_s->conf->p2p_oper_channel)) { params->freq = 2407 + 5 * wpa_s->conf->p2p_oper_channel; wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured " "frequency %d MHz", params->freq); } else if ((wpa_s->conf->p2p_oper_reg_class == 115 || wpa_s->conf->p2p_oper_reg_class == 116 || wpa_s->conf->p2p_oper_reg_class == 117 || wpa_s->conf->p2p_oper_reg_class == 124 || wpa_s->conf->p2p_oper_reg_class == 126 || wpa_s->conf->p2p_oper_reg_class == 127) && freq_included(channels, 5000 + 5 * wpa_s->conf->p2p_oper_channel)) { params->freq = 5000 + 5 * wpa_s->conf->p2p_oper_channel; wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured " "frequency %d MHz", params->freq); } else if (wpa_s->conf->p2p_oper_channel == 0 && wpa_s->best_overall_freq > 0 && p2p_supported_freq_go(wpa_s->global->p2p, wpa_s->best_overall_freq) && freq_included(channels, wpa_s->best_overall_freq)) { params->freq = wpa_s->best_overall_freq; wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall " "channel %d MHz", params->freq); } else if (wpa_s->conf->p2p_oper_channel == 0 && wpa_s->best_24_freq > 0 && p2p_supported_freq_go(wpa_s->global->p2p, wpa_s->best_24_freq) && freq_included(channels, wpa_s->best_24_freq)) { params->freq = wpa_s->best_24_freq; wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz " "channel %d MHz", params->freq); } else if (wpa_s->conf->p2p_oper_channel == 0 && wpa_s->best_5_freq > 0 && p2p_supported_freq_go(wpa_s->global->p2p, wpa_s->best_5_freq) && freq_included(channels, wpa_s->best_5_freq)) { params->freq = wpa_s->best_5_freq; wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz " "channel %d MHz", params->freq); } else if ((pref_freq = p2p_get_pref_freq(wpa_s->global->p2p, channels))) { params->freq = pref_freq; wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz from preferred " "channels", params->freq); } else { int chan; for (chan = 0; chan < 11; chan++) { params->freq = 2412 + chan * 5; if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) && freq_included(channels, params->freq)) break; } if (chan == 11) { wpa_printf(MSG_DEBUG, "P2P: No 2.4 GHz channel " "allowed"); return -1; } wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference " "known)", params->freq); } freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int)); if (!freqs) return -1; res = wpas_p2p_valid_oper_freqs(wpa_s, freqs, wpa_s->num_multichan_concurrent); if (res < 0) { os_free(freqs); return -1; } num = res; for (i = 0; i < num; i++) { if (freq && freqs[i] == freq) break; if (!freq && freq_included(channels, freqs[i])) { wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)", freqs[i]); params->freq = freqs[i]; break; } } if (i == num) { if (wpas_p2p_num_unused_channels(wpa_s) <= 0) { if (freq) wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq); else wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using"); os_free(freqs); return -1; } else if (num == 0) { wpa_printf(MSG_DEBUG, "P2P: Use one of the free channels"); } else { wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels"); } } os_free(freqs); return 0; } static struct wpa_supplicant * wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, int go) { struct wpa_supplicant *group_wpa_s; if (!wpas_p2p_create_iface(wpa_s)) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group " "operations"); wpa_s->p2p_first_connection_timeout = 0; return wpa_s; } if (wpas_p2p_add_group_interface(wpa_s, go ? WPA_IF_P2P_GO : WPA_IF_P2P_CLIENT) < 0) { wpa_msg_global(wpa_s, MSG_ERROR, "P2P: Failed to add group interface"); return NULL; } group_wpa_s = wpas_p2p_init_group_interface(wpa_s, go); if (group_wpa_s == NULL) { wpa_msg_global(wpa_s, MSG_ERROR, "P2P: Failed to initialize group interface"); wpas_p2p_remove_pending_group_interface(wpa_s); return NULL; } wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s", group_wpa_s->ifname); group_wpa_s->p2p_first_connection_timeout = 0; return group_wpa_s; } /** * wpas_p2p_group_add - Add a new P2P group with local end as Group Owner * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface() * @persistent_group: Whether to create a persistent group * @freq: Frequency for the group or 0 to indicate no hardcoding * @ht40: Start GO with 40 MHz channel width * @vht: Start GO with VHT support * Returns: 0 on success, -1 on failure * * This function creates a new P2P group with the local end as the Group Owner, * i.e., without using Group Owner Negotiation. */ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, int freq, int ht40, int vht) { struct p2p_go_neg_results params; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; os_free(wpa_s->global->add_psk); wpa_s->global->add_psk = NULL; /* Make sure we are not running find during connection establishment */ wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND"); wpas_p2p_stop_find_oper(wpa_s); freq = wpas_p2p_select_go_freq(wpa_s, freq); if (freq < 0) return -1; if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40, vht, NULL)) return -1; if (params.freq && !p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) { wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO " "(%u MHz) is not supported for P2P uses", params.freq); return -1; } p2p_go_params(wpa_s->global->p2p, ¶ms); params.persistent_group = persistent_group; wpa_s = wpas_p2p_get_group_iface(wpa_s, 0, 1); if (wpa_s == NULL) return -1; wpas_start_wps_go(wpa_s, ¶ms, 0); return 0; } static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s, struct wpa_ssid *params, int addr_allocated, int freq) { struct wpa_ssid *ssid; wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 0); if (wpa_s == NULL) return -1; wpa_s->p2p_last_4way_hs_fail = NULL; wpa_supplicant_ap_deinit(wpa_s); ssid = wpa_config_add_network(wpa_s->conf); if (ssid == NULL) return -1; wpa_config_set_network_defaults(ssid); ssid->temporary = 1; ssid->proto = WPA_PROTO_RSN; ssid->pairwise_cipher = WPA_CIPHER_CCMP; ssid->group_cipher = WPA_CIPHER_CCMP; ssid->key_mgmt = WPA_KEY_MGMT_PSK; ssid->ssid = os_malloc(params->ssid_len); if (ssid->ssid == NULL) { wpa_config_remove_network(wpa_s->conf, ssid->id); return -1; } os_memcpy(ssid->ssid, params->ssid, params->ssid_len); ssid->ssid_len = params->ssid_len; ssid->p2p_group = 1; ssid->export_keys = 1; if (params->psk_set) { os_memcpy(ssid->psk, params->psk, 32); ssid->psk_set = 1; } if (params->passphrase) ssid->passphrase = os_strdup(params->passphrase); wpa_s->show_group_started = 1; wpa_s->p2p_in_invitation = 1; wpa_s->p2p_invite_go_freq = freq; eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0, wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); wpa_supplicant_select_network(wpa_s, ssid); return 0; } int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int addr_allocated, int force_freq, int neg_freq, int ht40, int vht, const struct p2p_channels *channels, int connection_timeout) { struct p2p_go_neg_results params; int go = 0, freq; if (ssid->disabled != 2 || ssid->ssid == NULL) return -1; if (wpas_get_p2p_group(wpa_s, ssid->ssid, ssid->ssid_len, &go) && go == (ssid->mode == WPAS_MODE_P2P_GO)) { wpa_printf(MSG_DEBUG, "P2P: Requested persistent group is " "already running"); return 0; } os_free(wpa_s->global->add_psk); wpa_s->global->add_psk = NULL; /* Make sure we are not running find during connection establishment */ wpas_p2p_stop_find_oper(wpa_s); wpa_s->p2p_fallback_to_go_neg = 0; if (force_freq > 0) { freq = wpas_p2p_select_go_freq(wpa_s, force_freq); if (freq < 0) return -1; } else { freq = wpas_p2p_select_go_freq(wpa_s, neg_freq); if (freq < 0 || (freq > 0 && !freq_included(channels, freq))) freq = 0; } if (ssid->mode == WPAS_MODE_INFRA) return wpas_start_p2p_client(wpa_s, ssid, addr_allocated, freq); if (ssid->mode != WPAS_MODE_P2P_GO) return -1; if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40, vht, channels)) return -1; params.role_go = 1; params.psk_set = ssid->psk_set; if (params.psk_set) os_memcpy(params.psk, ssid->psk, sizeof(params.psk)); if (ssid->passphrase) { if (os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) { wpa_printf(MSG_ERROR, "P2P: Invalid passphrase in " "persistent group"); return -1; } os_strlcpy(params.passphrase, ssid->passphrase, sizeof(params.passphrase)); } os_memcpy(params.ssid, ssid->ssid, ssid->ssid_len); params.ssid_len = ssid->ssid_len; params.persistent_group = 1; wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 1); if (wpa_s == NULL) return -1; wpa_s->p2p_first_connection_timeout = connection_timeout; wpas_start_wps_go(wpa_s, ¶ms, 0); return 0; } static void wpas_p2p_ie_update(void *ctx, struct wpabuf *beacon_ies, struct wpabuf *proberesp_ies) { struct wpa_supplicant *wpa_s = ctx; if (wpa_s->ap_iface) { struct hostapd_data *hapd = wpa_s->ap_iface->bss[0]; if (!(hapd->conf->p2p & P2P_GROUP_OWNER)) { wpabuf_free(beacon_ies); wpabuf_free(proberesp_ies); return; } if (beacon_ies) { wpabuf_free(hapd->p2p_beacon_ie); hapd->p2p_beacon_ie = beacon_ies; } wpabuf_free(hapd->p2p_probe_resp_ie); hapd->p2p_probe_resp_ie = proberesp_ies; } else { wpabuf_free(beacon_ies); wpabuf_free(proberesp_ies); } wpa_supplicant_ap_update_beacon(wpa_s); } static void wpas_p2p_idle_update(void *ctx, int idle) { struct wpa_supplicant *wpa_s = ctx; if (!wpa_s->ap_iface) return; wpa_printf(MSG_DEBUG, "P2P: GO - group %sidle", idle ? "" : "not "); if (idle) { if (wpa_s->global->p2p_fail_on_wps_complete && wpa_s->p2p_in_provisioning) { wpas_p2p_grpform_fail_after_wps(wpa_s); return; } wpas_p2p_set_group_idle_timeout(wpa_s); } else eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL); } struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct p2p_group *group; struct p2p_group_config *cfg; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return NULL; cfg = os_zalloc(sizeof(*cfg)); if (cfg == NULL) return NULL; if (ssid->p2p_persistent_group && wpa_s->conf->persistent_reconnect) cfg->persistent_group = 2; else if (ssid->p2p_persistent_group) cfg->persistent_group = 1; os_memcpy(cfg->interface_addr, wpa_s->own_addr, ETH_ALEN); if (wpa_s->max_stations && wpa_s->max_stations < wpa_s->conf->max_num_sta) cfg->max_clients = wpa_s->max_stations; else cfg->max_clients = wpa_s->conf->max_num_sta; os_memcpy(cfg->ssid, ssid->ssid, ssid->ssid_len); cfg->ssid_len = ssid->ssid_len; cfg->freq = ssid->frequency; cfg->cb_ctx = wpa_s; cfg->ie_update = wpas_p2p_ie_update; cfg->idle_update = wpas_p2p_idle_update; group = p2p_group_init(wpa_s->global->p2p, cfg); if (group == NULL) os_free(cfg); if (ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) p2p_group_notif_formation_done(group); wpa_s->p2p_group = group; return group; } void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int registrar) { struct wpa_ssid *ssid = wpa_s->current_ssid; if (!wpa_s->p2p_in_provisioning) { wpa_printf(MSG_DEBUG, "P2P: Ignore WPS success event - P2P " "provisioning not in progress"); return; } if (ssid && ssid->mode == WPAS_MODE_INFRA) { u8 go_dev_addr[ETH_ALEN]; os_memcpy(go_dev_addr, wpa_s->bssid, ETH_ALEN); wpas_p2p_persistent_group(wpa_s, go_dev_addr, ssid->ssid, ssid->ssid_len); /* Clear any stored provisioning info */ p2p_clear_provisioning_info(wpa_s->global->p2p, go_dev_addr); } eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); wpa_s->p2p_go_group_formation_completed = 1; if (ssid && ssid->mode == WPAS_MODE_INFRA) { /* * Use a separate timeout for initial data connection to * complete to allow the group to be removed automatically if * something goes wrong in this step before the P2P group idle * timeout mechanism is taken into use. */ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Re-start group formation timeout (%d seconds) as client for initial connection", P2P_MAX_INITIAL_CONN_WAIT); eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0, wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); } else if (ssid) { /* * Use a separate timeout for initial data connection to * complete to allow the group to be removed automatically if * the client does not complete data connection successfully. */ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Re-start group formation timeout (%d seconds) as GO for initial connection", P2P_MAX_INITIAL_CONN_WAIT_GO); eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT_GO, 0, wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); /* * Complete group formation on first successful data connection */ wpa_s->p2p_go_group_formation_completed = 0; } if (wpa_s->global->p2p) p2p_wps_success_cb(wpa_s->global->p2p, peer_addr); wpas_group_formation_completed(wpa_s, 1); } void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail) { if (!wpa_s->p2p_in_provisioning) { wpa_printf(MSG_DEBUG, "P2P: Ignore WPS fail event - P2P " "provisioning not in progress"); return; } if (wpa_s->go_params) { p2p_clear_provisioning_info( wpa_s->global->p2p, wpa_s->go_params->peer_device_addr); } wpas_notify_p2p_wps_failed(wpa_s, fail); if (wpa_s == wpa_s->global->p2p_group_formation) { /* * Allow some time for the failed WPS negotiation exchange to * complete, but remove the group since group formation cannot * succeed after provisioning failure. */ wpa_printf(MSG_DEBUG, "P2P: WPS step failed during group formation - reject connection from timeout"); wpa_s->global->p2p_fail_on_wps_complete = 1; eloop_deplete_timeout(0, 50000, wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); } } int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s) { if (!wpa_s->global->p2p_fail_on_wps_complete || !wpa_s->p2p_in_provisioning) return 0; wpas_p2p_grpform_fail_after_wps(wpa_s); return 1; } int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, const char *config_method, enum wpas_p2p_prov_disc_use use) { u16 config_methods; wpa_s->p2p_fallback_to_go_neg = 0; wpa_s->pending_pd_use = NORMAL_PD; if (os_strncmp(config_method, "display", 7) == 0) config_methods = WPS_CONFIG_DISPLAY; else if (os_strncmp(config_method, "keypad", 6) == 0) config_methods = WPS_CONFIG_KEYPAD; else if (os_strncmp(config_method, "pbc", 3) == 0 || os_strncmp(config_method, "pushbutton", 10) == 0) config_methods = WPS_CONFIG_PUSHBUTTON; else { wpa_printf(MSG_DEBUG, "P2P: Unknown config method"); return -1; } if (use == WPAS_P2P_PD_AUTO) { os_memcpy(wpa_s->pending_join_dev_addr, peer_addr, ETH_ALEN); wpa_s->pending_pd_config_methods = config_methods; wpa_s->p2p_auto_pd = 1; wpa_s->p2p_auto_join = 0; wpa_s->pending_pd_before_join = 0; wpa_s->auto_pd_scan_retry = 0; wpas_p2p_stop_find(wpa_s); wpa_s->p2p_join_scan_count = 0; os_get_reltime(&wpa_s->p2p_auto_started); wpa_printf(MSG_DEBUG, "P2P: Auto PD started at %ld.%06ld", wpa_s->p2p_auto_started.sec, wpa_s->p2p_auto_started.usec); wpas_p2p_join_scan(wpa_s, NULL); return 0; } if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) return -1; return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr, config_methods, use == WPAS_P2P_PD_FOR_JOIN, 0, 1); } int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end) { return p2p_scan_result_text(ies, ies_len, buf, end); } static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s) { if (!offchannel_pending_action_tx(wpa_s)) return; wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new " "operation request"); offchannel_clear_pending_action_tx(wpa_s); } int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, enum p2p_discovery_type type, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id, unsigned int search_delay) { wpas_p2p_clear_pending_action_tx(wpa_s); wpa_s->p2p_long_listen = 0; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL || wpa_s->p2p_in_provisioning) return -1; wpa_supplicant_cancel_sched_scan(wpa_s); return p2p_find(wpa_s->global->p2p, timeout, type, num_req_dev_types, req_dev_types, dev_id, search_delay); } static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s) { wpas_p2p_clear_pending_action_tx(wpa_s); wpa_s->p2p_long_listen = 0; eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); if (wpa_s->global->p2p) p2p_stop_find(wpa_s->global->p2p); return 0; } void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s) { if (wpas_p2p_stop_find_oper(wpa_s) > 0) return; wpas_p2p_remove_pending_group_interface(wpa_s); } static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; wpa_s->p2p_long_listen = 0; } int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout) { int res; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; wpa_supplicant_cancel_sched_scan(wpa_s); wpas_p2p_clear_pending_action_tx(wpa_s); if (timeout == 0) { /* * This is a request for unlimited Listen state. However, at * least for now, this is mapped to a Listen state for one * hour. */ timeout = 3600; } eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); wpa_s->p2p_long_listen = 0; /* * Stop previous find/listen operation to avoid trying to request a new * remain-on-channel operation while the driver is still running the * previous one. */ if (wpa_s->global->p2p) p2p_stop_find(wpa_s->global->p2p); res = wpas_p2p_listen_start(wpa_s, timeout * 1000); if (res == 0 && timeout * 1000 > wpa_s->max_remain_on_chan) { wpa_s->p2p_long_listen = timeout * 1000; eloop_register_timeout(timeout, 0, wpas_p2p_long_listen_timeout, wpa_s, NULL); } return res; } int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, u8 *buf, size_t len, int p2p_group) { struct wpabuf *p2p_ie; int ret; if (wpa_s->global->p2p_disabled) return -1; if (wpa_s->global->p2p == NULL) return -1; if (bss == NULL) return -1; p2p_ie = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE); ret = p2p_assoc_req_ie(wpa_s->global->p2p, bss->bssid, buf, len, p2p_group, p2p_ie); wpabuf_free(p2p_ie); return ret; } int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *dst, const u8 *bssid, const u8 *ie, size_t ie_len, int ssi_signal) { if (wpa_s->global->p2p_disabled) return 0; if (wpa_s->global->p2p == NULL) return 0; switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid, ie, ie_len)) { case P2P_PREQ_NOT_P2P: wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len, ssi_signal); /* fall through */ case P2P_PREQ_MALFORMED: case P2P_PREQ_NOT_LISTEN: case P2P_PREQ_NOT_PROCESSED: default: /* make gcc happy */ return 0; case P2P_PREQ_PROCESSED: return 1; } } void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da, const u8 *sa, const u8 *bssid, u8 category, const u8 *data, size_t len, int freq) { if (wpa_s->global->p2p_disabled) return; if (wpa_s->global->p2p == NULL) return; p2p_rx_action(wpa_s->global->p2p, da, sa, bssid, category, data, len, freq); } void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies) { if (wpa_s->global->p2p_disabled) return; if (wpa_s->global->p2p == NULL) return; p2p_scan_ie(wpa_s->global->p2p, ies, NULL); } void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s) { p2p_group_deinit(wpa_s->p2p_group); wpa_s->p2p_group = NULL; wpa_s->ap_configured_cb = NULL; wpa_s->ap_configured_cb_ctx = NULL; wpa_s->ap_configured_cb_data = NULL; wpa_s->connect_without_scan = NULL; } int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr) { wpa_s->p2p_long_listen = 0; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; return p2p_reject(wpa_s->global->p2p, addr); } /* Invite to reinvoke a persistent group */ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq, int ht40, int vht, int pref_freq) { enum p2p_invite_role role; u8 *bssid = NULL; int force_freq = 0; int res; int no_pref_freq_given = pref_freq == 0; wpa_s->global->p2p_invite_group = NULL; if (peer_addr) os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN); else os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); wpa_s->p2p_persistent_go_freq = freq; wpa_s->p2p_go_ht40 = !!ht40; if (ssid->mode == WPAS_MODE_P2P_GO) { role = P2P_INVITE_ROLE_GO; if (peer_addr == NULL) { wpa_printf(MSG_DEBUG, "P2P: Missing peer " "address in invitation command"); return -1; } if (wpas_p2p_create_iface(wpa_s)) { if (wpas_p2p_add_group_interface(wpa_s, WPA_IF_P2P_GO) < 0) { wpa_printf(MSG_ERROR, "P2P: Failed to " "allocate a new interface for the " "group"); return -1; } bssid = wpa_s->pending_interface_addr; } else bssid = wpa_s->own_addr; } else { role = P2P_INVITE_ROLE_CLIENT; peer_addr = ssid->bssid; } wpa_s->pending_invite_ssid_id = ssid->id; res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq, role == P2P_INVITE_ROLE_GO); if (res) return res; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; if (wpa_s->parent->conf->p2p_ignore_shared_freq && no_pref_freq_given && pref_freq > 0 && wpa_s->num_multichan_concurrent > 1 && wpas_p2p_num_unused_channels(wpa_s) > 0) { wpa_printf(MSG_DEBUG, "P2P: Ignore own channel preference %d MHz for invitation due to p2p_ignore_shared_freq=1 configuration", pref_freq); pref_freq = 0; } return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid, ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr, 1, pref_freq, -1); } /* Invite to join an active group */ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, const u8 *peer_addr, const u8 *go_dev_addr) { struct wpa_global *global = wpa_s->global; enum p2p_invite_role role; u8 *bssid = NULL; struct wpa_ssid *ssid; int persistent; int freq = 0, force_freq = 0, pref_freq = 0; int res; wpa_s->p2p_persistent_go_freq = 0; wpa_s->p2p_go_ht40 = 0; wpa_s->p2p_go_vht = 0; for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { if (os_strcmp(wpa_s->ifname, ifname) == 0) break; } if (wpa_s == NULL) { wpa_printf(MSG_DEBUG, "P2P: Interface '%s' not found", ifname); return -1; } ssid = wpa_s->current_ssid; if (ssid == NULL) { wpa_printf(MSG_DEBUG, "P2P: No current SSID to use for " "invitation"); return -1; } wpa_s->global->p2p_invite_group = wpa_s; persistent = ssid->p2p_persistent_group && wpas_p2p_get_persistent(wpa_s->parent, peer_addr, ssid->ssid, ssid->ssid_len); if (ssid->mode == WPAS_MODE_P2P_GO) { role = P2P_INVITE_ROLE_ACTIVE_GO; bssid = wpa_s->own_addr; if (go_dev_addr == NULL) go_dev_addr = wpa_s->global->p2p_dev_addr; freq = ssid->frequency; } else { role = P2P_INVITE_ROLE_CLIENT; if (wpa_s->wpa_state < WPA_ASSOCIATED) { wpa_printf(MSG_DEBUG, "P2P: Not associated - cannot " "invite to current group"); return -1; } bssid = wpa_s->bssid; if (go_dev_addr == NULL && !is_zero_ether_addr(wpa_s->go_dev_addr)) go_dev_addr = wpa_s->go_dev_addr; freq = wpa_s->current_bss ? wpa_s->current_bss->freq : (int) wpa_s->assoc_freq; } wpa_s->parent->pending_invite_ssid_id = -1; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq, role == P2P_INVITE_ROLE_ACTIVE_GO); if (res) return res; wpas_p2p_set_own_freq_preference(wpa_s, force_freq); return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid, ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr, persistent, pref_freq, -1); } void wpas_p2p_completed(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid = wpa_s->current_ssid; const char *ssid_txt; u8 go_dev_addr[ETH_ALEN]; int network_id = -1; int persistent; int freq; u8 ip[3 * 4]; char ip_addr[100]; if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) { eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); } if (!wpa_s->show_group_started || !ssid) return; wpa_s->show_group_started = 0; ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len); os_memset(go_dev_addr, 0, ETH_ALEN); if (ssid->bssid_set) os_memcpy(go_dev_addr, ssid->bssid, ETH_ALEN); persistent = wpas_p2p_persistent_group(wpa_s, go_dev_addr, ssid->ssid, ssid->ssid_len); os_memcpy(wpa_s->go_dev_addr, go_dev_addr, ETH_ALEN); if (wpa_s->global->p2p_group_formation == wpa_s) wpa_s->global->p2p_group_formation = NULL; freq = wpa_s->current_bss ? wpa_s->current_bss->freq : (int) wpa_s->assoc_freq; ip_addr[0] = '\0'; if (wpa_sm_get_p2p_ip_addr(wpa_s->wpa, ip) == 0) { os_snprintf(ip_addr, sizeof(ip_addr), " ip_addr=%u.%u.%u.%u " "ip_mask=%u.%u.%u.%u go_ip_addr=%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11]); } if (ssid->passphrase == NULL && ssid->psk_set) { char psk[65]; wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32); wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED "%s client ssid=\"%s\" freq=%d psk=%s " "go_dev_addr=" MACSTR "%s%s", wpa_s->ifname, ssid_txt, freq, psk, MAC2STR(go_dev_addr), persistent ? " [PERSISTENT]" : "", ip_addr); } else { wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED "%s client ssid=\"%s\" freq=%d " "passphrase=\"%s\" go_dev_addr=" MACSTR "%s%s", wpa_s->ifname, ssid_txt, freq, ssid->passphrase ? ssid->passphrase : "", MAC2STR(go_dev_addr), persistent ? " [PERSISTENT]" : "", ip_addr); } if (persistent) network_id = wpas_p2p_store_persistent_group(wpa_s->parent, ssid, go_dev_addr); if (network_id < 0) network_id = ssid->id; wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1); } int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1, u32 interval1, u32 duration2, u32 interval2) { int ret; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; if (wpa_s->wpa_state < WPA_ASSOCIATED || wpa_s->current_ssid == NULL || wpa_s->current_ssid->mode != WPAS_MODE_INFRA) return -1; ret = p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid, wpa_s->own_addr, wpa_s->assoc_freq, duration1, interval1, duration2, interval2); if (ret == 0) wpa_s->waiting_presence_resp = 1; return ret; } int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period, unsigned int interval) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; return p2p_ext_listen(wpa_s->global->p2p, period, interval); } static int wpas_p2p_is_client(struct wpa_supplicant *wpa_s) { if (wpa_s->current_ssid == NULL) { /* * current_ssid can be cleared when P2P client interface gets * disconnected, so assume this interface was used as P2P * client. */ return 1; } return wpa_s->current_ssid->p2p_group && wpa_s->current_ssid->mode == WPAS_MODE_INFRA; } static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; if (wpa_s->conf->p2p_group_idle == 0 && !wpas_p2p_is_client(wpa_s)) { wpa_printf(MSG_DEBUG, "P2P: Ignore group idle timeout - " "disabled"); return; } wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate " "group"); wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_IDLE_TIMEOUT); } static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s) { int timeout; if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0) wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout"); if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group) return; timeout = wpa_s->conf->p2p_group_idle; if (wpa_s->current_ssid->mode == WPAS_MODE_INFRA && (timeout == 0 || timeout > P2P_MAX_CLIENT_IDLE)) timeout = P2P_MAX_CLIENT_IDLE; if (timeout == 0) return; if (timeout < 0) { if (wpa_s->current_ssid->mode == WPAS_MODE_INFRA) timeout = 0; /* special client mode no-timeout */ else return; } if (wpa_s->p2p_in_provisioning) { /* * Use the normal group formation timeout during the * provisioning phase to avoid terminating this process too * early due to group idle timeout. */ wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout " "during provisioning"); return; } if (wpa_s->show_group_started) { /* * Use the normal group formation timeout between the end of * the provisioning phase and completion of 4-way handshake to * avoid terminating this process too early due to group idle * timeout. */ wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout " "while waiting for initial 4-way handshake to " "complete"); return; } wpa_printf(MSG_DEBUG, "P2P: Set P2P group idle timeout to %u seconds", timeout); eloop_register_timeout(timeout, 0, wpas_p2p_group_idle_timeout, wpa_s, NULL); } /* Returns 1 if the interface was removed */ int wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, u16 reason_code, const u8 *ie, size_t ie_len, int locally_generated) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return 0; if (!locally_generated) p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len); if (reason_code == WLAN_REASON_DEAUTH_LEAVING && !locally_generated && wpa_s->current_ssid && wpa_s->current_ssid->p2p_group && wpa_s->current_ssid->mode == WPAS_MODE_INFRA) { wpa_printf(MSG_DEBUG, "P2P: GO indicated that the P2P Group " "session is ending"); if (wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_GO_ENDING_SESSION) > 0) return 1; } return 0; } void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, u16 reason_code, const u8 *ie, size_t ie_len, int locally_generated) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; if (!locally_generated) p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len); } void wpas_p2p_update_config(struct wpa_supplicant *wpa_s) { struct p2p_data *p2p = wpa_s->global->p2p; if (p2p == NULL) return; if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE)) return; if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_NAME) p2p_set_dev_name(p2p, wpa_s->conf->device_name); if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE) p2p_set_pri_dev_type(p2p, wpa_s->conf->device_type); if (wpa_s->wps && (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS)) p2p_set_config_methods(p2p, wpa_s->wps->config_methods); if (wpa_s->wps && (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID)) p2p_set_uuid(p2p, wpa_s->wps->uuid); if (wpa_s->conf->changed_parameters & CFG_CHANGED_WPS_STRING) { p2p_set_manufacturer(p2p, wpa_s->conf->manufacturer); p2p_set_model_name(p2p, wpa_s->conf->model_name); p2p_set_model_number(p2p, wpa_s->conf->model_number); p2p_set_serial_number(p2p, wpa_s->conf->serial_number); } if (wpa_s->conf->changed_parameters & CFG_CHANGED_SEC_DEVICE_TYPE) p2p_set_sec_dev_types(p2p, (void *) wpa_s->conf->sec_device_type, wpa_s->conf->num_sec_device_types); if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION) { int i; p2p_remove_wps_vendor_extensions(p2p); for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) { if (wpa_s->conf->wps_vendor_ext[i] == NULL) continue; p2p_add_wps_vendor_extension( p2p, wpa_s->conf->wps_vendor_ext[i]); } } if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) && wpa_s->conf->country[0] && wpa_s->conf->country[1]) { char country[3]; country[0] = wpa_s->conf->country[0]; country[1] = wpa_s->conf->country[1]; country[2] = 0x04; p2p_set_country(p2p, country); } if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_SSID_POSTFIX) { p2p_set_ssid_postfix(p2p, (u8 *) wpa_s->conf->p2p_ssid_postfix, wpa_s->conf->p2p_ssid_postfix ? os_strlen(wpa_s->conf->p2p_ssid_postfix) : 0); } if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_INTRA_BSS) p2p_set_intra_bss_dist(p2p, wpa_s->conf->p2p_intra_bss); if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_LISTEN_CHANNEL) { u8 reg_class, channel; int ret; unsigned int r; if (wpa_s->conf->p2p_listen_reg_class && wpa_s->conf->p2p_listen_channel) { reg_class = wpa_s->conf->p2p_listen_reg_class; channel = wpa_s->conf->p2p_listen_channel; } else { reg_class = 81; /* * Pick one of the social channels randomly as the * listen channel. */ os_get_random((u8 *) &r, sizeof(r)); channel = 1 + (r % 3) * 5; } ret = p2p_set_listen_channel(p2p, reg_class, channel); if (ret) wpa_printf(MSG_ERROR, "P2P: Own listen channel update " "failed: %d", ret); } if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_OPER_CHANNEL) { u8 op_reg_class, op_channel, cfg_op_channel; int ret = 0; unsigned int r; if (wpa_s->conf->p2p_oper_reg_class && wpa_s->conf->p2p_oper_channel) { op_reg_class = wpa_s->conf->p2p_oper_reg_class; op_channel = wpa_s->conf->p2p_oper_channel; cfg_op_channel = 1; } else { op_reg_class = 81; /* * Use random operation channel from (1, 6, 11) *if no other preference is indicated. */ os_get_random((u8 *) &r, sizeof(r)); op_channel = 1 + (r % 3) * 5; cfg_op_channel = 0; } ret = p2p_set_oper_channel(p2p, op_reg_class, op_channel, cfg_op_channel); if (ret) wpa_printf(MSG_ERROR, "P2P: Own oper channel update " "failed: %d", ret); } if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_PREF_CHAN) { if (p2p_set_pref_chan(p2p, wpa_s->conf->num_p2p_pref_chan, wpa_s->conf->p2p_pref_chan) < 0) { wpa_printf(MSG_ERROR, "P2P: Preferred channel list " "update failed"); } if (p2p_set_no_go_freq(p2p, &wpa_s->conf->p2p_no_go_freq) < 0) { wpa_printf(MSG_ERROR, "P2P: No GO channel list " "update failed"); } } } int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start, int duration) { if (!wpa_s->ap_iface) return -1; return hostapd_p2p_set_noa(wpa_s->ap_iface->bss[0], count, start, duration); } int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; wpa_s->global->cross_connection = enabled; p2p_set_cross_connect(wpa_s->global->p2p, enabled); if (!enabled) { struct wpa_supplicant *iface; for (iface = wpa_s->global->ifaces; iface; iface = iface->next) { if (iface->cross_connect_enabled == 0) continue; iface->cross_connect_enabled = 0; iface->cross_connect_in_use = 0; wpa_msg_global(iface->parent, MSG_INFO, P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s", iface->ifname, iface->cross_connect_uplink); } } return 0; } static void wpas_p2p_enable_cross_connect(struct wpa_supplicant *uplink) { struct wpa_supplicant *iface; if (!uplink->global->cross_connection) return; for (iface = uplink->global->ifaces; iface; iface = iface->next) { if (!iface->cross_connect_enabled) continue; if (os_strcmp(uplink->ifname, iface->cross_connect_uplink) != 0) continue; if (iface->ap_iface == NULL) continue; if (iface->cross_connect_in_use) continue; iface->cross_connect_in_use = 1; wpa_msg_global(iface->parent, MSG_INFO, P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s", iface->ifname, iface->cross_connect_uplink); } } static void wpas_p2p_disable_cross_connect(struct wpa_supplicant *uplink) { struct wpa_supplicant *iface; for (iface = uplink->global->ifaces; iface; iface = iface->next) { if (!iface->cross_connect_enabled) continue; if (os_strcmp(uplink->ifname, iface->cross_connect_uplink) != 0) continue; if (!iface->cross_connect_in_use) continue; wpa_msg_global(iface->parent, MSG_INFO, P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s", iface->ifname, iface->cross_connect_uplink); iface->cross_connect_in_use = 0; } } void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s) { if (wpa_s->ap_iface || wpa_s->current_ssid == NULL || wpa_s->current_ssid->mode != WPAS_MODE_INFRA || wpa_s->cross_connect_disallowed) wpas_p2p_disable_cross_connect(wpa_s); else wpas_p2p_enable_cross_connect(wpa_s); if (!wpa_s->ap_iface && eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0) wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout"); } void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s) { wpas_p2p_disable_cross_connect(wpa_s); if (!wpa_s->ap_iface && !eloop_is_timeout_registered(wpas_p2p_group_idle_timeout, wpa_s, NULL)) wpas_p2p_set_group_idle_timeout(wpa_s); } static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s) { struct wpa_supplicant *iface; if (!wpa_s->global->cross_connection) return; for (iface = wpa_s->global->ifaces; iface; iface = iface->next) { if (iface == wpa_s) continue; if (iface->drv_flags & WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE) continue; if (iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) continue; wpa_s->cross_connect_enabled = 1; os_strlcpy(wpa_s->cross_connect_uplink, iface->ifname, sizeof(wpa_s->cross_connect_uplink)); wpa_printf(MSG_DEBUG, "P2P: Enable cross connection from " "%s to %s whenever uplink is available", wpa_s->ifname, wpa_s->cross_connect_uplink); if (iface->ap_iface || iface->current_ssid == NULL || iface->current_ssid->mode != WPAS_MODE_INFRA || iface->cross_connect_disallowed || iface->wpa_state != WPA_COMPLETED) break; wpa_s->cross_connect_in_use = 1; wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s", wpa_s->ifname, wpa_s->cross_connect_uplink); break; } } int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s) { if (wpa_s->p2p_group_interface != P2P_GROUP_INTERFACE_CLIENT && !wpa_s->p2p_in_provisioning) return 0; /* not P2P client operation */ wpa_printf(MSG_DEBUG, "P2P: Terminate connection due to WPS PBC " "session overlap"); if (wpa_s != wpa_s->parent) wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP); wpas_p2p_group_formation_failed(wpa_s); return 1; } void wpas_p2p_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; wpas_p2p_notif_pbc_overlap(wpa_s); } void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s) { struct p2p_channels chan, cli_chan; struct wpa_supplicant *ifs; if (wpa_s->global == NULL || wpa_s->global->p2p == NULL) return; os_memset(&chan, 0, sizeof(chan)); os_memset(&cli_chan, 0, sizeof(cli_chan)); if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan)) { wpa_printf(MSG_ERROR, "P2P: Failed to update supported " "channel list"); return; } p2p_update_channel_list(wpa_s->global->p2p, &chan, &cli_chan); for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) { int freq; if (!ifs->current_ssid || !ifs->current_ssid->p2p_group || (ifs->current_ssid->mode != WPAS_MODE_P2P_GO && ifs->current_ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)) continue; freq = ifs->current_ssid->frequency; if (freq_included(&chan, freq)) { wpa_dbg(ifs, MSG_DEBUG, "P2P GO operating frequency %d MHz in valid range", freq); continue; } wpa_dbg(ifs, MSG_DEBUG, "P2P GO operating in invalid frequency %d MHz", freq); /* TODO: Consider using CSA or removing the group within * wpa_supplicant */ wpa_msg(ifs, MSG_INFO, P2P_EVENT_REMOVE_AND_REFORM_GROUP); } } static void wpas_p2p_scan_res_ignore(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { wpa_printf(MSG_DEBUG, "P2P: Ignore scan results"); } int wpas_p2p_cancel(struct wpa_supplicant *wpa_s) { struct wpa_global *global = wpa_s->global; int found = 0; const u8 *peer; if (global->p2p == NULL) return -1; wpa_printf(MSG_DEBUG, "P2P: Request to cancel group formation"); if (wpa_s->pending_interface_name[0] && !is_zero_ether_addr(wpa_s->pending_interface_addr)) found = 1; peer = p2p_get_go_neg_peer(global->p2p); if (peer) { wpa_printf(MSG_DEBUG, "P2P: Unauthorize pending GO Neg peer " MACSTR, MAC2STR(peer)); p2p_unauthorize(global->p2p, peer); found = 1; } if (wpa_s->scan_res_handler == wpas_p2p_scan_res_join) { wpa_printf(MSG_DEBUG, "P2P: Stop pending scan for join"); wpa_s->scan_res_handler = wpas_p2p_scan_res_ignore; found = 1; } if (wpa_s->pending_pd_before_join) { wpa_printf(MSG_DEBUG, "P2P: Stop pending PD before join"); wpa_s->pending_pd_before_join = 0; found = 1; } wpas_p2p_stop_find(wpa_s); for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { if (wpa_s == global->p2p_group_formation && (wpa_s->p2p_in_provisioning || wpa_s->parent->pending_interface_type == WPA_IF_P2P_CLIENT)) { wpa_printf(MSG_DEBUG, "P2P: Interface %s in group " "formation found - cancelling", wpa_s->ifname); found = 1; eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); if (wpa_s->p2p_in_provisioning) { wpas_group_formation_completed(wpa_s, 0); break; } wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_REQUESTED); break; } else if (wpa_s->p2p_in_invitation) { wpa_printf(MSG_DEBUG, "P2P: Interface %s in invitation found - cancelling", wpa_s->ifname); found = 1; wpas_p2p_group_formation_failed(wpa_s); } } if (!found) { wpa_printf(MSG_DEBUG, "P2P: No ongoing group formation found"); return -1; } return 0; } void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s) { if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group) return; wpa_printf(MSG_DEBUG, "P2P: Remove group due to driver resource not " "being available anymore"); wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_UNAVAILABLE); } void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s, int freq_24, int freq_5, int freq_overall) { struct p2p_data *p2p = wpa_s->global->p2p; if (p2p == NULL) return; p2p_set_best_channels(p2p, freq_24, freq_5, freq_overall); } int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr) { u8 peer[ETH_ALEN]; struct p2p_data *p2p = wpa_s->global->p2p; if (p2p == NULL) return -1; if (hwaddr_aton(addr, peer)) return -1; return p2p_unauthorize(p2p, peer); } /** * wpas_p2p_disconnect - Disconnect from a P2P Group * @wpa_s: Pointer to wpa_supplicant data * Returns: 0 on success, -1 on failure * * This can be used to disconnect from a group in which the local end is a P2P * Client or to end a P2P Group in case the local end is the Group Owner. If a * virtual network interface was created for this group, that interface will be * removed. Otherwise, only the configured P2P group network will be removed * from the interface. */ int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s) { if (wpa_s == NULL) return -1; return wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_REQUESTED) < 0 ? -1 : 0; } int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s) { int ret; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return 0; ret = p2p_in_progress(wpa_s->global->p2p); if (ret == 0) { /* * Check whether there is an ongoing WPS provisioning step (or * other parts of group formation) on another interface since * p2p_in_progress() does not report this to avoid issues for * scans during such provisioning step. */ if (wpa_s->global->p2p_group_formation && wpa_s->global->p2p_group_formation != wpa_s) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Another interface (%s) " "in group formation", wpa_s->global->p2p_group_formation->ifname); ret = 1; } } if (!ret && wpa_s->global->p2p_go_wait_client.sec) { struct os_reltime now; os_get_reltime(&now); if (os_reltime_expired(&now, &wpa_s->global->p2p_go_wait_client, P2P_MAX_INITIAL_CONN_WAIT_GO)) { /* Wait for the first client has expired */ wpa_s->global->p2p_go_wait_client.sec = 0; } else { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Waiting for initial client connection during group formation"); ret = 1; } } return ret; } void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { if (wpa_s->p2p_in_provisioning && ssid->p2p_group && eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL) > 0) { /** * Remove the network by scheduling the group formation * timeout to happen immediately. The teardown code * needs to be scheduled to run asynch later so that we * don't delete data from under ourselves unexpectedly. * Calling wpas_p2p_group_formation_timeout directly * causes a series of crashes in WPS failure scenarios. */ wpa_printf(MSG_DEBUG, "P2P: Canceled group formation due to " "P2P group network getting removed"); eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout, wpa_s->parent, NULL); } } struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *ssid, size_t ssid_len) { struct wpa_ssid *s; size_t i; for (s = wpa_s->conf->ssid; s; s = s->next) { if (s->disabled != 2) continue; if (ssid && (ssid_len != s->ssid_len || os_memcmp(ssid, s->ssid, ssid_len) != 0)) continue; if (addr == NULL) { if (s->mode == WPAS_MODE_P2P_GO) return s; continue; } if (os_memcmp(s->bssid, addr, ETH_ALEN) == 0) return s; /* peer is GO in the persistent group */ if (s->mode != WPAS_MODE_P2P_GO || s->p2p_client_list == NULL) continue; for (i = 0; i < s->num_p2p_clients; i++) { if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, addr, ETH_ALEN) == 0) return s; /* peer is P2P client in persistent * group */ } } return NULL; } void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *addr) { if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, NULL) > 0) { /* * This can happen if WPS provisioning step is not terminated * cleanly (e.g., P2P Client does not send WSC_Done). Since the * peer was able to connect, there is no need to time out group * formation after this, though. In addition, this is used with * the initial connection wait on the GO as a separate formation * timeout and as such, expected to be hit after the initial WPS * provisioning step. */ wpa_printf(MSG_DEBUG, "P2P: Canceled P2P group formation timeout on data connection"); } if (!wpa_s->p2p_go_group_formation_completed) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Marking group formation completed on GO on first data connection"); wpa_s->p2p_go_group_formation_completed = 1; wpa_s->global->p2p_group_formation = NULL; wpa_s->p2p_in_provisioning = 0; wpa_s->p2p_in_invitation = 0; } wpa_s->global->p2p_go_wait_client.sec = 0; if (addr == NULL) return; wpas_p2p_add_persistent_group_client(wpa_s, addr); } static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, int group_added) { struct wpa_supplicant *group = wpa_s; if (wpa_s->global->p2p_group_formation) group = wpa_s->global->p2p_group_formation; wpa_s = wpa_s->parent; offchannel_send_action_done(wpa_s); if (group_added) wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT); wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation"); wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin, wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0, 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq, wpa_s->p2p_persistent_id, wpa_s->p2p_pd_before_go_neg, wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht); } int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s) { if (!wpa_s->p2p_fallback_to_go_neg || wpa_s->p2p_in_provisioning <= 5) return 0; if (wpas_p2p_peer_go(wpa_s, wpa_s->pending_join_dev_addr) > 0) return 0; /* peer operating as a GO */ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - " "fallback to GO Negotiation"); wpas_p2p_fallback_to_go_neg(wpa_s, 1); return 1; } unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s) { struct wpa_supplicant *ifs; if (wpa_s->wpa_state > WPA_SCANNING) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search delay due to " "concurrent operation", P2P_CONCURRENT_SEARCH_DELAY); return P2P_CONCURRENT_SEARCH_DELAY; } dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant, radio_list) { if (ifs != wpa_s && ifs->wpa_state > WPA_SCANNING) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search " "delay due to concurrent operation on " "interface %s", P2P_CONCURRENT_SEARCH_DELAY, ifs->ifname); return P2P_CONCURRENT_SEARCH_DELAY; } } return 0; } static int wpas_p2p_remove_psk_entry(struct wpa_supplicant *wpa_s, struct wpa_ssid *s, const u8 *addr, int iface_addr) { struct psk_list_entry *psk, *tmp; int changed = 0; dl_list_for_each_safe(psk, tmp, &s->psk_list, struct psk_list_entry, list) { if ((iface_addr && !psk->p2p && os_memcmp(addr, psk->addr, ETH_ALEN) == 0) || (!iface_addr && psk->p2p && os_memcmp(addr, psk->addr, ETH_ALEN) == 0)) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove persistent group PSK list entry for " MACSTR " p2p=%u", MAC2STR(psk->addr), psk->p2p); dl_list_del(&psk->list); os_free(psk); changed++; } } return changed; } void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr, const u8 *p2p_dev_addr, const u8 *psk, size_t psk_len) { struct wpa_ssid *ssid = wpa_s->current_ssid; struct wpa_ssid *persistent; struct psk_list_entry *p, *last; if (psk_len != sizeof(p->psk)) return; if (p2p_dev_addr) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: New PSK for addr=" MACSTR " p2p_dev_addr=" MACSTR, MAC2STR(mac_addr), MAC2STR(p2p_dev_addr)); if (is_zero_ether_addr(p2p_dev_addr)) p2p_dev_addr = NULL; } else { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: New PSK for addr=" MACSTR, MAC2STR(mac_addr)); } if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: new_psk_cb during group formation"); /* To be added to persistent group once created */ if (wpa_s->global->add_psk == NULL) { wpa_s->global->add_psk = os_zalloc(sizeof(*p)); if (wpa_s->global->add_psk == NULL) return; } p = wpa_s->global->add_psk; if (p2p_dev_addr) { p->p2p = 1; os_memcpy(p->addr, p2p_dev_addr, ETH_ALEN); } else { p->p2p = 0; os_memcpy(p->addr, mac_addr, ETH_ALEN); } os_memcpy(p->psk, psk, psk_len); return; } if (ssid->mode != WPAS_MODE_P2P_GO || !ssid->p2p_persistent_group) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Ignore new_psk_cb on not-persistent GO"); return; } persistent = wpas_p2p_get_persistent(wpa_s->parent, NULL, ssid->ssid, ssid->ssid_len); if (!persistent) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not find persistent group information to store the new PSK"); return; } p = os_zalloc(sizeof(*p)); if (p == NULL) return; if (p2p_dev_addr) { p->p2p = 1; os_memcpy(p->addr, p2p_dev_addr, ETH_ALEN); } else { p->p2p = 0; os_memcpy(p->addr, mac_addr, ETH_ALEN); } os_memcpy(p->psk, psk, psk_len); if (dl_list_len(&persistent->psk_list) > P2P_MAX_STORED_CLIENTS && (last = dl_list_last(&persistent->psk_list, struct psk_list_entry, list))) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove oldest PSK entry for " MACSTR " (p2p=%u) to make room for a new one", MAC2STR(last->addr), last->p2p); dl_list_del(&last->list); os_free(last); } wpas_p2p_remove_psk_entry(wpa_s->parent, persistent, p2p_dev_addr ? p2p_dev_addr : mac_addr, p2p_dev_addr == NULL); if (p2p_dev_addr) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Add new PSK for p2p_dev_addr=" MACSTR, MAC2STR(p2p_dev_addr)); } else { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Add new PSK for addr=" MACSTR, MAC2STR(mac_addr)); } dl_list_add(&persistent->psk_list, &p->list); if (wpa_s->parent->conf->update_config && wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf)) wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration"); } static void wpas_p2p_remove_psk(struct wpa_supplicant *wpa_s, struct wpa_ssid *s, const u8 *addr, int iface_addr) { int res; res = wpas_p2p_remove_psk_entry(wpa_s, s, addr, iface_addr); if (res > 0 && wpa_s->conf->update_config && wpa_config_write(wpa_s->confname, wpa_s->conf)) wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Failed to update configuration"); } static void wpas_p2p_remove_client_go(struct wpa_supplicant *wpa_s, const u8 *peer, int iface_addr) { struct hostapd_data *hapd; struct hostapd_wpa_psk *psk, *prev, *rem; struct sta_info *sta; if (wpa_s->ap_iface == NULL || wpa_s->current_ssid == NULL || wpa_s->current_ssid->mode != WPAS_MODE_P2P_GO) return; /* Remove per-station PSK entry */ hapd = wpa_s->ap_iface->bss[0]; prev = NULL; psk = hapd->conf->ssid.wpa_psk; while (psk) { if ((iface_addr && os_memcmp(peer, psk->addr, ETH_ALEN) == 0) || (!iface_addr && os_memcmp(peer, psk->p2p_dev_addr, ETH_ALEN) == 0)) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove operating group PSK entry for " MACSTR " iface_addr=%d", MAC2STR(peer), iface_addr); if (prev) prev->next = psk->next; else hapd->conf->ssid.wpa_psk = psk->next; rem = psk; psk = psk->next; os_free(rem); } else { prev = psk; psk = psk->next; } } /* Disconnect from group */ if (iface_addr) sta = ap_get_sta(hapd, peer); else sta = ap_get_sta_p2p(hapd, peer); if (sta) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disconnect peer " MACSTR " (iface_addr=%d) from group", MAC2STR(peer), iface_addr); hostapd_drv_sta_deauth(hapd, sta->addr, WLAN_REASON_DEAUTH_LEAVING); ap_sta_deauthenticate(hapd, sta, WLAN_REASON_DEAUTH_LEAVING); } } void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer, int iface_addr) { struct wpa_ssid *s; struct wpa_supplicant *w; wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove client " MACSTR, MAC2STR(peer)); /* Remove from any persistent group */ for (s = wpa_s->parent->conf->ssid; s; s = s->next) { if (s->disabled != 2 || s->mode != WPAS_MODE_P2P_GO) continue; if (!iface_addr) wpas_remove_persistent_peer(wpa_s, s, peer, 0); wpas_p2p_remove_psk(wpa_s->parent, s, peer, iface_addr); } /* Remove from any operating group */ for (w = wpa_s->global->ifaces; w; w = w->next) wpas_p2p_remove_client_go(w, peer, iface_addr); } static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_PSK_FAILURE); } static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - terminate group"); wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_FREQ_CONFLICT); } int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq, struct wpa_ssid *ssid) { struct wpa_supplicant *iface; for (iface = wpa_s->global->ifaces; iface; iface = iface->next) { if (!iface->current_ssid || iface->current_ssid->frequency == freq || (iface->p2p_group_interface == NOT_P2P_GROUP_INTERFACE && !iface->current_ssid->p2p_group)) continue; /* Remove the connection with least priority */ if (!wpas_is_p2p_prioritized(iface)) { /* STA connection has priority over existing * P2P connection, so remove the interface. */ wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to single channel concurrent mode frequency conflict"); eloop_register_timeout(0, 0, wpas_p2p_group_freq_conflict, iface, NULL); /* If connection in progress is P2P connection, do not * proceed for the connection. */ if (wpa_s == iface) return -1; else return 0; } else { /* P2P connection has priority, disable the STA network */ wpa_supplicant_disable_network(wpa_s->global->ifaces, ssid); wpa_msg(wpa_s->global->ifaces, MSG_INFO, WPA_EVENT_FREQ_CONFLICT " id=%d", ssid->id); os_memset(wpa_s->global->ifaces->pending_bssid, 0, ETH_ALEN); /* If P2P connection is in progress, continue * connecting...*/ if (wpa_s == iface) return 0; else return -1; } } return 0; } int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid = wpa_s->current_ssid; if (ssid == NULL || !ssid->p2p_group) return 0; if (wpa_s->p2p_last_4way_hs_fail && wpa_s->p2p_last_4way_hs_fail == ssid) { u8 go_dev_addr[ETH_ALEN]; struct wpa_ssid *persistent; if (wpas_p2p_persistent_group(wpa_s, go_dev_addr, ssid->ssid, ssid->ssid_len) <= 0) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not determine whether 4-way handshake failures were for a persistent group"); goto disconnect; } wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Two 4-way handshake failures for a P2P group - go_dev_addr=" MACSTR, MAC2STR(go_dev_addr)); persistent = wpas_p2p_get_persistent(wpa_s->parent, go_dev_addr, ssid->ssid, ssid->ssid_len); if (persistent == NULL || persistent->mode != WPAS_MODE_INFRA) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No matching persistent group stored"); goto disconnect; } wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_PERSISTENT_PSK_FAIL "%d", persistent->id); disconnect: wpa_s->p2p_last_4way_hs_fail = NULL; /* * Remove the group from a timeout to avoid issues with caller * continuing to use the interface if this is on a P2P group * interface. */ eloop_register_timeout(0, 0, wpas_p2p_psk_failure_removal, wpa_s, NULL); return 1; } wpa_s->p2p_last_4way_hs_fail = ssid; return 0; } #ifdef CONFIG_WPS_NFC static struct wpabuf * wpas_p2p_nfc_handover(int ndef, struct wpabuf *wsc, struct wpabuf *p2p) { struct wpabuf *ret; size_t wsc_len; if (p2p == NULL) { wpabuf_free(wsc); wpa_printf(MSG_DEBUG, "P2P: No p2p buffer for handover"); return NULL; } wsc_len = wsc ? wpabuf_len(wsc) : 0; ret = wpabuf_alloc(2 + wsc_len + 2 + wpabuf_len(p2p)); if (ret == NULL) { wpabuf_free(wsc); wpabuf_free(p2p); return NULL; } wpabuf_put_be16(ret, wsc_len); if (wsc) wpabuf_put_buf(ret, wsc); wpabuf_put_be16(ret, wpabuf_len(p2p)); wpabuf_put_buf(ret, p2p); wpabuf_free(wsc); wpabuf_free(p2p); wpa_hexdump_buf(MSG_DEBUG, "P2P: Generated NFC connection handover message", ret); if (ndef && ret) { struct wpabuf *tmp; tmp = ndef_build_p2p(ret); wpabuf_free(ret); if (tmp == NULL) { wpa_printf(MSG_DEBUG, "P2P: Failed to NDEF encapsulate handover request"); return NULL; } ret = tmp; } return ret; } static int wpas_p2p_cli_freq(struct wpa_supplicant *wpa_s, struct wpa_ssid **ssid, u8 *go_dev_addr) { struct wpa_supplicant *iface; if (go_dev_addr) os_memset(go_dev_addr, 0, ETH_ALEN); if (ssid) *ssid = NULL; for (iface = wpa_s->global->ifaces; iface; iface = iface->next) { if (iface->wpa_state < WPA_ASSOCIATING || iface->current_ssid == NULL || iface->assoc_freq == 0 || !iface->current_ssid->p2p_group || iface->current_ssid->mode != WPAS_MODE_INFRA) continue; if (ssid) *ssid = iface->current_ssid; if (go_dev_addr) os_memcpy(go_dev_addr, iface->go_dev_addr, ETH_ALEN); return iface->assoc_freq; } return 0; } struct wpabuf * wpas_p2p_nfc_handover_req(struct wpa_supplicant *wpa_s, int ndef) { struct wpabuf *wsc, *p2p; struct wpa_ssid *ssid; u8 go_dev_addr[ETH_ALEN]; int cli_freq = wpas_p2p_cli_freq(wpa_s, &ssid, go_dev_addr); if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) { wpa_printf(MSG_DEBUG, "P2P: P2P disabled - cannot build handover request"); return NULL; } if (wpa_s->conf->wps_nfc_dh_pubkey == NULL && wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey, &wpa_s->conf->wps_nfc_dh_privkey) < 0) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No DH key available for handover request"); return NULL; } if (cli_freq == 0) { wsc = wps_build_nfc_handover_req_p2p( wpa_s->parent->wps, wpa_s->conf->wps_nfc_dh_pubkey); } else wsc = NULL; p2p = p2p_build_nfc_handover_req(wpa_s->global->p2p, cli_freq, go_dev_addr, ssid ? ssid->ssid : NULL, ssid ? ssid->ssid_len : 0); return wpas_p2p_nfc_handover(ndef, wsc, p2p); } struct wpabuf * wpas_p2p_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef, int tag) { struct wpabuf *wsc, *p2p; struct wpa_ssid *ssid; u8 go_dev_addr[ETH_ALEN]; int cli_freq = wpas_p2p_cli_freq(wpa_s, &ssid, go_dev_addr); if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return NULL; if (!tag && wpa_s->conf->wps_nfc_dh_pubkey == NULL && wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey, &wpa_s->conf->wps_nfc_dh_privkey) < 0) return NULL; if (cli_freq == 0) { wsc = wps_build_nfc_handover_sel_p2p( wpa_s->parent->wps, tag ? wpa_s->conf->wps_nfc_dev_pw_id : DEV_PW_NFC_CONNECTION_HANDOVER, wpa_s->conf->wps_nfc_dh_pubkey, tag ? wpa_s->conf->wps_nfc_dev_pw : NULL); } else wsc = NULL; p2p = p2p_build_nfc_handover_sel(wpa_s->global->p2p, cli_freq, go_dev_addr, ssid ? ssid->ssid : NULL, ssid ? ssid->ssid_len : 0); return wpas_p2p_nfc_handover(ndef, wsc, p2p); } static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s, struct p2p_nfc_params *params) { wpa_printf(MSG_DEBUG, "P2P: Initiate join-group based on NFC " "connection handover (freq=%d)", params->go_freq); if (params->go_freq && params->go_ssid_len) { wpa_s->p2p_wps_method = WPS_NFC; wpa_s->pending_join_wps_method = WPS_NFC; os_memset(wpa_s->pending_join_iface_addr, 0, ETH_ALEN); os_memcpy(wpa_s->pending_join_dev_addr, params->go_dev_addr, ETH_ALEN); return wpas_p2p_join_start(wpa_s, params->go_freq, params->go_ssid, params->go_ssid_len); } return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL, WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent, params->go_freq, -1, 0, 1, 1); } static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s, struct p2p_nfc_params *params, int tag) { int res, persistent; struct wpa_ssid *ssid; wpa_printf(MSG_DEBUG, "P2P: Authorize join-group based on NFC " "connection handover"); for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) { ssid = wpa_s->current_ssid; if (ssid == NULL) continue; if (ssid->mode != WPAS_MODE_P2P_GO) continue; if (wpa_s->ap_iface == NULL) continue; break; } if (wpa_s == NULL) { wpa_printf(MSG_DEBUG, "P2P: Could not find GO interface"); return -1; } if (wpa_s->parent->p2p_oob_dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && !wpa_s->parent->p2p_oob_dev_pw) { wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known"); return -1; } res = wpas_ap_wps_add_nfc_pw( wpa_s, wpa_s->parent->p2p_oob_dev_pw_id, wpa_s->parent->p2p_oob_dev_pw, wpa_s->parent->p2p_peer_oob_pk_hash_known ? wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL); if (res) return res; if (!tag) { wpa_printf(MSG_DEBUG, "P2P: Negotiated handover - wait for peer to join without invitation"); return 0; } if (!params->peer || !(params->peer->dev_capab & P2P_DEV_CAPAB_INVITATION_PROCEDURE)) return 0; wpa_printf(MSG_DEBUG, "P2P: Static handover - invite peer " MACSTR " to join", MAC2STR(params->peer->p2p_device_addr)); wpa_s->global->p2p_invite_group = wpa_s; persistent = ssid->p2p_persistent_group && wpas_p2p_get_persistent(wpa_s->parent, params->peer->p2p_device_addr, ssid->ssid, ssid->ssid_len); wpa_s->parent->pending_invite_ssid_id = -1; return p2p_invite(wpa_s->global->p2p, params->peer->p2p_device_addr, P2P_INVITE_ROLE_ACTIVE_GO, wpa_s->own_addr, ssid->ssid, ssid->ssid_len, ssid->frequency, wpa_s->global->p2p_dev_addr, persistent, 0, wpa_s->parent->p2p_oob_dev_pw_id); } static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s, struct p2p_nfc_params *params, int forced_freq) { wpa_printf(MSG_DEBUG, "P2P: Initiate GO Negotiation based on NFC " "connection handover"); return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL, WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent, forced_freq, -1, 0, 1, 1); } static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s, struct p2p_nfc_params *params, int forced_freq) { int res; wpa_printf(MSG_DEBUG, "P2P: Authorize GO Negotiation based on NFC " "connection handover"); res = wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL, WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent, forced_freq, -1, 0, 1, 1); if (res) return res; res = wpas_p2p_listen(wpa_s, 60); if (res) { p2p_unauthorize(wpa_s->global->p2p, params->peer->p2p_device_addr); } return res; } static int wpas_p2p_nfc_connection_handover(struct wpa_supplicant *wpa_s, const struct wpabuf *data, int sel, int tag, int forced_freq) { const u8 *pos, *end; u16 len, id; struct p2p_nfc_params params; int res; os_memset(¶ms, 0, sizeof(params)); params.sel = sel; wpa_hexdump_buf(MSG_DEBUG, "P2P: Received NFC tag payload", data); pos = wpabuf_head(data); end = pos + wpabuf_len(data); if (end - pos < 2) { wpa_printf(MSG_DEBUG, "P2P: Not enough data for Length of WSC " "attributes"); return -1; } len = WPA_GET_BE16(pos); pos += 2; if (pos + len > end) { wpa_printf(MSG_DEBUG, "P2P: Not enough data for WSC " "attributes"); return -1; } params.wsc_attr = pos; params.wsc_len = len; pos += len; if (end - pos < 2) { wpa_printf(MSG_DEBUG, "P2P: Not enough data for Length of P2P " "attributes"); return -1; } len = WPA_GET_BE16(pos); pos += 2; if (pos + len > end) { wpa_printf(MSG_DEBUG, "P2P: Not enough data for P2P " "attributes"); return -1; } params.p2p_attr = pos; params.p2p_len = len; pos += len; wpa_hexdump(MSG_DEBUG, "P2P: WSC attributes", params.wsc_attr, params.wsc_len); wpa_hexdump(MSG_DEBUG, "P2P: P2P attributes", params.p2p_attr, params.p2p_len); if (pos < end) { wpa_hexdump(MSG_DEBUG, "P2P: Ignored extra data after P2P attributes", pos, end - pos); } res = p2p_process_nfc_connection_handover(wpa_s->global->p2p, ¶ms); if (res) return res; if (params.next_step == NO_ACTION) return 0; if (params.next_step == BOTH_GO) { wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_BOTH_GO "peer=" MACSTR, MAC2STR(params.peer->p2p_device_addr)); return 0; } if (params.next_step == PEER_CLIENT) { if (!is_zero_ether_addr(params.go_dev_addr)) { wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_PEER_CLIENT "peer=" MACSTR " freq=%d go_dev_addr=" MACSTR " ssid=\"%s\"", MAC2STR(params.peer->p2p_device_addr), params.go_freq, MAC2STR(params.go_dev_addr), wpa_ssid_txt(params.go_ssid, params.go_ssid_len)); } else { wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_PEER_CLIENT "peer=" MACSTR " freq=%d", MAC2STR(params.peer->p2p_device_addr), params.go_freq); } return 0; } if (wpas_p2p_cli_freq(wpa_s, NULL, NULL)) { wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_NFC_WHILE_CLIENT "peer=" MACSTR, MAC2STR(params.peer->p2p_device_addr)); return 0; } wpabuf_free(wpa_s->p2p_oob_dev_pw); wpa_s->p2p_oob_dev_pw = NULL; if (params.oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2) { wpa_printf(MSG_DEBUG, "P2P: No peer OOB Dev Pw " "received"); return -1; } id = WPA_GET_BE16(params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN); wpa_printf(MSG_DEBUG, "P2P: Peer OOB Dev Pw %u", id); wpa_hexdump(MSG_DEBUG, "P2P: Peer OOB Public Key hash", params.oob_dev_pw, WPS_OOB_PUBKEY_HASH_LEN); os_memcpy(wpa_s->p2p_peer_oob_pubkey_hash, params.oob_dev_pw, WPS_OOB_PUBKEY_HASH_LEN); wpa_s->p2p_peer_oob_pk_hash_known = 1; if (tag) { if (id < 0x10) { wpa_printf(MSG_DEBUG, "P2P: Static handover - invalid " "peer OOB Device Password Id %u", id); return -1; } wpa_printf(MSG_DEBUG, "P2P: Static handover - use peer OOB " "Device Password Id %u", id); wpa_hexdump_key(MSG_DEBUG, "P2P: Peer OOB Device Password", params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN + 2, params.oob_dev_pw_len - WPS_OOB_PUBKEY_HASH_LEN - 2); wpa_s->p2p_oob_dev_pw_id = id; wpa_s->p2p_oob_dev_pw = wpabuf_alloc_copy( params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN + 2, params.oob_dev_pw_len - WPS_OOB_PUBKEY_HASH_LEN - 2); if (wpa_s->p2p_oob_dev_pw == NULL) return -1; if (wpa_s->conf->wps_nfc_dh_pubkey == NULL && wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey, &wpa_s->conf->wps_nfc_dh_privkey) < 0) return -1; } else { wpa_printf(MSG_DEBUG, "P2P: Using abbreviated WPS handshake " "without Device Password"); wpa_s->p2p_oob_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER; } switch (params.next_step) { case NO_ACTION: case BOTH_GO: case PEER_CLIENT: /* already covered above */ return 0; case JOIN_GROUP: return wpas_p2p_nfc_join_group(wpa_s, ¶ms); case AUTH_JOIN: return wpas_p2p_nfc_auth_join(wpa_s, ¶ms, tag); case INIT_GO_NEG: return wpas_p2p_nfc_init_go_neg(wpa_s, ¶ms, forced_freq); case RESP_GO_NEG: /* TODO: use own OOB Dev Pw */ return wpas_p2p_nfc_resp_go_neg(wpa_s, ¶ms, forced_freq); } return -1; } int wpas_p2p_nfc_tag_process(struct wpa_supplicant *wpa_s, const struct wpabuf *data, int forced_freq) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; return wpas_p2p_nfc_connection_handover(wpa_s, data, 1, 1, forced_freq); } int wpas_p2p_nfc_report_handover(struct wpa_supplicant *wpa_s, int init, const struct wpabuf *req, const struct wpabuf *sel, int forced_freq) { struct wpabuf *tmp; int ret; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; wpa_printf(MSG_DEBUG, "NFC: P2P connection handover reported"); wpa_hexdump_ascii(MSG_DEBUG, "NFC: Req", wpabuf_head(req), wpabuf_len(req)); wpa_hexdump_ascii(MSG_DEBUG, "NFC: Sel", wpabuf_head(sel), wpabuf_len(sel)); if (forced_freq) wpa_printf(MSG_DEBUG, "NFC: Forced freq %d", forced_freq); tmp = ndef_parse_p2p(init ? sel : req); if (tmp == NULL) { wpa_printf(MSG_DEBUG, "P2P: Could not parse NDEF"); return -1; } ret = wpas_p2p_nfc_connection_handover(wpa_s, tmp, init, 0, forced_freq); wpabuf_free(tmp); return ret; } int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled) { const u8 *if_addr; int go_intent = wpa_s->conf->p2p_go_intent; struct wpa_supplicant *iface; if (wpa_s->global->p2p == NULL) return -1; if (!enabled) { wpa_printf(MSG_DEBUG, "P2P: Disable use of own NFC Tag"); for (iface = wpa_s->global->ifaces; iface; iface = iface->next) { if (!iface->ap_iface) continue; hostapd_wps_nfc_token_disable(iface->ap_iface->bss[0]); } p2p_set_authorized_oob_dev_pw_id(wpa_s->global->p2p, 0, 0, NULL); if (wpa_s->p2p_nfc_tag_enabled) wpas_p2p_remove_pending_group_interface(wpa_s); wpa_s->p2p_nfc_tag_enabled = 0; return 0; } if (wpa_s->global->p2p_disabled) return -1; if (wpa_s->conf->wps_nfc_dh_pubkey == NULL || wpa_s->conf->wps_nfc_dh_privkey == NULL || wpa_s->conf->wps_nfc_dev_pw == NULL || wpa_s->conf->wps_nfc_dev_pw_id < 0x10) { wpa_printf(MSG_DEBUG, "P2P: NFC password token not configured " "to allow static handover cases"); return -1; } wpa_printf(MSG_DEBUG, "P2P: Enable use of own NFC Tag"); wpa_s->p2p_oob_dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id; wpabuf_free(wpa_s->p2p_oob_dev_pw); wpa_s->p2p_oob_dev_pw = wpabuf_dup(wpa_s->conf->wps_nfc_dev_pw); if (wpa_s->p2p_oob_dev_pw == NULL) return -1; wpa_s->p2p_peer_oob_pk_hash_known = 0; if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO || wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT) { /* * P2P Group Interface present and the command came on group * interface, so enable the token for the current interface. */ wpa_s->create_p2p_iface = 0; } else { wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s); } if (wpa_s->create_p2p_iface) { enum wpa_driver_if_type iftype; /* Prepare to add a new interface for the group */ iftype = WPA_IF_P2P_GROUP; if (go_intent == 15) iftype = WPA_IF_P2P_GO; if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) { wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new " "interface for the group"); return -1; } if_addr = wpa_s->pending_interface_addr; } else if_addr = wpa_s->own_addr; wpa_s->p2p_nfc_tag_enabled = enabled; for (iface = wpa_s->global->ifaces; iface; iface = iface->next) { struct hostapd_data *hapd; if (iface->ap_iface == NULL) continue; hapd = iface->ap_iface->bss[0]; wpabuf_free(hapd->conf->wps_nfc_dh_pubkey); hapd->conf->wps_nfc_dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey); wpabuf_free(hapd->conf->wps_nfc_dh_privkey); hapd->conf->wps_nfc_dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey); wpabuf_free(hapd->conf->wps_nfc_dev_pw); hapd->conf->wps_nfc_dev_pw = wpabuf_dup(wpa_s->conf->wps_nfc_dev_pw); hapd->conf->wps_nfc_dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id; if (hostapd_wps_nfc_token_enable(iface->ap_iface->bss[0]) < 0) { wpa_dbg(iface, MSG_DEBUG, "P2P: Failed to enable NFC Tag for GO"); } } p2p_set_authorized_oob_dev_pw_id( wpa_s->global->p2p, wpa_s->conf->wps_nfc_dev_pw_id, go_intent, if_addr); return 0; } #endif /* CONFIG_WPS_NFC */ wpa_supplicant-2.2/wpa_supplicant/wpa_passphrase.c0000664000175000017500000000254112343617166020436 0ustar jmjm/* * WPA Supplicant - ASCII passphrase to WPA PSK tool * Copyright (c) 2003-2005, 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/sha1.h" int main(int argc, char *argv[]) { unsigned char psk[32]; int i; char *ssid, *passphrase, buf[64], *pos; if (argc < 2) { printf("usage: wpa_passphrase [passphrase]\n" "\nIf passphrase is left out, it will be read from " "stdin\n"); return 1; } ssid = argv[1]; if (argc > 2) { passphrase = argv[2]; } else { printf("# reading passphrase from stdin\n"); if (fgets(buf, sizeof(buf), stdin) == NULL) { printf("Failed to read passphrase\n"); return 1; } buf[sizeof(buf) - 1] = '\0'; pos = buf; while (*pos != '\0') { if (*pos == '\r' || *pos == '\n') { *pos = '\0'; break; } pos++; } passphrase = buf; } if (os_strlen(passphrase) < 8 || os_strlen(passphrase) > 63) { printf("Passphrase must be 8..63 characters\n"); return 1; } pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32); printf("network={\n"); printf("\tssid=\"%s\"\n", ssid); printf("\t#psk=\"%s\"\n", passphrase); printf("\tpsk="); for (i = 0; i < 32; i++) printf("%02x", psk[i]); printf("\n"); printf("}\n"); return 0; } wpa_supplicant-2.2/wpa_supplicant/wpa_supplicant_conf.mk0000664000175000017500000000240312343617166021636 0ustar jmjm# # Copyright (C) 2010 The Android Open Source Project # # This software may be distributed under the terms of the BSD license. # See README for more details. # # Include this makefile to generate your hardware specific wpa_supplicant.conf # Requires: WIFI_DRIVER_SOCKET_IFACE LOCAL_PATH := $(call my-dir) ######################## include $(CLEAR_VARS) LOCAL_MODULE := wpa_supplicant.conf LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_TAGS := optional LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/wifi include $(BUILD_SYSTEM)/base_rules.mk WPA_SUPPLICANT_CONF_TEMPLATE := $(LOCAL_PATH)/wpa_supplicant_template.conf WPA_SUPPLICANT_CONF_SCRIPT := $(LOCAL_PATH)/wpa_supplicant_conf.sh $(LOCAL_BUILT_MODULE): PRIVATE_WIFI_DRIVER_SOCKET_IFACE := $(WIFI_DRIVER_SOCKET_IFACE) $(LOCAL_BUILT_MODULE): PRIVATE_WPA_SUPPLICANT_CONF_TEMPLATE := $(WPA_SUPPLICANT_CONF_TEMPLATE) $(LOCAL_BUILT_MODULE): PRIVATE_WPA_SUPPLICANT_CONF_SCRIPT := $(WPA_SUPPLICANT_CONF_SCRIPT) $(LOCAL_BUILT_MODULE) : $(WPA_SUPPLICANT_CONF_TEMPLATE) $(WPA_SUPPLICANT_CONF_SCRIPT) @echo Target wpa_supplicant.conf: $@ @mkdir -p $(dir $@) $(hide) WIFI_DRIVER_SOCKET_IFACE="$(PRIVATE_WIFI_DRIVER_SOCKET_IFACE)" \ bash $(PRIVATE_WPA_SUPPLICANT_CONF_SCRIPT) $(PRIVATE_WPA_SUPPLICANT_CONF_TEMPLATE) > $@ ######################## wpa_supplicant-2.2/wpa_supplicant/bss.h0000664000175000017500000001104412343617166016210 0ustar jmjm/* * BSS table * Copyright (c) 2009-2010, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef BSS_H #define BSS_H struct wpa_scan_res; #define WPA_BSS_QUAL_INVALID BIT(0) #define WPA_BSS_NOISE_INVALID BIT(1) #define WPA_BSS_LEVEL_INVALID BIT(2) #define WPA_BSS_LEVEL_DBM BIT(3) #define WPA_BSS_AUTHENTICATED BIT(4) #define WPA_BSS_ASSOCIATED BIT(5) #define WPA_BSS_ANQP_FETCH_TRIED BIT(6) /** * struct wpa_bss_anqp - ANQP data for a BSS entry (struct wpa_bss) */ struct wpa_bss_anqp { /** Number of BSS entries referring to this ANQP data instance */ unsigned int users; #ifdef CONFIG_INTERWORKING struct wpabuf *venue_name; struct wpabuf *network_auth_type; struct wpabuf *roaming_consortium; struct wpabuf *ip_addr_type_availability; struct wpabuf *nai_realm; struct wpabuf *anqp_3gpp; struct wpabuf *domain_name; #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 struct wpabuf *hs20_operator_friendly_name; struct wpabuf *hs20_wan_metrics; struct wpabuf *hs20_connection_capability; struct wpabuf *hs20_operating_class; struct wpabuf *hs20_osu_providers_list; #endif /* CONFIG_HS20 */ }; /** * struct wpa_bss - BSS table * * This structure is used to store information about neighboring BSSes in * generic format. It is mainly updated based on scan results from the driver. */ struct wpa_bss { /** List entry for struct wpa_supplicant::bss */ struct dl_list list; /** List entry for struct wpa_supplicant::bss_id */ struct dl_list list_id; /** Unique identifier for this BSS entry */ unsigned int id; /** Number of counts without seeing this BSS */ unsigned int scan_miss_count; /** Index of the last scan update */ unsigned int last_update_idx; /** Information flags about the BSS/IBSS (WPA_BSS_*) */ unsigned int flags; /** BSSID */ u8 bssid[ETH_ALEN]; /** HESSID */ u8 hessid[ETH_ALEN]; /** SSID */ u8 ssid[32]; /** Length of SSID */ size_t ssid_len; /** Frequency of the channel in MHz (e.g., 2412 = channel 1) */ int freq; /** Beacon interval in TUs (host byte order) */ u16 beacon_int; /** Capability information field in host byte order */ u16 caps; /** Signal quality */ int qual; /** Noise level */ int noise; /** Signal level */ int level; /** Timestamp of last Beacon/Probe Response frame */ u64 tsf; /** Time of the last update (i.e., Beacon or Probe Response RX) */ struct os_reltime last_update; /** ANQP data */ struct wpa_bss_anqp *anqp; /** Length of the following IE field in octets (from Probe Response) */ size_t ie_len; /** Length of the following Beacon IE field in octets */ size_t beacon_ie_len; /* followed by ie_len octets of IEs */ /* followed by beacon_ie_len octets of IEs */ }; void wpa_bss_update_start(struct wpa_supplicant *wpa_s); void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res, struct os_reltime *fetch_time); void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, int new_scan); int wpa_bss_init(struct wpa_supplicant *wpa_s); void wpa_bss_deinit(struct wpa_supplicant *wpa_s); void wpa_bss_flush(struct wpa_supplicant *wpa_s); void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age); struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid, const u8 *ssid, size_t ssid_len); struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid); struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s, const u8 *bssid); struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s, const u8 *dev_addr); struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id); struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s, unsigned int idf, unsigned int idl); const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie); const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type); const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss, u32 vendor_type); struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss, u32 vendor_type); struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss, u32 vendor_type); int wpa_bss_get_max_rate(const struct wpa_bss *bss); int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates); struct wpa_bss_anqp * wpa_bss_anqp_alloc(void); int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss); static inline int bss_is_dmg(const struct wpa_bss *bss) { return bss->freq > 45000; } #endif /* BSS_H */ wpa_supplicant-2.2/wpa_supplicant/ibss_rsn.c0000664000175000017500000005522712343617166017251 0ustar jmjm/* * wpa_supplicant - IBSS RSN * Copyright (c) 2009-2013, 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 "common/wpa_ctrl.h" #include "utils/eloop.h" #include "l2_packet/l2_packet.h" #include "rsn_supp/wpa.h" #include "rsn_supp/wpa_ie.h" #include "ap/wpa_auth.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "common/ieee802_11_defs.h" #include "ibss_rsn.h" static void ibss_rsn_auth_timeout(void *eloop_ctx, void *timeout_ctx); static struct ibss_rsn_peer * ibss_rsn_get_peer(struct ibss_rsn *ibss_rsn, const u8 *addr) { struct ibss_rsn_peer *peer; for (peer = ibss_rsn->peers; peer; peer = peer->next) if (os_memcmp(addr, peer->addr, ETH_ALEN) == 0) break; return peer; } static void ibss_rsn_free(struct ibss_rsn_peer *peer) { eloop_cancel_timeout(ibss_rsn_auth_timeout, peer, NULL); wpa_auth_sta_deinit(peer->auth); wpa_sm_deinit(peer->supp); os_free(peer); } static void supp_set_state(void *ctx, enum wpa_states state) { struct ibss_rsn_peer *peer = ctx; peer->supp_state = state; } static enum wpa_states supp_get_state(void *ctx) { struct ibss_rsn_peer *peer = ctx; return peer->supp_state; } static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf, size_t len) { struct ibss_rsn_peer *peer = ctx; struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s; wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x " "len=%lu)", __func__, MAC2STR(dest), proto, (unsigned long) len); if (wpa_s->l2) return l2_packet_send(wpa_s->l2, dest, proto, buf, len); return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len); } static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data, u16 data_len, size_t *msg_len, void **data_pos) { struct ieee802_1x_hdr *hdr; wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)", __func__, type, data_len); *msg_len = sizeof(*hdr) + data_len; hdr = os_malloc(*msg_len); if (hdr == NULL) return NULL; hdr->version = 2; hdr->type = type; hdr->length = host_to_be16(data_len); if (data) os_memcpy(hdr + 1, data, data_len); else os_memset(hdr + 1, 0, data_len); if (data_pos) *data_pos = hdr + 1; return (u8 *) hdr; } static int supp_get_beacon_ie(void *ctx) { struct ibss_rsn_peer *peer = ctx; wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); /* TODO: get correct RSN IE */ return wpa_sm_set_ap_rsn_ie(peer->supp, (u8 *) "\x30\x14\x01\x00" "\x00\x0f\xac\x04" "\x01\x00\x00\x0f\xac\x04" "\x01\x00\x00\x0f\xac\x02" "\x00\x00", 22); } static void ibss_check_rsn_completed(struct ibss_rsn_peer *peer) { struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s; if ((peer->authentication_status & (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH)) != (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH)) return; if (peer->authentication_status & IBSS_RSN_REPORTED_PTK) return; peer->authentication_status |= IBSS_RSN_REPORTED_PTK; wpa_msg(wpa_s, MSG_INFO, IBSS_RSN_COMPLETED MACSTR, MAC2STR(peer->addr)); } static int supp_set_key(void *ctx, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) { struct ibss_rsn_peer *peer = ctx; wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d " "set_tx=%d)", __func__, alg, MAC2STR(addr), key_idx, set_tx); wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len); wpa_hexdump_key(MSG_DEBUG, "SUPP: set_key - key", key, key_len); if (key_idx == 0) { peer->authentication_status |= IBSS_RSN_SET_PTK_SUPP; ibss_check_rsn_completed(peer); /* * In IBSS RSN, the pairwise key from the 4-way handshake * initiated by the peer with highest MAC address is used. */ if (os_memcmp(peer->ibss_rsn->wpa_s->own_addr, peer->addr, ETH_ALEN) > 0) { wpa_printf(MSG_DEBUG, "SUPP: Do not use this PTK"); return 0; } } if (is_broadcast_ether_addr(addr)) addr = peer->addr; return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx, set_tx, seq, seq_len, key, key_len); } static void * supp_get_network_ctx(void *ctx) { struct ibss_rsn_peer *peer = ctx; return wpa_supplicant_get_ssid(peer->ibss_rsn->wpa_s); } static int supp_mlme_setprotection(void *ctx, const u8 *addr, int protection_type, int key_type) { wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d " "key_type=%d)", __func__, MAC2STR(addr), protection_type, key_type); return 0; } static void supp_cancel_auth_timeout(void *ctx) { wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); } static void supp_deauthenticate(void * ctx, int reason_code) { wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__); } static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, const u8 *psk) { struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx)); if (ctx == NULL) return -1; ctx->ctx = peer; ctx->msg_ctx = peer->ibss_rsn->wpa_s; ctx->set_state = supp_set_state; ctx->get_state = supp_get_state; ctx->ether_send = supp_ether_send; ctx->get_beacon_ie = supp_get_beacon_ie; ctx->alloc_eapol = supp_alloc_eapol; ctx->set_key = supp_set_key; ctx->get_network_ctx = supp_get_network_ctx; ctx->mlme_setprotection = supp_mlme_setprotection; ctx->cancel_auth_timeout = supp_cancel_auth_timeout; ctx->deauthenticate = supp_deauthenticate; peer->supp = wpa_sm_init(ctx); if (peer->supp == NULL) { wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed"); return -1; } wpa_sm_set_own_addr(peer->supp, own_addr); wpa_sm_set_param(peer->supp, WPA_PARAM_RSN_ENABLED, 1); wpa_sm_set_param(peer->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN); wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP); wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP); wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK); wpa_sm_set_pmk(peer->supp, psk, PMK_LEN); peer->supp_ie_len = sizeof(peer->supp_ie); if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie, &peer->supp_ie_len) < 0) { wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()" " failed"); return -1; } wpa_sm_notify_assoc(peer->supp, peer->addr); return 0; } static void auth_logger(void *ctx, const u8 *addr, logger_level level, const char *txt) { if (addr) wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s", MAC2STR(addr), txt); else wpa_printf(MSG_DEBUG, "AUTH: %s", txt); } static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *p2p_dev_addr, const u8 *prev_psk) { struct ibss_rsn *ibss_rsn = ctx; wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", __func__, MAC2STR(addr), prev_psk); if (prev_psk) return NULL; return ibss_rsn->psk; } static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data, size_t data_len, int encrypt) { struct ibss_rsn *ibss_rsn = ctx; struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s; wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu " "encrypt=%d)", __func__, MAC2STR(addr), (unsigned long) data_len, encrypt); if (wpa_s->l2) return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data, data_len); return wpa_drv_send_eapol(wpa_s, addr, ETH_P_EAPOL, data, data_len); } static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, const u8 *addr, int idx, u8 *key, size_t key_len) { struct ibss_rsn *ibss_rsn = ctx; u8 seq[6]; os_memset(seq, 0, sizeof(seq)); if (addr) { wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d addr=" MACSTR " key_idx=%d)", __func__, alg, MAC2STR(addr), idx); } else { wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d key_idx=%d)", __func__, alg, idx); } wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len); if (idx == 0) { if (addr) { struct ibss_rsn_peer *peer; peer = ibss_rsn_get_peer(ibss_rsn, addr); if (peer) { peer->authentication_status |= IBSS_RSN_SET_PTK_AUTH; ibss_check_rsn_completed(peer); } } /* * In IBSS RSN, the pairwise key from the 4-way handshake * initiated by the peer with highest MAC address is used. */ if (addr == NULL || os_memcmp(ibss_rsn->wpa_s->own_addr, addr, ETH_ALEN) < 0) { wpa_printf(MSG_DEBUG, "AUTH: Do not use this PTK"); return 0; } } return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx, 1, seq, 6, key, key_len); } static void ibss_rsn_disconnect(void *ctx, const u8 *addr, u16 reason) { struct ibss_rsn *ibss_rsn = ctx; wpa_drv_sta_deauth(ibss_rsn->wpa_s, addr, reason); } static int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx), void *cb_ctx) { struct ibss_rsn *ibss_rsn = ctx; struct ibss_rsn_peer *peer; wpa_printf(MSG_DEBUG, "AUTH: for_each_sta"); for (peer = ibss_rsn->peers; peer; peer = peer->next) { if (peer->auth && cb(peer->auth, cb_ctx)) return 1; } return 0; } static void ibss_set_sta_authorized(struct ibss_rsn *ibss_rsn, struct ibss_rsn_peer *peer, int authorized) { int res; if (authorized) { res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr, WPA_STA_AUTHORIZED, WPA_STA_AUTHORIZED, ~0); wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " authorizing port", MAC2STR(peer->addr)); } else { res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr, 0, 0, ~WPA_STA_AUTHORIZED); wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " unauthorizing port", MAC2STR(peer->addr)); } if (res && errno != ENOENT) { wpa_printf(MSG_DEBUG, "Could not set station " MACSTR " flags " "for kernel driver (errno=%d)", MAC2STR(peer->addr), errno); } } static void auth_set_eapol(void *ctx, const u8 *addr, wpa_eapol_variable var, int value) { struct ibss_rsn *ibss_rsn = ctx; struct ibss_rsn_peer *peer = ibss_rsn_get_peer(ibss_rsn, addr); if (peer == NULL) return; switch (var) { case WPA_EAPOL_authorized: ibss_set_sta_authorized(ibss_rsn, peer, value); break; default: /* do not handle any other event */ wpa_printf(MSG_DEBUG, "AUTH: eapol event not handled %d", var); break; } } static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn, const u8 *own_addr) { struct wpa_auth_config conf; struct wpa_auth_callbacks cb; wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); os_memset(&conf, 0, sizeof(conf)); conf.wpa = 2; conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK; conf.wpa_pairwise = WPA_CIPHER_CCMP; conf.rsn_pairwise = WPA_CIPHER_CCMP; conf.wpa_group = WPA_CIPHER_CCMP; conf.eapol_version = 2; conf.wpa_group_rekey = 600; os_memset(&cb, 0, sizeof(cb)); cb.ctx = ibss_rsn; cb.logger = auth_logger; cb.set_eapol = auth_set_eapol; cb.send_eapol = auth_send_eapol; cb.get_psk = auth_get_psk; cb.set_key = auth_set_key; cb.for_each_sta = auth_for_each_sta; cb.disconnect = ibss_rsn_disconnect; ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb); if (ibss_rsn->auth_group == NULL) { wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed"); return -1; } wpa_init_keys(ibss_rsn->auth_group); return 0; } static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn, struct ibss_rsn_peer *peer) { peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr, NULL); if (peer->auth == NULL) { wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed"); return -1; } /* TODO: get peer RSN IE with Probe Request */ if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth, (u8 *) "\x30\x14\x01\x00" "\x00\x0f\xac\x04" "\x01\x00\x00\x0f\xac\x04" "\x01\x00\x00\x0f\xac\x02" "\x00\x00", 22, NULL, 0) != WPA_IE_OK) { wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); return -1; } if (wpa_auth_sm_event(peer->auth, WPA_ASSOC)) return -1; if (wpa_auth_sta_associated(ibss_rsn->auth_group, peer->auth)) return -1; return 0; } static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq) { struct ieee80211_mgmt auth; const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth); struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s; if (wpa_s->driver->send_frame == NULL) return -1; os_memset(&auth, 0, sizeof(auth)); auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_AUTH); os_memcpy(auth.da, da, ETH_ALEN); os_memcpy(auth.sa, wpa_s->own_addr, ETH_ALEN); os_memcpy(auth.bssid, wpa_s->bssid, ETH_ALEN); auth.u.auth.auth_alg = host_to_le16(WLAN_AUTH_OPEN); auth.u.auth.auth_transaction = host_to_le16(seq); auth.u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS); wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR, seq, MAC2STR(da)); return wpa_s->driver->send_frame(wpa_s->drv_priv, (u8 *) &auth, auth_length, 0); } static int ibss_rsn_is_auth_started(struct ibss_rsn_peer * peer) { return peer->authentication_status & (IBSS_RSN_AUTH_BY_US | IBSS_RSN_AUTH_EAPOL_BY_US); } static struct ibss_rsn_peer * ibss_rsn_peer_init(struct ibss_rsn *ibss_rsn, const u8 *addr) { struct ibss_rsn_peer *peer; if (ibss_rsn == NULL) return NULL; peer = ibss_rsn_get_peer(ibss_rsn, addr); if (peer) { wpa_printf(MSG_DEBUG, "RSN: IBSS Supplicant for peer "MACSTR " already running", MAC2STR(addr)); return peer; } wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Supplicant for peer "MACSTR, MAC2STR(addr)); peer = os_zalloc(sizeof(*peer)); if (peer == NULL) { wpa_printf(MSG_DEBUG, "RSN: Could not allocate memory."); return NULL; } peer->ibss_rsn = ibss_rsn; os_memcpy(peer->addr, addr, ETH_ALEN); peer->authentication_status = IBSS_RSN_AUTH_NOT_AUTHENTICATED; if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, ibss_rsn->psk) < 0) { ibss_rsn_free(peer); return NULL; } peer->next = ibss_rsn->peers; ibss_rsn->peers = peer; return peer; } static void ibss_rsn_auth_timeout(void *eloop_ctx, void *timeout_ctx) { struct ibss_rsn_peer *peer = eloop_ctx; /* * Assume peer does not support Authentication exchange or the frame was * lost somewhere - start EAPOL Authenticator. */ wpa_printf(MSG_DEBUG, "RSN: Timeout on waiting Authentication frame response from " MACSTR " - start authenticator", MAC2STR(peer->addr)); peer->authentication_status |= IBSS_RSN_AUTH_BY_US; ibss_rsn_auth_init(peer->ibss_rsn, peer); } int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) { struct ibss_rsn_peer *peer; int res; /* if the peer already exists, exit immediately */ peer = ibss_rsn_get_peer(ibss_rsn, addr); if (peer) return 0; peer = ibss_rsn_peer_init(ibss_rsn, addr); if (peer == NULL) return -1; /* Open Authentication: send first Authentication frame */ res = ibss_rsn_send_auth(ibss_rsn, addr, 1); if (res) { /* * The driver may not support Authentication frame exchange in * IBSS. Ignore authentication and go through EAPOL exchange. */ peer->authentication_status |= IBSS_RSN_AUTH_BY_US; return ibss_rsn_auth_init(ibss_rsn, peer); } else { os_get_reltime(&peer->own_auth_tx); eloop_register_timeout(1, 0, ibss_rsn_auth_timeout, peer, NULL); } return 0; } static int ibss_rsn_peer_authenticated(struct ibss_rsn *ibss_rsn, struct ibss_rsn_peer *peer, int reason) { int already_started; if (ibss_rsn == NULL || peer == NULL) return -1; already_started = ibss_rsn_is_auth_started(peer); peer->authentication_status |= reason; if (already_started) { wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator already " "started for peer " MACSTR, MAC2STR(peer->addr)); return 0; } wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator " "for now-authenticated peer " MACSTR, MAC2STR(peer->addr)); return ibss_rsn_auth_init(ibss_rsn, peer); } void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac) { struct ibss_rsn_peer *peer, *prev; if (ibss_rsn == NULL) return; if (peermac == NULL) { /* remove all peers */ wpa_printf(MSG_DEBUG, "%s: Remove all peers", __func__); peer = ibss_rsn->peers; while (peer) { prev = peer; peer = peer->next; ibss_rsn_free(prev); ibss_rsn->peers = peer; } } else { /* remove specific peer */ wpa_printf(MSG_DEBUG, "%s: Remove specific peer " MACSTR, __func__, MAC2STR(peermac)); for (prev = NULL, peer = ibss_rsn->peers; peer != NULL; prev = peer, peer = peer->next) { if (os_memcmp(peermac, peer->addr, ETH_ALEN) == 0) { if (prev == NULL) ibss_rsn->peers = peer->next; else prev->next = peer->next; ibss_rsn_free(peer); wpa_printf(MSG_DEBUG, "%s: Successfully " "removed a specific peer", __func__); break; } } } } struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s) { struct ibss_rsn *ibss_rsn; ibss_rsn = os_zalloc(sizeof(*ibss_rsn)); if (ibss_rsn == NULL) return NULL; ibss_rsn->wpa_s = wpa_s; if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) { ibss_rsn_deinit(ibss_rsn); return NULL; } return ibss_rsn; } void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn) { struct ibss_rsn_peer *peer, *prev; if (ibss_rsn == NULL) return; peer = ibss_rsn->peers; while (peer) { prev = peer; peer = peer->next; ibss_rsn_free(prev); } wpa_deinit(ibss_rsn->auth_group); os_free(ibss_rsn); } static int ibss_rsn_eapol_dst_supp(const u8 *buf, size_t len) { const struct ieee802_1x_hdr *hdr; const struct wpa_eapol_key *key; u16 key_info; size_t plen; /* TODO: Support other EAPOL packets than just EAPOL-Key */ if (len < sizeof(*hdr) + sizeof(*key)) return -1; hdr = (const struct ieee802_1x_hdr *) buf; key = (const struct wpa_eapol_key *) (hdr + 1); plen = be_to_host16(hdr->length); if (hdr->version < EAPOL_VERSION) { /* TODO: backwards compatibility */ } if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) { wpa_printf(MSG_DEBUG, "RSN: EAPOL frame (type %u) discarded, " "not a Key frame", hdr->type); return -1; } if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) { wpa_printf(MSG_DEBUG, "RSN: EAPOL frame payload size %lu " "invalid (frame size %lu)", (unsigned long) plen, (unsigned long) len); return -1; } if (key->type != EAPOL_KEY_TYPE_RSN) { wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key type (%d) unknown, " "discarded", key->type); return -1; } key_info = WPA_GET_BE16(key->key_info); return !!(key_info & WPA_KEY_INFO_ACK); } static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn, struct ibss_rsn_peer *peer, const u8 *buf, size_t len) { int supp; u8 *tmp; supp = ibss_rsn_eapol_dst_supp(buf, len); if (supp < 0) return -1; tmp = os_malloc(len); if (tmp == NULL) return -1; os_memcpy(tmp, buf, len); if (supp) { peer->authentication_status |= IBSS_RSN_AUTH_EAPOL_BY_PEER; wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant from " MACSTR, MAC2STR(peer->addr)); wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len); } else { if (ibss_rsn_is_auth_started(peer) == 0) { wpa_printf(MSG_DEBUG, "RSN: IBSS EAPOL for " "Authenticator dropped as " MACSTR " is not " "authenticated", MAC2STR(peer->addr)); os_free(tmp); return -1; } wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator " "from "MACSTR, MAC2STR(peer->addr)); wpa_receive(ibss_rsn->auth_group, peer->auth, tmp, len); } os_free(tmp); return 1; } int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, const u8 *buf, size_t len) { struct ibss_rsn_peer *peer; if (ibss_rsn == NULL) return -1; peer = ibss_rsn_get_peer(ibss_rsn, src_addr); if (peer) return ibss_rsn_process_rx_eapol(ibss_rsn, peer, buf, len); if (ibss_rsn_eapol_dst_supp(buf, len) > 0) { /* * Create new IBSS peer based on an EAPOL message from the peer * Authenticator. */ peer = ibss_rsn_peer_init(ibss_rsn, src_addr); if (peer == NULL) return -1; /* assume the peer is authenticated already */ wpa_printf(MSG_DEBUG, "RSN: IBSS Not using IBSS Auth for peer " MACSTR, MAC2STR(src_addr)); ibss_rsn_peer_authenticated(ibss_rsn, peer, IBSS_RSN_AUTH_EAPOL_BY_US); return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers, buf, len); } return 0; } void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk) { if (ibss_rsn == NULL) return; os_memcpy(ibss_rsn->psk, psk, PMK_LEN); } static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn, struct ibss_rsn_peer *peer, const u8* addr) { wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 1) from " MACSTR, MAC2STR(addr)); if (peer && peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) { if (peer->own_auth_tx.sec) { struct os_reltime now, diff; os_get_reltime(&now); os_reltime_sub(&now, &peer->own_auth_tx, &diff); if (diff.sec == 0 && diff.usec < 500000) { wpa_printf(MSG_DEBUG, "RSN: Skip IBSS reinit since only %u usec from own Auth frame TX", (int) diff.usec); goto skip_reinit; } } /* * A peer sent us an Authentication frame even though it already * started an EAPOL session. We should reinit state machines * here, but it's much more complicated than just deleting and * recreating the state machine */ wpa_printf(MSG_DEBUG, "RSN: IBSS Reinitializing station " MACSTR, MAC2STR(addr)); ibss_rsn_stop(ibss_rsn, addr); peer = NULL; } if (!peer) { peer = ibss_rsn_peer_init(ibss_rsn, addr); if (!peer) return; wpa_printf(MSG_DEBUG, "RSN: IBSS Auth started by peer " MACSTR, MAC2STR(addr)); } skip_reinit: /* reply with an Authentication frame now, before sending an EAPOL */ ibss_rsn_send_auth(ibss_rsn, addr, 2); /* no need to start another AUTH challenge in the other way.. */ ibss_rsn_peer_authenticated(ibss_rsn, peer, IBSS_RSN_AUTH_EAPOL_BY_US); } void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame, size_t len) { const struct ieee80211_mgmt *header; struct ibss_rsn_peer *peer; size_t auth_length; header = (const struct ieee80211_mgmt *) auth_frame; auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth); if (ibss_rsn == NULL || len < auth_length) return; if (le_to_host16(header->u.auth.auth_alg) != WLAN_AUTH_OPEN || le_to_host16(header->u.auth.status_code) != WLAN_STATUS_SUCCESS) return; peer = ibss_rsn_get_peer(ibss_rsn, header->sa); switch (le_to_host16(header->u.auth.auth_transaction)) { case 1: ibss_rsn_handle_auth_1_of_2(ibss_rsn, peer, header->sa); break; case 2: wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 2) from " MACSTR, MAC2STR(header->sa)); if (!peer) { wpa_printf(MSG_DEBUG, "RSN: Received Auth seq 2 from " "unknown STA " MACSTR, MAC2STR(header->sa)); break; } /* authentication has been completed */ eloop_cancel_timeout(ibss_rsn_auth_timeout, peer, NULL); wpa_printf(MSG_DEBUG, "RSN: IBSS Auth completed with " MACSTR, MAC2STR(header->sa)); ibss_rsn_peer_authenticated(ibss_rsn, peer, IBSS_RSN_AUTH_BY_US); break; } } wpa_supplicant-2.2/wpa_supplicant/notify.c0000664000175000017500000003673512343617166016742 0ustar jmjm/* * wpa_supplicant - Event notifications * Copyright (c) 2009-2010, 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 "common/wpa_ctrl.h" #include "config.h" #include "wpa_supplicant_i.h" #include "wps_supplicant.h" #include "dbus/dbus_common.h" #include "dbus/dbus_old.h" #include "dbus/dbus_new.h" #include "rsn_supp/wpa.h" #include "driver_i.h" #include "scan.h" #include "p2p_supplicant.h" #include "sme.h" #include "notify.h" int wpas_notify_supplicant_initialized(struct wpa_global *global) { #ifdef CONFIG_DBUS if (global->params.dbus_ctrl_interface) { global->dbus = wpas_dbus_init(global); if (global->dbus == NULL) return -1; } #endif /* CONFIG_DBUS */ return 0; } void wpas_notify_supplicant_deinitialized(struct wpa_global *global) { #ifdef CONFIG_DBUS if (global->dbus) wpas_dbus_deinit(global->dbus); #endif /* CONFIG_DBUS */ } int wpas_notify_iface_added(struct wpa_supplicant *wpa_s) { if (wpas_dbus_register_iface(wpa_s)) return -1; if (wpas_dbus_register_interface(wpa_s)) return -1; return 0; } void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s) { /* unregister interface in old DBus ctrl iface */ wpas_dbus_unregister_iface(wpa_s); /* unregister interface in new DBus ctrl iface */ wpas_dbus_unregister_interface(wpa_s); } void wpas_notify_state_changed(struct wpa_supplicant *wpa_s, enum wpa_states new_state, enum wpa_states old_state) { /* notify the old DBus API */ wpa_supplicant_dbus_notify_state_change(wpa_s, new_state, old_state); /* notify the new DBus API */ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATE); #ifdef CONFIG_P2P if (new_state == WPA_COMPLETED) wpas_p2p_notif_connected(wpa_s); else if (old_state >= WPA_ASSOCIATED && new_state < WPA_ASSOCIATED) wpas_p2p_notif_disconnected(wpa_s); #endif /* CONFIG_P2P */ sme_state_changed(wpa_s); #ifdef ANDROID wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE "id=%d state=%d BSSID=" MACSTR " SSID=%s", wpa_s->current_ssid ? wpa_s->current_ssid->id : -1, new_state, MAC2STR(wpa_s->bssid), wpa_s->current_ssid && wpa_s->current_ssid->ssid ? wpa_ssid_txt(wpa_s->current_ssid->ssid, wpa_s->current_ssid->ssid_len) : ""); #endif /* ANDROID */ } void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s) { wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_DISCONNECT_REASON); } void wpas_notify_network_changed(struct wpa_supplicant *wpa_s) { wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_NETWORK); } void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s) { wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_AP_SCAN); } void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s) { wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_BSS); } void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s) { wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_AUTH_MODE); } void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { wpas_dbus_signal_network_enabled_changed(wpa_s, ssid); } void wpas_notify_network_selected(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { wpas_dbus_signal_network_selected(wpa_s, ssid->id); } void wpas_notify_network_request(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, enum wpa_ctrl_req_type rtype, const char *default_txt) { wpas_dbus_signal_network_request(wpa_s, ssid, rtype, default_txt); } void wpas_notify_scanning(struct wpa_supplicant *wpa_s) { /* notify the old DBus API */ wpa_supplicant_dbus_notify_scanning(wpa_s); /* notify the new DBus API */ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SCANNING); } void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success) { wpas_dbus_signal_scan_done(wpa_s, success); } void wpas_notify_scan_results(struct wpa_supplicant *wpa_s) { /* notify the old DBus API */ wpa_supplicant_dbus_notify_scan_results(wpa_s); wpas_wps_notify_scan_results(wpa_s); } void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s, const struct wps_credential *cred) { #ifdef CONFIG_WPS /* notify the old DBus API */ wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred); /* notify the new DBus API */ wpas_dbus_signal_wps_cred(wpa_s, cred); #endif /* CONFIG_WPS */ } void wpas_notify_wps_event_m2d(struct wpa_supplicant *wpa_s, struct wps_event_m2d *m2d) { #ifdef CONFIG_WPS wpas_dbus_signal_wps_event_m2d(wpa_s, m2d); #endif /* CONFIG_WPS */ } void wpas_notify_wps_event_fail(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail) { #ifdef CONFIG_WPS wpas_dbus_signal_wps_event_fail(wpa_s, fail); #endif /* CONFIG_WPS */ } void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s) { #ifdef CONFIG_WPS wpas_dbus_signal_wps_event_success(wpa_s); #endif /* CONFIG_WPS */ } void wpas_notify_network_added(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { /* * Networks objects created during any P2P activities should not be * exposed out. They might/will confuse certain non-P2P aware * applications since these network objects won't behave like * regular ones. */ if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s) wpas_dbus_register_network(wpa_s, ssid); } void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { #ifdef CONFIG_P2P wpas_dbus_register_persistent_group(wpa_s, ssid); #endif /* CONFIG_P2P */ } void wpas_notify_persistent_group_removed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { #ifdef CONFIG_P2P wpas_dbus_unregister_persistent_group(wpa_s, ssid->id); #endif /* CONFIG_P2P */ } void wpas_notify_network_removed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { if (wpa_s->next_ssid == ssid) wpa_s->next_ssid = NULL; if (wpa_s->wpa) wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s) wpas_dbus_unregister_network(wpa_s, ssid->id); #ifdef CONFIG_P2P wpas_p2p_network_removed(wpa_s, ssid); #endif /* CONFIG_P2P */ } void wpas_notify_bss_added(struct wpa_supplicant *wpa_s, u8 bssid[], unsigned int id) { wpas_dbus_register_bss(wpa_s, bssid, id); wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_ADDED "%u " MACSTR, id, MAC2STR(bssid)); } void wpas_notify_bss_removed(struct wpa_supplicant *wpa_s, u8 bssid[], unsigned int id) { wpas_dbus_unregister_bss(wpa_s, bssid, id); wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_REMOVED "%u " MACSTR, id, MAC2STR(bssid)); } void wpas_notify_bss_freq_changed(struct wpa_supplicant *wpa_s, unsigned int id) { wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_FREQ, id); } void wpas_notify_bss_signal_changed(struct wpa_supplicant *wpa_s, unsigned int id) { wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_SIGNAL, id); } void wpas_notify_bss_privacy_changed(struct wpa_supplicant *wpa_s, unsigned int id) { wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_PRIVACY, id); } void wpas_notify_bss_mode_changed(struct wpa_supplicant *wpa_s, unsigned int id) { wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_MODE, id); } void wpas_notify_bss_wpaie_changed(struct wpa_supplicant *wpa_s, unsigned int id) { wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPA, id); } void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s, unsigned int id) { wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_RSN, id); } void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s, unsigned int id) { #ifdef CONFIG_WPS wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPS, id); #endif /* CONFIG_WPS */ } void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s, unsigned int id) { wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_IES, id); } void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s, unsigned int id) { wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_RATES, id); } void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name) { wpas_dbus_signal_blob_added(wpa_s, name); } void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name) { wpas_dbus_signal_blob_removed(wpa_s, name); } void wpas_notify_debug_level_changed(struct wpa_global *global) { wpas_dbus_signal_debug_level_changed(global); } void wpas_notify_debug_timestamp_changed(struct wpa_global *global) { wpas_dbus_signal_debug_timestamp_changed(global); } void wpas_notify_debug_show_keys_changed(struct wpa_global *global) { wpas_dbus_signal_debug_show_keys_changed(global); } void wpas_notify_suspend(struct wpa_global *global) { struct wpa_supplicant *wpa_s; os_get_time(&global->suspend_time); wpa_printf(MSG_DEBUG, "System suspend notification"); for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) wpa_drv_suspend(wpa_s); } void wpas_notify_resume(struct wpa_global *global) { struct os_time now; int slept; struct wpa_supplicant *wpa_s; if (global->suspend_time.sec == 0) slept = -1; else { os_get_time(&now); slept = now.sec - global->suspend_time.sec; } wpa_printf(MSG_DEBUG, "System resume notification (slept %d seconds)", slept); for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { wpa_drv_resume(wpa_s); if (wpa_s->wpa_state == WPA_DISCONNECTED) wpa_supplicant_req_scan(wpa_s, 0, 100000); } } #ifdef CONFIG_P2P void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s, const u8 *dev_addr, int new_device) { if (new_device) { /* Create the new peer object */ wpas_dbus_register_peer(wpa_s, dev_addr); } /* Notify a new peer has been detected*/ wpas_dbus_signal_peer_device_found(wpa_s, dev_addr); } void wpas_notify_p2p_device_lost(struct wpa_supplicant *wpa_s, const u8 *dev_addr) { wpas_dbus_unregister_peer(wpa_s, dev_addr); /* Create signal on interface object*/ wpas_dbus_signal_peer_device_lost(wpa_s, dev_addr); } void wpas_notify_p2p_group_removed(struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role) { wpas_dbus_unregister_p2p_group(wpa_s, ssid); wpas_dbus_signal_p2p_group_removed(wpa_s, role); } void wpas_notify_p2p_go_neg_req(struct wpa_supplicant *wpa_s, const u8 *src, u16 dev_passwd_id) { wpas_dbus_signal_p2p_go_neg_req(wpa_s, src, dev_passwd_id); } void wpas_notify_p2p_go_neg_completed(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *res) { wpas_dbus_signal_p2p_go_neg_resp(wpa_s, res); } void wpas_notify_p2p_invitation_result(struct wpa_supplicant *wpa_s, int status, const u8 *bssid) { wpas_dbus_signal_p2p_invitation_result(wpa_s, status, bssid); } void wpas_notify_p2p_sd_request(struct wpa_supplicant *wpa_s, int freq, const u8 *sa, u8 dialog_token, u16 update_indic, const u8 *tlvs, size_t tlvs_len) { wpas_dbus_signal_p2p_sd_request(wpa_s, freq, sa, dialog_token, update_indic, tlvs, tlvs_len); } void wpas_notify_p2p_sd_response(struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic, const u8 *tlvs, size_t tlvs_len) { wpas_dbus_signal_p2p_sd_response(wpa_s, sa, update_indic, tlvs, tlvs_len); } /** * wpas_notify_p2p_provision_discovery - Notification of provision discovery * @dev_addr: Who sent the request or responded to our request. * @request: Will be 1 if request, 0 for response. * @status: Valid only in case of response (0 in case of success) * @config_methods: WPS config methods * @generated_pin: PIN to be displayed in case of WPS_CONFIG_DISPLAY method * * This can be used to notify: * - Requests or responses * - Various config methods * - Failure condition in case of response */ void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request, enum p2p_prov_disc_status status, u16 config_methods, unsigned int generated_pin) { wpas_dbus_signal_p2p_provision_discovery(wpa_s, dev_addr, request, status, config_methods, generated_pin); } void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int network_id, int client) { /* Notify a group has been started */ wpas_dbus_register_p2p_group(wpa_s, ssid); wpas_dbus_signal_p2p_group_started(wpa_s, ssid, client, network_id); } void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail) { wpas_dbus_signal_p2p_wps_failed(wpa_s, fail); } #endif /* CONFIG_P2P */ static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr) { #ifdef CONFIG_P2P wpas_p2p_notify_ap_sta_authorized(wpa_s, p2p_dev_addr); /* * Register a group member object corresponding to this peer and * emit a PeerJoined signal. This will check if it really is a * P2P group. */ wpas_dbus_register_p2p_groupmember(wpa_s, sta); /* * Create 'peer-joined' signal on group object -- will also * check P2P itself. */ wpas_dbus_signal_p2p_peer_joined(wpa_s, sta); #endif /* CONFIG_P2P */ /* Notify listeners a new station has been authorized */ wpas_dbus_signal_sta_authorized(wpa_s, sta); } static void wpas_notify_ap_sta_deauthorized(struct wpa_supplicant *wpa_s, const u8 *sta) { #ifdef CONFIG_P2P /* * Unregister a group member object corresponding to this peer * if this is a P2P group. */ wpas_dbus_unregister_p2p_groupmember(wpa_s, sta); /* * Create 'peer-disconnected' signal on group object if this * is a P2P group. */ wpas_dbus_signal_p2p_peer_disconnected(wpa_s, sta); #endif /* CONFIG_P2P */ /* Notify listeners a station has been deauthorized */ wpas_dbus_signal_sta_deauthorized(wpa_s, sta); } void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *mac_addr, int authorized, const u8 *p2p_dev_addr) { if (authorized) wpas_notify_ap_sta_authorized(wpa_s, mac_addr, p2p_dev_addr); else wpas_notify_ap_sta_deauthorized(wpa_s, mac_addr); } void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth, const char *subject, const char *cert_hash, const struct wpabuf *cert) { wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT "depth=%d subject='%s'%s%s", depth, subject, cert_hash ? " hash=" : "", cert_hash ? cert_hash : ""); if (cert) { char *cert_hex; size_t len = wpabuf_len(cert) * 2 + 1; cert_hex = os_malloc(len); if (cert_hex) { wpa_snprintf_hex(cert_hex, len, wpabuf_head(cert), wpabuf_len(cert)); wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT "depth=%d subject='%s' cert=%s", depth, subject, cert_hex); os_free(cert_hex); } } /* notify the old DBus API */ wpa_supplicant_dbus_notify_certification(wpa_s, depth, subject, cert_hash, cert); /* notify the new DBus API */ wpas_dbus_signal_certification(wpa_s, depth, subject, cert_hash, cert); } void wpas_notify_preq(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *dst, const u8 *bssid, const u8 *ie, size_t ie_len, u32 ssi_signal) { #ifdef CONFIG_AP wpas_dbus_signal_preq(wpa_s, addr, dst, bssid, ie, ie_len, ssi_signal); #endif /* CONFIG_AP */ } void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status, const char *parameter) { wpas_dbus_signal_eap_status(wpa_s, status, parameter); wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_EAP_STATUS "status='%s' parameter='%s'", status, parameter); } wpa_supplicant-2.2/wpa_supplicant/eap_testing.txt0000664000175000017500000003467512343617166020332 0ustar jmjmAutomatic regression and interoperability testing of wpa_supplicant's IEEE 802.1X/EAPOL authentication Test program: - Linked some parts of IEEE 802.1X Authenticator implementation from hostapd (RADIUS client and RADIUS processing, EAP<->RADIUS encapsulation/decapsulation) into wpa_supplicant. - Replaced wpa_supplicant.c and wpa.c with test code that trigger IEEE 802.1X authentication automatically without need for wireless client card or AP. - For EAP methods that generate keying material, the key derived by the Supplicant is verified to match with the one received by the (now integrated) Authenticator. The full automated test suite can now be run in couple of seconds, but I'm more than willing to add new RADIUS authentication servers to make this take a bit more time.. ;-) As an extra bonus, this can also be seen as automatic regression/interoperability testing for the RADIUS server, too. In order for me to be able to use a new authentication server, the server need to be available from Internet (at least from one static IP address) and I will need to get suitable user name/password pairs, certificates, and private keys for testing use. Other alternative would be to get an evaluation version of the server so that I can install it on my own test setup. If you are interested in providing either server access or evaluation version, please contact me (j@w1.fi). Test matrix +) tested successfully F) failed -) server did not support ?) not tested Cisco ACS ----------------------------------------------------------. hostapd --------------------------------------------------------. | Cisco Aironet 1200 AP (local RADIUS server) ----------------. | | Periodik Labs Elektron ---------------------------------. | | | Lucent NavisRadius ---------------------------------. | | | | Interlink RAD-Series ---------------------------. | | | | | Radiator -----------------------------------. | | | | | | Meetinghouse Aegis ---------------------. | | | | | | | Funk Steel-Belted ------------------. | | | | | | | | Funk Odyssey -------------------. | | | | | | | | | Microsoft IAS --------------. | | | | | | | | | | FreeRADIUS -------------. | | | | | | | | | | | | | | | | | | | | | | | EAP-MD5 + - - + + + + + - - + + EAP-GTC + - - ? + + + + - - + - EAP-OTP - - - - - + - - - - - - EAP-MSCHAPv2 + - - + + + + + - - + - EAP-TLS + + + + + + + + - - + + EAP-PEAPv0/MSCHAPv2 + + + + + + + + + - + + EAP-PEAPv0/GTC + - + - + + + + - - + + EAP-PEAPv0/OTP - - - - - + - - - - - - EAP-PEAPv0/MD5 + - - + + + + + - - + - EAP-PEAPv0/TLS + + - + + + F + - - + + EAP-PEAPv0/SIM - - - - - - - - - - + - EAP-PEAPv0/AKA - - - - - - - - - - + - EAP-PEAPv0/PSK - - - - - - - - - - + - EAP-PEAPv0/PAX - - - - - - - - - - + - EAP-PEAPv0/SAKE - - - - - - - - - - + - EAP-PEAPv0/GPSK - - - - - - - - - - + - EAP-PEAPv1/MSCHAPv2 - - + + + +1 + +5 +8 - + + EAP-PEAPv1/GTC - - + + + +1 + +5 +8 - + + EAP-PEAPv1/OTP - - - - - +1 - - - - - - EAP-PEAPv1/MD5 - - - + + +1 + +5 - - + - EAP-PEAPv1/TLS - - - + + +1 F +5 - - + + EAP-PEAPv1/SIM - - - - - - - - - - + - EAP-PEAPv1/AKA - - - - - - - - - - + - EAP-PEAPv1/PSK - - - - - - - - - - + - EAP-PEAPv1/PAX - - - - - - - - - - + - EAP-PEAPv1/SAKE - - - - - - - - - - + - EAP-PEAPv1/GPSK - - - - - - - - - - + - EAP-TTLS/CHAP + - +2 + + + + + + - + - EAP-TTLS/MSCHAP + - + + + + + + + - + - EAP-TTLS/MSCHAPv2 + - + + + + + + + - + - EAP-TTLS/PAP + - + + + + + + + - + - EAP-TTLS/EAP-MD5 + - +2 + + + + + + - + - EAP-TTLS/EAP-GTC + - +2 ? + + + + - - + - EAP-TTLS/EAP-OTP - - - - - + - - - - - - EAP-TTLS/EAP-MSCHAPv2 + - +2 + + + + + + - + - EAP-TTLS/EAP-TLS + - +2 + F + + + - - + - EAP-TTLS/EAP-SIM - - - - - - - - - - + - EAP-TTLS/EAP-AKA - - - - - - - - - - + - EAP-TTLS/EAP-PSK - - - - - - - - - - + - EAP-TTLS/EAP-PAX - - - - - - - - - - + - EAP-TTLS/EAP-SAKE - - - - - - - - - - + - EAP-TTLS/EAP-GPSK - - - - - - - - - - + - EAP-TTLS + TNC - - - - - + - - - - + - EAP-SIM + - - ? - + - ? - - + - EAP-AKA - - - - - + - - - - + - EAP-AKA' - - - - - - - - - - + - EAP-PSK +7 - - - - + - - - - + - EAP-PAX - - - - - + - - - - + - EAP-SAKE - - - - - - - - - - + - EAP-GPSK - - - - - - - - - - + - EAP-FAST/MSCHAPv2(prov) - - - + - + - - - + + + EAP-FAST/GTC(auth) - - - + - + - - - + + + EAP-FAST/MSCHAPv2(aprov)- - - - - + - - - - + + EAP-FAST/GTC(aprov) - - - - - + - - - - + + EAP-FAST/MD5(aprov) - - - - - + - - - - + - EAP-FAST/TLS(aprov) - - - - - - - - - - + + EAP-FAST/SIM(aprov) - - - - - - - - - - + - EAP-FAST/AKA(aprov) - - - - - - - - - - + - EAP-FAST/MSCHAPv2(auth) - - - - - + - - - - + + EAP-FAST/MD5(auth) - - - - - + - - - - + - EAP-FAST/TLS(auth) - - - - - - - - - - + + EAP-FAST/SIM(auth) - - - - - - - - - - + - EAP-FAST/AKA(auth) - - - - - - - - - - + - EAP-FAST + TNC - - - - - - - - - - + - LEAP + - + + + + F +6 - + - + EAP-TNC +9 - - - - + - - - - + - EAP-IKEv2 +10 - - - - - - - - - + - 1) PEAPv1 required new label, "client PEAP encryption" instead of "client EAP encryption", during key derivation (requires phase1="peaplabel=1" in the network configuration in wpa_supplicant.conf) 2) used FreeRADIUS as inner auth server 5) PEAPv1 required termination of negotiation on tunneled EAP-Success and new label in key deriviation (phase1="peap_outer_success=0 peaplabel=1") (in "IETF Draft 5" mode) 6) Authenticator simulator required patching for handling Access-Accept within negotiation (for the first EAP-Success of LEAP) 7) tested only with an older (incompatible) draft of EAP-PSK; FreeRADIUS does not support the current EAP-PSK (RFC) specification 8) PEAPv1 used non-standard version negotiation (client had to force v1 even though server reported v0 as the highest supported version) 9) only EAP-TTLS/EAP-TNC tested, i.e., test did not include proper sequence of client authentication followed by TNC inside the tunnel 10) worked only with special compatibility code to match the IKEv2 server implementation Automated tests: FreeRADIUS (2.0-beta/CVS snapshot) - EAP-MD5-Challenge - EAP-GTC - EAP-MSCHAPv2 - EAP-TLS - EAP-PEAPv0 / MSCHAPv2 - EAP-PEAPv0 / GTC - EAP-PEAPv0 / MD5-Challenge - EAP-PEAPv0 / TLS - EAP-TTLS / EAP-MD5-Challenge - EAP-TTLS / EAP-GTC - EAP-TTLS / EAP-MSCHAPv2 - EAP-TTLS / EAP-TLS - EAP-TTLS / CHAP - EAP-TTLS / PAP - EAP-TTLS / MSCHAP - EAP-TTLS / MSCHAPv2 - EAP-TTLS / EAP-TNC (partial support; no authentication sequence) - EAP-SIM - LEAP Microsoft Windows Server 2003 / IAS - EAP-TLS - EAP-PEAPv0 / MSCHAPv2 - EAP-PEAPv0 / TLS - EAP-MD5 * IAS does not seem to support other EAP methods Funk Odyssey 2.01.00.653 - EAP-TLS - EAP-PEAPv0 / MSCHAPv2 - EAP-PEAPv0 / GTC - EAP-PEAPv1 / MSCHAPv2 - EAP-PEAPv1 / GTC Note: PEAPv1 requires TLS key derivation to use label "client EAP encryption" - EAP-TTLS / CHAP (using FreeRADIUS as inner auth srv) - EAP-TTLS / MSCHAP - EAP-TTLS / MSCHAPv2 - EAP-TTLS / PAP - EAP-TTLS / EAP-MD5-Challenge (using FreeRADIUS as inner auth srv) - EAP-TTLS / EAP-GTC (using FreeRADIUS as inner auth srv) - EAP-TTLS / EAP-MSCHAPv2 (using FreeRADIUS as inner auth srv) - EAP-TTLS / EAP-TLS (using FreeRADIUS as inner auth srv) * not supported in Odyssey: - EAP-MD5-Challenge - EAP-GTC - EAP-MSCHAPv2 - EAP-PEAP / MD5-Challenge - EAP-PEAP / TLS Funk Steel-Belted Radius Enterprise Edition v4.71.739 - EAP-MD5-Challenge - EAP-MSCHAPv2 - EAP-TLS - EAP-PEAPv0 / MSCHAPv2 - EAP-PEAPv0 / MD5 - EAP-PEAPv0 / TLS - EAP-PEAPv1 / MSCHAPv2 - EAP-PEAPv1 / MD5 - EAP-PEAPv1 / GTC - EAP-PEAPv1 / TLS Note: PEAPv1 requires TLS key derivation to use label "client EAP encryption" - EAP-TTLS / CHAP - EAP-TTLS / MSCHAP - EAP-TTLS / MSCHAPv2 - EAP-TTLS / PAP - EAP-TTLS / EAP-MD5-Challenge - EAP-TTLS / EAP-MSCHAPv2 - EAP-TTLS / EAP-TLS Meetinghouse Aegis 1.1.4 - EAP-MD5-Challenge - EAP-GTC - EAP-MSCHAPv2 - EAP-TLS - EAP-PEAPv0 / MSCHAPv2 - EAP-PEAPv0 / TLS - EAP-PEAPv0 / GTC - EAP-PEAPv0 / MD5-Challenge - EAP-PEAPv1 / MSCHAPv2 - EAP-PEAPv1 / TLS - EAP-PEAPv1 / GTC - EAP-PEAPv1 / MD5-Challenge Note: PEAPv1 requires TLS key derivation to use label "client EAP encryption" - EAP-TTLS / CHAP - EAP-TTLS / MSCHAP - EAP-TTLS / MSCHAPv2 - EAP-TTLS / PAP - EAP-TTLS / EAP-MD5-Challenge - EAP-TTLS / EAP-GTC - EAP-TTLS / EAP-MSCHAPv2 * did not work - EAP-TTLS / EAP-TLS (Server rejects authentication without any reason in debug log. It looks like the inner TLS negotiation starts properly and the last packet from Supplicant looks like the one sent in the Phase 1. The server generates a valid looking reply in the same way as in Phase 1, but then ends up sending Access-Reject. Maybe an issue with TTLS fragmentation in the Aegis server(?) The packet seems to include 1328 bytes of EAP-Message and this may go beyond the fragmentation limit with AVP encapsulation and TLS tunneling. Note: EAP-PEAP/TLS did work, so this issue seems to be with something TTLS specific.) Radiator 3.17.1 (eval, with all patches up to and including 2007-05-25) - EAP-MD5-Challenge - EAP-GTC - EAP-OTP - EAP-MSCHAPv2 - EAP-TLS - EAP-PEAPv0 / MSCHAPv2 - EAP-PEAPv0 / GTC - EAP-PEAPv0 / OTP - EAP-PEAPv0 / MD5-Challenge - EAP-PEAPv0 / TLS Note: Needed to use unknown identity in outer auth and some times the server seems to get confused and fails to send proper Phase 2 data. - EAP-PEAPv1 / MSCHAPv2 - EAP-PEAPv1 / GTC - EAP-PEAPv1 / OTP - EAP-PEAPv1 / MD5-Challenge - EAP-PEAPv1 / TLS Note: This has some additional requirements for EAPTLS_MaxFragmentSize. Using 1300 for outer auth and 500 for inner auth seemed to work. Note: Needed to use unknown identity in outer auth and some times the server seems to get confused and fails to send proper Phase 2 data. - EAP-TTLS / CHAP - EAP-TTLS / MSCHAP - EAP-TTLS / MSCHAPv2 - EAP-TTLS / PAP - EAP-TTLS / EAP-MD5-Challenge - EAP-TTLS / EAP-GTC - EAP-TTLS / EAP-OTP - EAP-TTLS / EAP-MSCHAPv2 - EAP-TTLS / EAP-TLS Note: This has some additional requirements for EAPTLS_MaxFragmentSize. Using 1300 for outer auth and 500 for inner auth seemed to work. - EAP-SIM - EAP-AKA - EAP-PSK - EAP-PAX - EAP-TNC Interlink Networks RAD-Series 6.1.2.7 - EAP-MD5-Challenge - EAP-GTC - EAP-MSCHAPv2 - EAP-TLS - EAP-PEAPv0 / MSCHAPv2 - EAP-PEAPv0 / GTC - EAP-PEAPv0 / MD5-Challenge - EAP-PEAPv1 / MSCHAPv2 - EAP-PEAPv1 / GTC - EAP-PEAPv1 / MD5-Challenge Note: PEAPv1 requires TLS key derivation to use label "client EAP encryption" - EAP-TTLS / CHAP - EAP-TTLS / MSCHAP - EAP-TTLS / MSCHAPv2 - EAP-TTLS / PAP - EAP-TTLS / EAP-MD5-Challenge - EAP-TTLS / EAP-GTC - EAP-TTLS / EAP-MSCHAPv2 - EAP-TTLS / EAP-TLS * did not work - EAP-PEAPv0 / TLS - EAP-PEAPv1 / TLS (Failed to decrypt Phase 2 data) Lucent NavisRadius 4.4.0 - EAP-MD5-Challenge - EAP-GTC - EAP-MSCHAPv2 - EAP-TLS - EAP-PEAPv0 / MD5-Challenge - EAP-PEAPv0 / MSCHAPv2 - EAP-PEAPv0 / GTC - EAP-PEAPv0 / TLS - EAP-PEAPv1 / MD5-Challenge - EAP-PEAPv1 / MSCHAPv2 - EAP-PEAPv1 / GTC - EAP-PEAPv1 / TLS "IETF Draft 5" mode requires phase1="peap_outer_success=0 peaplabel=1" 'Cisco ACU 5.05' mode works without phase1 configuration - EAP-TTLS / CHAP - EAP-TTLS / MSCHAP - EAP-TTLS / MSCHAPv2 - EAP-TTLS / PAP - EAP-TTLS / EAP-MD5-Challenge - EAP-TTLS / EAP-MSCHAPv2 - EAP-TTLS / EAP-GTC - EAP-TTLS / EAP-TLS Note: user certificate from NavisRadius had private key in a format that wpa_supplicant could not use. Converting this to PKCS#12 and then back to PEM allowed wpa_supplicant to use the key. hostapd v0.3.3 - EAP-MD5-Challenge - EAP-GTC - EAP-MSCHAPv2 - EAP-TLS - EAP-PEAPv0 / MSCHAPv2 - EAP-PEAPv0 / GTC - EAP-PEAPv0 / MD5-Challenge - EAP-PEAPv1 / MSCHAPv2 - EAP-PEAPv1 / GTC - EAP-PEAPv1 / MD5-Challenge - EAP-TTLS / CHAP - EAP-TTLS / MSCHAP - EAP-TTLS / MSCHAPv2 - EAP-TTLS / PAP - EAP-TTLS / EAP-MD5-Challenge - EAP-TTLS / EAP-GTC - EAP-TTLS / EAP-MSCHAPv2 - EAP-SIM - EAP-PAX PEAPv1: Funk Odyssey 2.01.00.653: - uses tunneled EAP-Success, expects reply in tunnel or TLS ACK, sends MPPE keys with outer EAP-Success message after this - uses label "client EAP encryption" - (peap_outer_success 1 and 2 work) Funk Steel-Belted Radius Enterprise Edition v4.71.739 - uses tunneled EAP-Success, expects reply in tunnel or TLS ACK, sends MPPE keys with outer EAP-Success message after this - uses label "client EAP encryption" - (peap_outer_success 1 and 2 work) Radiator 3.9: - uses TLV Success and Reply, sends MPPE keys with outer EAP-Success message after this - uses label "client PEAP encryption" Lucent NavisRadius 4.4.0 (in "IETF Draft 5" mode): - sends tunneled EAP-Success with MPPE keys and expects the authentication to terminate at this point (gets somewhat confused with reply to this) - uses label "client PEAP encryption" - phase1="peap_outer_success=0 peaplabel=1" Lucent NavisRadius 4.4.0 (in "Cisco ACU 5.05" mode): - sends tunneled EAP-Success with MPPE keys and expects to receive TLS ACK as a reply - uses label "client EAP encryption" Meetinghouse Aegis 1.1.4 - uses tunneled EAP-Success, expects reply in tunnel or TLS ACK, sends MPPE keys with outer EAP-Success message after this - uses label "client EAP encryption" - peap_outer_success 1 and 2 work wpa_supplicant-2.2/wpa_supplicant/blacklist.c0000664000175000017500000000660112343617166017367 0ustar jmjm/* * wpa_supplicant - Temporary BSSID blacklist * Copyright (c) 2003-2007, 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 "wpa_supplicant_i.h" #include "blacklist.h" /** * wpa_blacklist_get - Get the blacklist entry for a BSSID * @wpa_s: Pointer to wpa_supplicant data * @bssid: BSSID * Returns: Matching blacklist entry for the BSSID or %NULL if not found */ struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s, const u8 *bssid) { struct wpa_blacklist *e; if (wpa_s == NULL || bssid == NULL) return NULL; e = wpa_s->blacklist; while (e) { if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) return e; e = e->next; } return NULL; } /** * wpa_blacklist_add - Add an BSSID to the blacklist * @wpa_s: Pointer to wpa_supplicant data * @bssid: BSSID to be added to the blacklist * Returns: Current blacklist count on success, -1 on failure * * This function adds the specified BSSID to the blacklist or increases the * blacklist count if the BSSID was already listed. It should be called when * an association attempt fails either due to the selected BSS rejecting * association or due to timeout. * * This blacklist is used to force %wpa_supplicant to go through all available * BSSes before retrying to associate with an BSS that rejected or timed out * association. It does not prevent the listed BSS from being used; it only * changes the order in which they are tried. */ int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid) { struct wpa_blacklist *e; if (wpa_s == NULL || bssid == NULL) return -1; e = wpa_blacklist_get(wpa_s, bssid); if (e) { e->count++; wpa_printf(MSG_DEBUG, "BSSID " MACSTR " blacklist count " "incremented to %d", MAC2STR(bssid), e->count); return e->count; } e = os_zalloc(sizeof(*e)); if (e == NULL) return -1; os_memcpy(e->bssid, bssid, ETH_ALEN); e->count = 1; e->next = wpa_s->blacklist; wpa_s->blacklist = e; wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR " into blacklist", MAC2STR(bssid)); return e->count; } /** * wpa_blacklist_del - Remove an BSSID from the blacklist * @wpa_s: Pointer to wpa_supplicant data * @bssid: BSSID to be removed from the blacklist * Returns: 0 on success, -1 on failure */ int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid) { struct wpa_blacklist *e, *prev = NULL; if (wpa_s == NULL || bssid == NULL) return -1; e = wpa_s->blacklist; while (e) { if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) { if (prev == NULL) { wpa_s->blacklist = e->next; } else { prev->next = e->next; } wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from " "blacklist", MAC2STR(bssid)); os_free(e); return 0; } prev = e; e = e->next; } return -1; } /** * wpa_blacklist_clear - Clear the blacklist of all entries * @wpa_s: Pointer to wpa_supplicant data */ void wpa_blacklist_clear(struct wpa_supplicant *wpa_s) { struct wpa_blacklist *e, *prev; int max_count = 0; e = wpa_s->blacklist; wpa_s->blacklist = NULL; while (e) { if (e->count > max_count) max_count = e->count; prev = e; e = e->next; wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from " "blacklist (clear)", MAC2STR(prev->bssid)); os_free(prev); } wpa_s->extra_blacklist_count += max_count; } wpa_supplicant-2.2/wpa_supplicant/blacklist.h0000664000175000017500000000122412343617166017370 0ustar jmjm/* * wpa_supplicant - Temporary BSSID blacklist * Copyright (c) 2003-2007, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef BLACKLIST_H #define BLACKLIST_H struct wpa_blacklist { struct wpa_blacklist *next; u8 bssid[ETH_ALEN]; int count; }; struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s, const u8 *bssid); int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid); int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid); void wpa_blacklist_clear(struct wpa_supplicant *wpa_s); #endif /* BLACKLIST_H */ wpa_supplicant-2.2/wpa_supplicant/wpa_supplicant_i.h0000664000175000017500000007234212343617166020772 0ustar jmjm/* * wpa_supplicant - Internal definitions * Copyright (c) 2003-2014, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef WPA_SUPPLICANT_I_H #define WPA_SUPPLICANT_I_H #include "utils/list.h" #include "common/defs.h" #include "common/sae.h" #include "wps/wps_defs.h" #include "config_ssid.h" extern const char *wpa_supplicant_version; extern const char *wpa_supplicant_license; #ifndef CONFIG_NO_STDOUT_DEBUG extern const char *wpa_supplicant_full_license1; extern const char *wpa_supplicant_full_license2; extern const char *wpa_supplicant_full_license3; extern const char *wpa_supplicant_full_license4; extern const char *wpa_supplicant_full_license5; #endif /* CONFIG_NO_STDOUT_DEBUG */ struct wpa_sm; struct wpa_supplicant; struct ibss_rsn; struct scan_info; struct wpa_bss; struct wpa_scan_results; struct hostapd_hw_modes; struct wpa_driver_associate_params; /* * Forward declarations of private structures used within the ctrl_iface * backends. Other parts of wpa_supplicant do not have access to data stored in * these structures. */ struct ctrl_iface_priv; struct ctrl_iface_global_priv; struct wpas_dbus_priv; /** * struct wpa_interface - Parameters for wpa_supplicant_add_iface() */ struct wpa_interface { /** * confname - Configuration name (file or profile) name * * This can also be %NULL when a configuration file is not used. In * that case, ctrl_interface must be set to allow the interface to be * configured. */ const char *confname; /** * confanother - Additional configuration name (file or profile) name * * This can also be %NULL when the additional configuration file is not * used. */ const char *confanother; #ifdef CONFIG_P2P /** * conf_p2p_dev - Additional configuration file used to hold the * P2P Device configuration parameters. * * This can also be %NULL. In such a case, if a P2P Device dedicated * interfaces is created, the main configuration file will be used. */ const char *conf_p2p_dev; #endif /* CONFIG_P2P */ /** * ctrl_interface - Control interface parameter * * If a configuration file is not used, this variable can be used to * set the ctrl_interface parameter that would have otherwise been read * from the configuration file. If both confname and ctrl_interface are * set, ctrl_interface is used to override the value from configuration * file. */ const char *ctrl_interface; /** * driver - Driver interface name, or %NULL to use the default driver */ const char *driver; /** * driver_param - Driver interface parameters * * If a configuration file is not used, this variable can be used to * set the driver_param parameters that would have otherwise been read * from the configuration file. If both confname and driver_param are * set, driver_param is used to override the value from configuration * file. */ const char *driver_param; /** * ifname - Interface name */ const char *ifname; /** * bridge_ifname - Optional bridge interface name * * If the driver interface (ifname) is included in a Linux bridge * device, the bridge interface may need to be used for receiving EAPOL * frames. This can be enabled by setting this variable to enable * receiving of EAPOL frames from an additional interface. */ const char *bridge_ifname; /** * p2p_mgmt - Interface used for P2P management (P2P Device operations) * * Indicates whether wpas_p2p_init() must be called for this interface. * This is used only when the driver supports a dedicated P2P Device * interface that is not a network interface. */ int p2p_mgmt; }; /** * struct wpa_params - Parameters for wpa_supplicant_init() */ struct wpa_params { /** * daemonize - Run %wpa_supplicant in the background */ int daemonize; /** * wait_for_monitor - Wait for a monitor program before starting */ int wait_for_monitor; /** * pid_file - Path to a PID (process ID) file * * If this and daemonize are set, process ID of the background process * will be written to the specified file. */ char *pid_file; /** * wpa_debug_level - Debugging verbosity level (e.g., MSG_INFO) */ int wpa_debug_level; /** * wpa_debug_show_keys - Whether keying material is included in debug * * This parameter can be used to allow keying material to be included * in debug messages. This is a security risk and this option should * not be enabled in normal configuration. If needed during * development or while troubleshooting, this option can provide more * details for figuring out what is happening. */ int wpa_debug_show_keys; /** * wpa_debug_timestamp - Whether to include timestamp in debug messages */ int wpa_debug_timestamp; /** * ctrl_interface - Global ctrl_iface path/parameter */ char *ctrl_interface; /** * ctrl_interface_group - Global ctrl_iface group */ char *ctrl_interface_group; /** * dbus_ctrl_interface - Enable the DBus control interface */ int dbus_ctrl_interface; /** * wpa_debug_file_path - Path of debug file or %NULL to use stdout */ const char *wpa_debug_file_path; /** * wpa_debug_syslog - Enable log output through syslog */ int wpa_debug_syslog; /** * wpa_debug_tracing - Enable log output through Linux tracing */ int wpa_debug_tracing; /** * override_driver - Optional driver parameter override * * This parameter can be used to override the driver parameter in * dynamic interface addition to force a specific driver wrapper to be * used instead. */ char *override_driver; /** * override_ctrl_interface - Optional ctrl_interface override * * This parameter can be used to override the ctrl_interface parameter * in dynamic interface addition to force a control interface to be * created. */ char *override_ctrl_interface; /** * entropy_file - Optional entropy file * * This parameter can be used to configure wpa_supplicant to maintain * its internal entropy store over restarts. */ char *entropy_file; }; struct p2p_srv_bonjour { struct dl_list list; struct wpabuf *query; struct wpabuf *resp; }; struct p2p_srv_upnp { struct dl_list list; u8 version; char *service; }; /** * struct wpa_global - Internal, global data for all %wpa_supplicant interfaces * * This structure is initialized by calling wpa_supplicant_init() when starting * %wpa_supplicant. */ struct wpa_global { struct wpa_supplicant *ifaces; struct wpa_params params; struct ctrl_iface_global_priv *ctrl_iface; struct wpas_dbus_priv *dbus; void **drv_priv; size_t drv_count; struct os_time suspend_time; struct p2p_data *p2p; struct wpa_supplicant *p2p_init_wpa_s; struct wpa_supplicant *p2p_group_formation; struct wpa_supplicant *p2p_invite_group; u8 p2p_dev_addr[ETH_ALEN]; struct os_reltime p2p_go_wait_client; struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */ struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */ int p2p_disabled; int cross_connection; struct wpa_freq_range_list p2p_disallow_freq; struct wpa_freq_range_list p2p_go_avoid_freq; enum wpa_conc_pref { WPA_CONC_PREF_NOT_SET, WPA_CONC_PREF_STA, WPA_CONC_PREF_P2P } conc_pref; unsigned int p2p_per_sta_psk:1; unsigned int p2p_fail_on_wps_complete:1; #ifdef CONFIG_WIFI_DISPLAY int wifi_display; #define MAX_WFD_SUBELEMS 10 struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS]; #endif /* CONFIG_WIFI_DISPLAY */ struct psk_list_entry *add_psk; /* From group formation */ }; /** * struct wpa_radio - Internal data for per-radio information * * This structure is used to share data about configured interfaces * (struct wpa_supplicant) that share the same physical radio, e.g., to allow * better coordination of offchannel operations. */ struct wpa_radio { char name[16]; /* from driver_ops get_radio_name() or empty if not * available */ struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */ struct dl_list work; /* struct wpa_radio_work::list entries */ }; /** * struct wpa_radio_work - Radio work item */ struct wpa_radio_work { struct dl_list list; unsigned int freq; /* known frequency (MHz) or 0 for multiple/unknown */ const char *type; struct wpa_supplicant *wpa_s; void (*cb)(struct wpa_radio_work *work, int deinit); void *ctx; unsigned int started:1; struct os_reltime time; }; int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, const char *type, int next, void (*cb)(struct wpa_radio_work *work, int deinit), void *ctx); void radio_work_done(struct wpa_radio_work *work); void radio_remove_works(struct wpa_supplicant *wpa_s, const char *type, int remove_all); void radio_work_check_next(struct wpa_supplicant *wpa_s); int radio_work_pending(struct wpa_supplicant *wpa_s, const char *type); struct wpa_connect_work { unsigned int sme:1; struct wpa_bss *bss; struct wpa_ssid *ssid; }; int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss, struct wpa_ssid *test_ssid); void wpas_connect_work_free(struct wpa_connect_work *cwork); void wpas_connect_work_done(struct wpa_supplicant *wpa_s); struct wpa_external_work { unsigned int id; char type[100]; unsigned int timeout; }; /** * offchannel_send_action_result - Result of offchannel send Action frame */ enum offchannel_send_action_result { OFFCHANNEL_SEND_ACTION_SUCCESS /**< Frame was send and acknowledged */, OFFCHANNEL_SEND_ACTION_NO_ACK /**< Frame was sent, but not acknowledged */, OFFCHANNEL_SEND_ACTION_FAILED /**< Frame was not sent due to a failure */ }; struct wps_ap_info { u8 bssid[ETH_ALEN]; enum wps_ap_info_type { WPS_AP_NOT_SEL_REG, WPS_AP_SEL_REG, WPS_AP_SEL_REG_OUR } type; unsigned int tries; struct os_reltime last_attempt; }; struct wpa_ssid_value { u8 ssid[32]; size_t ssid_len; }; /** * struct wpa_supplicant - Internal data for wpa_supplicant interface * * This structure contains the internal data for core wpa_supplicant code. This * should be only used directly from the core code. However, a pointer to this * data is used from other files as an arbitrary context pointer in calls to * core functions. */ struct wpa_supplicant { struct wpa_global *global; struct wpa_radio *radio; /* shared radio context */ struct dl_list radio_list; /* list head: struct wpa_radio::ifaces */ struct wpa_supplicant *parent; struct wpa_supplicant *next; struct l2_packet_data *l2; struct l2_packet_data *l2_br; unsigned char own_addr[ETH_ALEN]; char ifname[100]; #ifdef CONFIG_CTRL_IFACE_DBUS char *dbus_path; #endif /* CONFIG_CTRL_IFACE_DBUS */ #ifdef CONFIG_CTRL_IFACE_DBUS_NEW char *dbus_new_path; char *dbus_groupobj_path; #ifdef CONFIG_AP char *preq_notify_peer; #endif /* CONFIG_AP */ #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ char bridge_ifname[16]; char *confname; char *confanother; #ifdef CONFIG_P2P char *conf_p2p_dev; #endif /* CONFIG_P2P */ struct wpa_config *conf; int countermeasures; struct os_reltime last_michael_mic_error; u8 bssid[ETH_ALEN]; u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this * field contains the target BSSID. */ int reassociate; /* reassociation requested */ int disconnected; /* all connections disabled; i.e., do no reassociate * before this has been cleared */ struct wpa_ssid *current_ssid; struct wpa_bss *current_bss; int ap_ies_from_associnfo; unsigned int assoc_freq; /* Selected configuration (based on Beacon/ProbeResp WPA IE) */ int pairwise_cipher; int group_cipher; int key_mgmt; int wpa_proto; int mgmt_group_cipher; void *drv_priv; /* private data used by driver_ops */ void *global_drv_priv; u8 *bssid_filter; size_t bssid_filter_count; u8 *disallow_aps_bssid; size_t disallow_aps_bssid_count; struct wpa_ssid_value *disallow_aps_ssid; size_t disallow_aps_ssid_count; enum { WPA_SETBAND_AUTO, WPA_SETBAND_5G, WPA_SETBAND_2G } setband; /* Preferred network for the next connection attempt */ struct wpa_ssid *next_ssid; /* previous scan was wildcard when interleaving between * wildcard scans and specific SSID scan when max_ssids=1 */ int prev_scan_wildcard; struct wpa_ssid *prev_scan_ssid; /* previously scanned SSID; * NULL = not yet initialized (start * with wildcard SSID) * WILDCARD_SSID_SCAN = wildcard * SSID was used in the previous scan */ #define WILDCARD_SSID_SCAN ((struct wpa_ssid *) 1) struct wpa_ssid *prev_sched_ssid; /* last SSID used in sched scan */ int sched_scan_timeout; int sched_scan_interval; int first_sched_scan; int sched_scan_timed_out; void (*scan_res_handler)(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); struct dl_list bss; /* struct wpa_bss::list */ struct dl_list bss_id; /* struct wpa_bss::list_id */ size_t num_bss; unsigned int bss_update_idx; unsigned int bss_next_id; /* * Pointers to BSS entries in the order they were in the last scan * results. */ struct wpa_bss **last_scan_res; unsigned int last_scan_res_used; unsigned int last_scan_res_size; struct os_reltime last_scan; struct wpa_driver_ops *driver; int interface_removed; /* whether the network interface has been * removed */ struct wpa_sm *wpa; struct eapol_sm *eapol; struct ctrl_iface_priv *ctrl_iface; enum wpa_states wpa_state; struct wpa_radio_work *scan_work; int scanning; int sched_scanning; int new_connection; int eapol_received; /* number of EAPOL packets received after the * previous association event */ struct scard_data *scard; char imsi[20]; int mnc_len; unsigned char last_eapol_src[ETH_ALEN]; unsigned int keys_cleared; /* bitfield of key indexes that the driver is * known not to be configured with a key */ struct wpa_blacklist *blacklist; /** * extra_blacklist_count - Sum of blacklist counts after last connection * * This variable is used to maintain a count of temporary blacklisting * failures (maximum number for any BSS) over blacklist clear * operations. This is needed for figuring out whether there has been * failures prior to the last blacklist clear operation which happens * whenever no other not-blacklisted BSS candidates are available. This * gets cleared whenever a connection has been established successfully. */ int extra_blacklist_count; /** * scan_req - Type of the scan request */ enum scan_req_type { /** * NORMAL_SCAN_REQ - Normal scan request * * This is used for scans initiated by wpa_supplicant to find an * AP for a connection. */ NORMAL_SCAN_REQ, /** * INITIAL_SCAN_REQ - Initial scan request * * This is used for the first scan on an interface to force at * least one scan to be run even if the configuration does not * include any enabled networks. */ INITIAL_SCAN_REQ, /** * MANUAL_SCAN_REQ - Manual scan request * * This is used for scans where the user request a scan or * a specific wpa_supplicant operation (e.g., WPS) requires scan * to be run. */ MANUAL_SCAN_REQ } scan_req, last_scan_req; struct os_reltime scan_trigger_time, scan_start_time; int scan_runs; /* number of scan runs since WPS was started */ int *next_scan_freqs; int *manual_scan_freqs; int *manual_sched_scan_freqs; unsigned int manual_scan_passive:1; unsigned int manual_scan_use_id:1; unsigned int manual_scan_only_new:1; unsigned int own_scan_requested:1; unsigned int own_scan_running:1; unsigned int external_scan_running:1; unsigned int clear_driver_scan_cache:1; unsigned int manual_scan_id; int scan_interval; /* time in sec between scans to find suitable AP */ int normal_scans; /* normal scans run before sched_scan */ int scan_for_connection; /* whether the scan request was triggered for * finding a connection */ unsigned int drv_flags; unsigned int drv_enc; /* * A bitmap of supported protocols for probe response offload. See * struct wpa_driver_capa in driver.h */ unsigned int probe_resp_offloads; /* extended capabilities supported by the driver */ const u8 *extended_capa, *extended_capa_mask; unsigned int extended_capa_len; int max_scan_ssids; int max_sched_scan_ssids; int sched_scan_supported; unsigned int max_match_sets; unsigned int max_remain_on_chan; unsigned int max_stations; int pending_mic_error_report; int pending_mic_error_pairwise; int mic_errors_seen; /* Michael MIC errors with the current PTK */ struct wps_context *wps; int wps_success; /* WPS success event received */ struct wps_er *wps_er; int blacklist_cleared; struct wpabuf *pending_eapol_rx; struct os_reltime pending_eapol_rx_time; u8 pending_eapol_rx_src[ETH_ALEN]; unsigned int last_eapol_matches_bssid:1; unsigned int eap_expected_failure:1; unsigned int reattach:1; /* reassociation to the same BSS requested */ struct ibss_rsn *ibss_rsn; int set_sta_uapsd; int sta_uapsd; int set_ap_uapsd; int ap_uapsd; #ifdef CONFIG_SME struct { u8 ssid[32]; size_t ssid_len; int freq; u8 assoc_req_ie[200]; size_t assoc_req_ie_len; int mfp; int ft_used; u8 mobility_domain[2]; u8 *ft_ies; size_t ft_ies_len; u8 prev_bssid[ETH_ALEN]; int prev_bssid_set; int auth_alg; int proto; int sa_query_count; /* number of pending SA Query requests; * 0 = no SA Query in progress */ int sa_query_timed_out; u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN * * sa_query_count octets of pending * SA Query transaction identifiers */ struct os_reltime sa_query_start; u8 sched_obss_scan; u16 obss_scan_int; u16 bss_max_idle_period; #ifdef CONFIG_SAE struct sae_data sae; struct wpabuf *sae_token; int sae_group_index; #endif /* CONFIG_SAE */ } sme; #endif /* CONFIG_SME */ #ifdef CONFIG_AP struct hostapd_iface *ap_iface; void (*ap_configured_cb)(void *ctx, void *data); void *ap_configured_cb_ctx; void *ap_configured_cb_data; #endif /* CONFIG_AP */ unsigned int off_channel_freq; struct wpabuf *pending_action_tx; u8 pending_action_src[ETH_ALEN]; u8 pending_action_dst[ETH_ALEN]; u8 pending_action_bssid[ETH_ALEN]; unsigned int pending_action_freq; int pending_action_no_cck; int pending_action_without_roc; unsigned int pending_action_tx_done:1; void (*pending_action_tx_status_cb)(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *data, size_t data_len, enum offchannel_send_action_result result); unsigned int roc_waiting_drv_freq; int action_tx_wait_time; int p2p_mgmt; #ifdef CONFIG_P2P struct p2p_go_neg_results *go_params; int create_p2p_iface; u8 pending_interface_addr[ETH_ALEN]; char pending_interface_name[100]; int pending_interface_type; int p2p_group_idx; unsigned int pending_listen_freq; unsigned int pending_listen_duration; enum { NOT_P2P_GROUP_INTERFACE, P2P_GROUP_INTERFACE_PENDING, P2P_GROUP_INTERFACE_GO, P2P_GROUP_INTERFACE_CLIENT } p2p_group_interface; struct p2p_group *p2p_group; int p2p_long_listen; /* remaining time in long Listen state in ms */ char p2p_pin[10]; int p2p_wps_method; u8 p2p_auth_invite[ETH_ALEN]; int p2p_sd_over_ctrl_iface; int p2p_in_provisioning; int p2p_in_invitation; int p2p_invite_go_freq; int pending_invite_ssid_id; int show_group_started; u8 go_dev_addr[ETH_ALEN]; int pending_pd_before_join; u8 pending_join_iface_addr[ETH_ALEN]; u8 pending_join_dev_addr[ETH_ALEN]; int pending_join_wps_method; u8 p2p_join_ssid[32]; size_t p2p_join_ssid_len; int p2p_join_scan_count; int auto_pd_scan_retry; int force_long_sd; u16 pending_pd_config_methods; enum { NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN } pending_pd_use; /* * Whether cross connection is disallowed by the AP to which this * interface is associated (only valid if there is an association). */ int cross_connect_disallowed; /* * Whether this P2P group is configured to use cross connection (only * valid if this is P2P GO interface). The actual cross connect packet * forwarding may not be configured depending on the uplink status. */ int cross_connect_enabled; /* Whether cross connection forwarding is in use at the moment. */ int cross_connect_in_use; /* * Uplink interface name for cross connection */ char cross_connect_uplink[100]; unsigned int p2p_auto_join:1; unsigned int p2p_auto_pd:1; unsigned int p2p_persistent_group:1; unsigned int p2p_fallback_to_go_neg:1; unsigned int p2p_pd_before_go_neg:1; unsigned int p2p_go_ht40:1; unsigned int p2p_go_vht:1; unsigned int user_initiated_pd:1; unsigned int p2p_go_group_formation_completed:1; unsigned int waiting_presence_resp; int p2p_first_connection_timeout; unsigned int p2p_nfc_tag_enabled:1; unsigned int p2p_peer_oob_pk_hash_known:1; unsigned int p2p_disable_ip_addr_req:1; int p2p_persistent_go_freq; int p2p_persistent_id; int p2p_go_intent; int p2p_connect_freq; struct os_reltime p2p_auto_started; struct wpa_ssid *p2p_last_4way_hs_fail; struct wpa_radio_work *p2p_scan_work; struct wpa_radio_work *p2p_listen_work; struct wpa_radio_work *p2p_send_action_work; u16 p2p_oob_dev_pw_id; /* OOB Device Password Id for group formation */ struct wpabuf *p2p_oob_dev_pw; /* OOB Device Password for group * formation */ u8 p2p_peer_oob_pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN]; u8 p2p_ip_addr_info[3 * 4]; #endif /* CONFIG_P2P */ struct wpa_ssid *bgscan_ssid; const struct bgscan_ops *bgscan; void *bgscan_priv; const struct autoscan_ops *autoscan; struct wpa_driver_scan_params *autoscan_params; void *autoscan_priv; struct wpa_ssid *connect_without_scan; struct wps_ap_info *wps_ap; size_t num_wps_ap; int wps_ap_iter; int after_wps; int known_wps_freq; unsigned int wps_freq; int wps_fragment_size; int auto_reconnect_disabled; /* Channel preferences for AP/P2P GO use */ int best_24_freq; int best_5_freq; int best_overall_freq; struct gas_query *gas; #ifdef CONFIG_INTERWORKING unsigned int fetch_anqp_in_progress:1; unsigned int network_select:1; unsigned int auto_select:1; unsigned int auto_network_select:1; unsigned int fetch_all_anqp:1; unsigned int fetch_osu_info:1; unsigned int fetch_osu_icon_in_progress:1; struct wpa_bss *interworking_gas_bss; unsigned int osu_icon_id; struct osu_provider *osu_prov; size_t osu_prov_count; struct os_reltime osu_icon_fetch_start; unsigned int num_osu_scans; unsigned int num_prov_found; #endif /* CONFIG_INTERWORKING */ unsigned int drv_capa_known; struct { struct hostapd_hw_modes *modes; u16 num_modes; u16 flags; } hw; #ifdef CONFIG_MACSEC struct ieee802_1x_kay *kay; #endif /* CONFIG_MACSEC */ int pno; int pno_sched_pending; /* WLAN_REASON_* reason codes. Negative if locally generated. */ int disconnect_reason; struct ext_password_data *ext_pw; struct wpabuf *last_gas_resp, *prev_gas_resp; u8 last_gas_addr[ETH_ALEN], prev_gas_addr[ETH_ALEN]; u8 last_gas_dialog_token, prev_gas_dialog_token; unsigned int no_keep_alive:1; unsigned int ext_mgmt_frame_handling:1; #ifdef CONFIG_WNM u8 wnm_dialog_token; u8 wnm_reply; u8 wnm_num_neighbor_report; u8 wnm_mode; u16 wnm_dissoc_timer; u8 wnm_validity_interval; u8 wnm_bss_termination_duration[12]; struct neighbor_report *wnm_neighbor_report_elements; #endif /* CONFIG_WNM */ #ifdef CONFIG_TESTING_GET_GTK u8 last_gtk[32]; size_t last_gtk_len; #endif /* CONFIG_TESTING_GET_GTK */ unsigned int num_multichan_concurrent; struct wpa_radio_work *connect_work; unsigned int ext_work_id; }; /* wpa_supplicant.c */ void wpa_supplicant_apply_ht_overrides( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_driver_associate_params *params); void wpa_supplicant_apply_vht_overrides( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_driver_associate_params *params); int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s); const char * wpa_supplicant_state_txt(enum wpa_states state); int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s); int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s); int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid, u8 *wpa_ie, size_t *wpa_ie_len); void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid); void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s); void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr); void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s, int sec, int usec); void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s); void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, enum wpa_states state); struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s); const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s); void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s); void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, int reason_code); void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s, const char *pkcs11_engine_path, const char *pkcs11_module_path); int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan); int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s, unsigned int expire_age); int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s, unsigned int expire_count); int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s, int scan_interval); int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level, int debug_timestamp, int debug_show_keys); void free_hw_features(struct wpa_supplicant *wpa_s); void wpa_show_license(void); struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global, struct wpa_interface *iface); int wpa_supplicant_remove_iface(struct wpa_global *global, struct wpa_supplicant *wpa_s, int terminate); struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global, const char *ifname); struct wpa_global * wpa_supplicant_init(struct wpa_params *params); int wpa_supplicant_run(struct wpa_global *global); void wpa_supplicant_deinit(struct wpa_global *global); int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_terminate_proc(struct wpa_global *global); void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, const u8 *buf, size_t len); void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s); void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s); void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid); int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s); int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s); void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason); void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int clear_failures); int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid); int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid, size_t ssid_len); void wpas_request_connection(struct wpa_supplicant *wpa_s); int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf); /** * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response * @wpa_s: Pointer to wpa_supplicant data * @ssid: Pointer to the network block the reply is for * @field: field the response is a reply for * @value: value (ie, password, etc) for @field * Returns: 0 on success, non-zero on error * * Helper function to handle replies to control interface requests. */ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, const char *field, const char *value); /* events.c */ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s); int wpa_supplicant_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *selected, struct wpa_ssid *ssid); void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx); void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx); void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s); int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s); struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s, struct wpa_ssid **selected_ssid); /* eap_register.c */ int eap_register_methods(void); /** * Utility method to tell if a given network is a persistent group * @ssid: Network object * Returns: 1 if network is a persistent group, 0 otherwise */ static inline int network_is_persistent_group(struct wpa_ssid *ssid) { return ((ssid->disabled == 2) || ssid->p2p_persistent_group); } int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int wpas_init_ext_pw(struct wpa_supplicant *wpa_s); void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title, int *freq_array, unsigned int len); int get_shared_radio_freqs(struct wpa_supplicant *wpa_s, int *freq_array, unsigned int len); #endif /* WPA_SUPPLICANT_I_H */ wpa_supplicant-2.2/wpa_supplicant/README-Windows.txt0000664000175000017500000003016312343617166020401 0ustar jmjmwpa_supplicant for Windows ========================== Copyright (c) 2003-2009, Jouni Malinen and contributors All Rights Reserved. This program is licensed under the BSD license (the one with advertisement clause removed). wpa_supplicant has support for being used as a WPA/WPA2/IEEE 802.1X Supplicant on Windows. The current port requires that WinPcap (http://winpcap.polito.it/) is installed for accessing packets and the driver interface. Both release versions 3.0 and 3.1 are supported. The current port is still somewhat experimental. It has been tested mainly on Windows XP (SP2) with limited set of NDIS drivers. In addition, the current version has been reported to work with Windows 2000. All security modes have been verified to work (at least complete authentication and successfully ping a wired host): - plaintext - static WEP / open system authentication - static WEP / shared key authentication - IEEE 802.1X with dynamic WEP keys - WPA-PSK, TKIP, CCMP, TKIP+CCMP - WPA-EAP, TKIP, CCMP, TKIP+CCMP - WPA2-PSK, TKIP, CCMP, TKIP+CCMP - WPA2-EAP, TKIP, CCMP, TKIP+CCMP Building wpa_supplicant with mingw ---------------------------------- The default build setup for wpa_supplicant is to use MinGW and cross-compiling from Linux to MinGW/Windows. It should also be possible to build this under Windows using the MinGW tools, but that is not tested nor supported and is likely to require some changes to the Makefile unless cygwin is used. Building wpa_supplicant with MSVC --------------------------------- wpa_supplicant can be built with Microsoft Visual C++ compiler. This has been tested with Microsoft Visual C++ Toolkit 2003 and Visual Studio 2005 using the included nmake.mak as a Makefile for nmake. IDE can also be used by creating a project that includes the files and defines mentioned in nmake.mak. Example VS2005 solution and project files are included in vs2005 subdirectory. This can be used as a starting point for building the programs with VS2005 IDE. Visual Studio 2008 Express Edition is also able to use these project files. WinPcap development package is needed for the build and this can be downloaded from http://www.winpcap.org/install/bin/WpdPack_4_0_2.zip. The default nmake.mak expects this to be unpacked into C:\dev\WpdPack so that Include and Lib directories are in this directory. The files can be stored elsewhere as long as the WINPCAPDIR in nmake.mak is updated to match with the selected directory. In case a project file in the IDE is used, these Include and Lib directories need to be added to project properties as additional include/library directories. OpenSSL source package can be downloaded from http://www.openssl.org/source/openssl-0.9.8i.tar.gz and built and installed following instructions in INSTALL.W32. Note that if EAP-FAST support will be included in the wpa_supplicant, OpenSSL needs to be patched to# support it openssl-0.9.8i-tls-extensions.patch. The example nmake.mak file expects OpenSSL to be installed into C:\dev\openssl, but this directory can be modified by changing OPENSSLDIR variable in nmake.mak. If you do not need EAP-FAST support, you may also be able to use Win32 binary installation package of OpenSSL from http://www.slproweb.com/products/Win32OpenSSL.html instead of building the library yourself. In this case, you will need to copy Include and Lib directories in suitable directory, e.g., C:\dev\openssl for the default nmake.mak. Copy {Win32OpenSSLRoot}\include into C:\dev\openssl\include and make C:\dev\openssl\lib subdirectory with files from {Win32OpenSSLRoot}\VC (i.e., libeay*.lib and ssleay*.lib). This will end up using dynamically linked OpenSSL (i.e., .dll files are needed) for it. Alternative, you can copy files from {Win32OpenSSLRoot}\VC\static to create a static build (no OpenSSL .dll files needed). Building wpa_supplicant for cygwin ---------------------------------- wpa_supplicant can be built for cygwin by installing the needed development packages for cygwin. This includes things like compiler, make, openssl development package, etc. In addition, developer's pack for WinPcap (WPdpack.zip) from http://winpcap.polito.it/install/default.htm is needed. .config file should enable only one driver interface, CONFIG_DRIVER_NDIS. In addition, include directories may need to be added to match the system. An example configuration is available in defconfig. The library and include files for WinPcap will either need to be installed in compiler/linker default directories or their location will need to be adding to .config when building wpa_supplicant. Othen than this, the build should be more or less identical to Linux version, i.e., just run make after having created .config file. An additional tool, win_if_list.exe, can be built by running "make win_if_list". Building wpa_gui ---------------- wpa_gui uses Qt application framework from Trolltech. It can be built with the open source version of Qt4 and MinGW. Following commands can be used to build the binary in the Qt 4 Command Prompt: # go to the root directory of wpa_supplicant source code cd wpa_gui-qt4 qmake -o Makefile wpa_gui.pro make # the wpa_gui.exe binary is created into 'release' subdirectory Using wpa_supplicant for Windows -------------------------------- wpa_supplicant, wpa_cli, and wpa_gui behave more or less identically to Linux version, so instructions in README and example wpa_supplicant.conf should be applicable for most parts. In addition, there is another version of wpa_supplicant, wpasvc.exe, which can be used as a Windows service and which reads its configuration from registry instead of text file. When using access points in "hidden SSID" mode, ap_scan=2 mode need to be used (see wpa_supplicant.conf for more information). Windows NDIS/WinPcap uses quite long interface names, so some care will be needed when starting wpa_supplicant. Alternatively, the adapter description can be used as the interface name which may be easier since it is usually in more human-readable format. win_if_list.exe can be used to find out the proper interface name. Example steps in starting up wpa_supplicant: # win_if_list.exe ifname: \Device\NPF_GenericNdisWanAdapter description: Generic NdisWan adapter ifname: \Device\NPF_{769E012B-FD17-4935-A5E3-8090C38E25D2} description: Atheros Wireless Network Adapter (Microsoft's Packet Scheduler) ifname: \Device\NPF_{732546E7-E26C-48E3-9871-7537B020A211} description: Intel 8255x-based Integrated Fast Ethernet (Microsoft's Packet Scheduler) Since the example configuration used Atheros WLAN card, the middle one is the correct interface in this case. The interface name for -i command line option is the full string following "ifname:" (the "\Device\NPF_" prefix can be removed). In other words, wpa_supplicant would be started with the following command: # wpa_supplicant.exe -i'{769E012B-FD17-4935-A5E3-8090C38E25D2}' -c wpa_supplicant.conf -d -d optional enables some more debugging (use -dd for even more, if needed). It can be left out if debugging information is not needed. With the alternative mechanism for selecting the interface, this command has identical results in this case: # wpa_supplicant.exe -iAtheros -c wpa_supplicant.conf -d Simple configuration example for WPA-PSK: #ap_scan=2 ctrl_interface= network={ ssid="test" key_mgmt=WPA-PSK proto=WPA pairwise=TKIP psk="secret passphrase" } (remove '#' from the comment out ap_scan line to enable mode in which wpa_supplicant tries to associate with the SSID without doing scanning; this allows APs with hidden SSIDs to be used) wpa_cli.exe and wpa_gui.exe can be used to interact with the wpa_supplicant.exe program in the same way as with Linux. Note that ctrl_interface is using UNIX domain sockets when built for cygwin, but the native build for Windows uses named pipes and the contents of the ctrl_interface configuration item is used to control access to the interface. Anyway, this variable has to be included in the configuration to enable the control interface. Example SDDL string formats: (local admins group has permission, but nobody else): ctrl_interface=SDDL=D:(A;;GA;;;BA) ("A" == "access allowed", "GA" == GENERIC_ALL == all permissions, and "BA" == "builtin administrators" == the local admins. The empty fields are for flags and object GUIDs, none of which should be required in this case.) (local admins and the local "power users" group have permissions, but nobody else): ctrl_interface=SDDL=D:(A;;GA;;;BA)(A;;GA;;;PU) (One ACCESS_ALLOWED ACE for GENERIC_ALL for builtin administrators, and one ACCESS_ALLOWED ACE for GENERIC_ALL for power users.) (close to wide open, but you have to be a valid user on the machine): ctrl_interface=SDDL=D:(A;;GA;;;AU) (One ACCESS_ALLOWED ACE for GENERIC_ALL for the "authenticated users" group.) This one would allow absolutely everyone (including anonymous users) -- this is *not* recommended, since named pipes can be attached to from anywhere on the network (i.e. there's no "this machine only" like there is with 127.0.0.1 sockets): ctrl_interface=SDDL=D:(A;;GA;;;BU)(A;;GA;;;AN) (BU == "builtin users", "AN" == "anonymous") See also [1] for the format of ACEs, and [2] for the possible strings that can be used for principal names. [1] http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/ace_strings.asp [2] http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/sid_strings.asp Starting wpa_supplicant as a Windows service (wpasvc.exe) --------------------------------------------------------- wpa_supplicant can be started as a Windows service by using wpasvc.exe program that is alternative build of wpa_supplicant.exe. Most of the core functionality of wpasvc.exe is identical to wpa_supplicant.exe, but it is using Windows registry for configuration information instead of a text file and command line parameters. In addition, it can be registered as a service that can be started automatically or manually like any other Windows service. The root of wpa_supplicant configuration in registry is HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant. This level includes global parameters and a 'interfaces' subkey with all the interface configuration (adapter to confname mapping). Each such mapping is a subkey that has 'adapter', 'config', and 'ctrl_interface' values. This program can be run either as a normal command line application, e.g., for debugging, with 'wpasvc.exe app' or as a Windows service. Service need to be registered with 'wpasvc.exe reg '. Alternatively, 'wpasvc.exe reg' can be used to register the service with the current location of wpasvc.exe. After this, wpasvc can be started like any other Windows service (e.g., 'net start wpasvc') or it can be configured to start automatically through the Services tool in administrative tasks. The service can be unregistered with 'wpasvc.exe unreg'. If the service is set to start during system bootup to make the network connection available before any user has logged in, there may be a long (half a minute or so) delay in starting up wpa_supplicant due to WinPcap needing a driver called "Network Monitor Driver" which is started by default on demand. To speed up wpa_supplicant start during system bootup, "Network Monitor Driver" can be configured to be started sooner by setting its startup type to System instead of the default Demand. To do this, open up Device Manager, select Show Hidden Devices, expand the "Non Plug-and-Play devices" branch, double click "Network Monitor Driver", go to the Driver tab, and change the Demand setting to System instead. Configuration data is in HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs key. Each configuration profile has its own key under this. In terms of text files, each profile would map to a separate text file with possibly multiple networks. Under each profile, there is a networks key that lists all networks as a subkey. Each network has set of values in the same way as network block in the configuration file. In addition, blobs subkey has possible blobs as values. HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000 ssid="example" key_mgmt=WPA-PSK See win_example.reg for an example on how to setup wpasvc.exe parameters in registry. It can also be imported to registry as a starting point for the configuration. wpa_supplicant-2.2/wpa_supplicant/config_none.c0000664000175000017500000000240212343617166017676 0ustar jmjm/* * WPA Supplicant / Configuration backend: empty starting point * Copyright (c) 2003-2005, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. * * This file implements dummy example of a configuration backend. None of the * functions are actually implemented so this can be used as a simple * compilation test or a starting point for a new configuration backend. */ #include "includes.h" #include "common.h" #include "config.h" #include "base64.h" struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) { struct wpa_config *config; if (name == NULL) return NULL; if (cfgp) config = cfgp; else config = wpa_config_alloc_empty(NULL, NULL); if (config == NULL) return NULL; /* TODO: fill in configuration data */ return config; } int wpa_config_write(const char *name, struct wpa_config *config) { struct wpa_ssid *ssid; struct wpa_config_blob *blob; wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name); /* TODO: write global config parameters */ for (ssid = config->ssid; ssid; ssid = ssid->next) { /* TODO: write networks */ } for (blob = config->blobs; blob; blob = blob->next) { /* TODO: write blobs */ } return 0; } wpa_supplicant-2.2/wpa_supplicant/ctrl_iface_named_pipe.c0000664000175000017500000004726012343617166021701 0ustar jmjm/* * WPA Supplicant / Windows Named Pipe -based control interface * Copyright (c) 2004-2006, 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 "eloop.h" #include "config.h" #include "eapol_supp/eapol_supp_sm.h" #include "wpa_supplicant_i.h" #include "ctrl_iface.h" #include "common/wpa_ctrl.h" #ifdef __MINGW32_VERSION /* mingw-w32api v3.1 does not yet include sddl.h, so define needed parts here */ #define SDDL_REVISION_1 1 BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA( LPCSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG); BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW( LPCWSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG); #ifdef UNICODE #define ConvertStringSecurityDescriptorToSecurityDescriptor \ ConvertStringSecurityDescriptorToSecurityDescriptorW #else #define ConvertStringSecurityDescriptorToSecurityDescriptor \ ConvertStringSecurityDescriptorToSecurityDescriptorA #endif #else /* __MINGW32_VERSION */ #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0500 #endif #include #endif /* __MINGW32_VERSION */ #ifndef WPA_SUPPLICANT_NAMED_PIPE #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" #endif #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) /* Per-interface ctrl_iface */ #define REQUEST_BUFSIZE 256 #define REPLY_BUFSIZE 4096 struct ctrl_iface_priv; /** * struct wpa_ctrl_dst - Internal data structure of control interface clients * * This structure is used to store information about registered control * interface monitors into struct wpa_supplicant. This data is private to * ctrl_iface_named_pipe.c and should not be touched directly from other files. */ struct wpa_ctrl_dst { /* Note: OVERLAPPED must be the first member of struct wpa_ctrl_dst */ OVERLAPPED overlap; struct wpa_ctrl_dst *next, *prev; struct ctrl_iface_priv *priv; HANDLE pipe; int attached; int debug_level; int errors; char req_buf[REQUEST_BUFSIZE]; char *rsp_buf; int used; }; struct ctrl_iface_priv { struct wpa_supplicant *wpa_s; struct wpa_ctrl_dst *ctrl_dst; SECURITY_ATTRIBUTES attr; int sec_attr_set; }; static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, int level, const char *buf, size_t len); static void ctrl_close_pipe(struct wpa_ctrl_dst *dst); static void wpa_supplicant_ctrl_iface_receive(void *, void *); static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, LPOVERLAPPED overlap); struct wpa_global_dst; static void global_close_pipe(struct wpa_global_dst *dst); static void wpa_supplicant_global_iface_receive(void *eloop_data, void *user_ctx); static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, LPOVERLAPPED overlap); static int ctrl_broken_pipe(HANDLE pipe, int used) { DWORD err; if (PeekNamedPipe(pipe, NULL, 0, NULL, NULL, NULL)) return 0; err = GetLastError(); if (err == ERROR_BROKEN_PIPE || (err == ERROR_BAD_PIPE && used)) return 1; return 0; } static void ctrl_flush_broken_pipes(struct ctrl_iface_priv *priv) { struct wpa_ctrl_dst *dst, *next; dst = priv->ctrl_dst; while (dst) { next = dst->next; if (ctrl_broken_pipe(dst->pipe, dst->used)) { wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", dst); ctrl_close_pipe(dst); } dst = next; } } static int ctrl_open_pipe(struct ctrl_iface_priv *priv) { struct wpa_ctrl_dst *dst; DWORD err; TCHAR name[256]; dst = os_zalloc(sizeof(*dst)); if (dst == NULL) return -1; wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); dst->priv = priv; dst->debug_level = MSG_INFO; dst->pipe = INVALID_HANDLE_VALUE; dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); if (dst->overlap.hEvent == NULL) { wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", (int) GetLastError()); goto fail; } eloop_register_event(dst->overlap.hEvent, sizeof(dst->overlap.hEvent), wpa_supplicant_ctrl_iface_receive, dst, NULL); #ifdef UNICODE _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), priv->wpa_s->ifname); #else /* UNICODE */ os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", priv->wpa_s->ifname); #endif /* UNICODE */ /* TODO: add support for configuring access list for the pipe */ dst->pipe = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 15, REPLY_BUFSIZE, REQUEST_BUFSIZE, 1000, priv->sec_attr_set ? &priv->attr : NULL); if (dst->pipe == INVALID_HANDLE_VALUE) { wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", (int) GetLastError()); goto fail; } if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", (int) GetLastError()); CloseHandle(dst->pipe); os_free(dst); return -1; } err = GetLastError(); switch (err) { case ERROR_IO_PENDING: wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " "progress"); break; case ERROR_PIPE_CONNECTED: wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " "connected"); if (SetEvent(dst->overlap.hEvent)) break; /* fall through */ default: wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", (int) err); CloseHandle(dst->pipe); os_free(dst); return -1; } dst->next = priv->ctrl_dst; if (dst->next) dst->next->prev = dst; priv->ctrl_dst = dst; return 0; fail: ctrl_close_pipe(dst); return -1; } static void ctrl_close_pipe(struct wpa_ctrl_dst *dst) { wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); if (dst->overlap.hEvent) { eloop_unregister_event(dst->overlap.hEvent, sizeof(dst->overlap.hEvent)); CloseHandle(dst->overlap.hEvent); } if (dst->pipe != INVALID_HANDLE_VALUE) { /* * Could use FlushFileBuffers() here to guarantee that all data * gets delivered to the client, but that can block, so let's * not do this for now. * FlushFileBuffers(dst->pipe); */ CloseHandle(dst->pipe); } if (dst->prev) dst->prev->next = dst->next; else dst->priv->ctrl_dst = dst->next; if (dst->next) dst->next->prev = dst->prev; os_free(dst->rsp_buf); os_free(dst); } static VOID WINAPI ctrl_iface_write_completed(DWORD err, DWORD bytes, LPOVERLAPPED overlap) { struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " "err=%d bytes=%d", dst, (int) err, (int) bytes); if (err) { ctrl_close_pipe(dst); return; } os_free(dst->rsp_buf); dst->rsp_buf = NULL; if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), &dst->overlap, ctrl_iface_read_completed)) { wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", (int) GetLastError()); ctrl_close_pipe(dst); return; } wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); } static void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst *dst, size_t len) { struct wpa_supplicant *wpa_s = dst->priv->wpa_s; char *reply = NULL, *send_buf; size_t reply_len = 0, send_len; int new_attached = 0; char *buf = dst->req_buf; dst->used = 1; if (len >= REQUEST_BUFSIZE) len = REQUEST_BUFSIZE - 1; buf[len] = '\0'; if (os_strcmp(buf, "ATTACH") == 0) { dst->attached = 1; wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached"); new_attached = 1; reply_len = 2; } else if (os_strcmp(buf, "DETACH") == 0) { dst->attached = 0; wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached"); reply_len = 2; } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", buf + 6); dst->debug_level = atoi(buf + 6); reply_len = 2; } else { reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf, &reply_len); } if (reply) { send_buf = reply; send_len = reply_len; } else if (reply_len == 2) { send_buf = "OK\n"; send_len = 3; } else { send_buf = "FAIL\n"; send_len = 5; } os_free(dst->rsp_buf); dst->rsp_buf = os_malloc(send_len); if (dst->rsp_buf == NULL) { ctrl_close_pipe(dst); os_free(reply); return; } os_memcpy(dst->rsp_buf, send_buf, send_len); os_free(reply); if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, ctrl_iface_write_completed)) { wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", (int) GetLastError()); ctrl_close_pipe(dst); } else { wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", dst); } if (new_attached) eapol_sm_notify_ctrl_attached(wpa_s->eapol); } static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, LPOVERLAPPED overlap) { struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " "bytes=%d", dst, (int) err, (int) bytes); if (err == 0 && bytes > 0) wpa_supplicant_ctrl_iface_rx(dst, bytes); } static void wpa_supplicant_ctrl_iface_receive(void *eloop_data, void *user_ctx) { struct wpa_ctrl_dst *dst = eloop_data; struct ctrl_iface_priv *priv = dst->priv; DWORD bytes; wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_ctrl_iface_receive"); ResetEvent(dst->overlap.hEvent); if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", (int) GetLastError()); return; } wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " "connected"); /* Open a new named pipe for the next client. */ ctrl_open_pipe(priv); /* Use write completion function to start reading a command */ ctrl_iface_write_completed(0, 0, &dst->overlap); ctrl_flush_broken_pipes(priv); } static int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params) { const char *sddl = NULL; TCHAR *t_sddl; if (os_strncmp(params, "SDDL=", 5) == 0) sddl = params + 5; if (!sddl) { sddl = os_strstr(params, " SDDL="); if (sddl) sddl += 6; } if (!sddl) return 0; wpa_printf(MSG_DEBUG, "CTRL: SDDL='%s'", sddl); os_memset(&priv->attr, 0, sizeof(priv->attr)); priv->attr.nLength = sizeof(priv->attr); priv->attr.bInheritHandle = FALSE; t_sddl = wpa_strdup_tchar(sddl); if (t_sddl == NULL) return -1; if (!ConvertStringSecurityDescriptorToSecurityDescriptor( t_sddl, SDDL_REVISION_1, (PSECURITY_DESCRIPTOR *) (void *) &priv->attr.lpSecurityDescriptor, NULL)) { os_free(t_sddl); wpa_printf(MSG_ERROR, "CTRL: SDDL='%s' - could not convert to " "security descriptor: %d", sddl, (int) GetLastError()); return -1; } os_free(t_sddl); priv->sec_attr_set = 1; return 0; } static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global, const char *txt, size_t len) { struct wpa_supplicant *wpa_s = ctx; if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) return; wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); } struct ctrl_iface_priv * wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) { struct ctrl_iface_priv *priv; priv = os_zalloc(sizeof(*priv)); if (priv == NULL) return NULL; priv->wpa_s = wpa_s; if (wpa_s->conf->ctrl_interface == NULL) return priv; if (ctrl_iface_parse(priv, wpa_s->conf->ctrl_interface) < 0) { os_free(priv); return NULL; } if (ctrl_open_pipe(priv) < 0) { os_free(priv); return NULL; } wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); return priv; } void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) { while (priv->ctrl_dst) ctrl_close_pipe(priv->ctrl_dst); if (priv->sec_attr_set) LocalFree(priv->attr.lpSecurityDescriptor); os_free(priv); } static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, int level, const char *buf, size_t len) { struct wpa_ctrl_dst *dst, *next; char levelstr[10]; int idx; char *sbuf; int llen; DWORD written; dst = priv->ctrl_dst; if (dst == NULL) return; os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); llen = os_strlen(levelstr); sbuf = os_malloc(llen + len); if (sbuf == NULL) return; os_memcpy(sbuf, levelstr, llen); os_memcpy(sbuf + llen, buf, len); idx = 0; while (dst) { next = dst->next; if (dst->attached && level >= dst->debug_level) { wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %p", dst); if (!WriteFile(dst->pipe, sbuf, llen + len, &written, NULL)) { wpa_printf(MSG_DEBUG, "CTRL: WriteFile to dst " "%p failed: %d", dst, (int) GetLastError()); dst->errors++; if (dst->errors > 10) ctrl_close_pipe(dst); } else dst->errors = 0; } idx++; dst = next; } os_free(sbuf); } void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) { wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", priv->wpa_s->ifname); if (priv->ctrl_dst == NULL) return; WaitForSingleObject(priv->ctrl_dst->pipe, INFINITE); } /* Global ctrl_iface */ struct ctrl_iface_global_priv; struct wpa_global_dst { /* Note: OVERLAPPED must be the first member of struct wpa_global_dst */ OVERLAPPED overlap; struct wpa_global_dst *next, *prev; struct ctrl_iface_global_priv *priv; HANDLE pipe; char req_buf[REQUEST_BUFSIZE]; char *rsp_buf; int used; }; struct ctrl_iface_global_priv { struct wpa_global *global; struct wpa_global_dst *ctrl_dst; }; static void global_flush_broken_pipes(struct ctrl_iface_global_priv *priv) { struct wpa_global_dst *dst, *next; dst = priv->ctrl_dst; while (dst) { next = dst->next; if (ctrl_broken_pipe(dst->pipe, dst->used)) { wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", dst); global_close_pipe(dst); } dst = next; } } static int global_open_pipe(struct ctrl_iface_global_priv *priv) { struct wpa_global_dst *dst; DWORD err; dst = os_zalloc(sizeof(*dst)); if (dst == NULL) return -1; wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); dst->priv = priv; dst->pipe = INVALID_HANDLE_VALUE; dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); if (dst->overlap.hEvent == NULL) { wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", (int) GetLastError()); goto fail; } eloop_register_event(dst->overlap.hEvent, sizeof(dst->overlap.hEvent), wpa_supplicant_global_iface_receive, dst, NULL); /* TODO: add support for configuring access list for the pipe */ dst->pipe = CreateNamedPipe(NAMED_PIPE_PREFIX, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 10, REPLY_BUFSIZE, REQUEST_BUFSIZE, 1000, NULL); if (dst->pipe == INVALID_HANDLE_VALUE) { wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", (int) GetLastError()); goto fail; } if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", (int) GetLastError()); CloseHandle(dst->pipe); os_free(dst); return -1; } err = GetLastError(); switch (err) { case ERROR_IO_PENDING: wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " "progress"); break; case ERROR_PIPE_CONNECTED: wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " "connected"); if (SetEvent(dst->overlap.hEvent)) break; /* fall through */ default: wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", (int) err); CloseHandle(dst->pipe); os_free(dst); return -1; } dst->next = priv->ctrl_dst; if (dst->next) dst->next->prev = dst; priv->ctrl_dst = dst; return 0; fail: global_close_pipe(dst); return -1; } static void global_close_pipe(struct wpa_global_dst *dst) { wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); if (dst->overlap.hEvent) { eloop_unregister_event(dst->overlap.hEvent, sizeof(dst->overlap.hEvent)); CloseHandle(dst->overlap.hEvent); } if (dst->pipe != INVALID_HANDLE_VALUE) { /* * Could use FlushFileBuffers() here to guarantee that all data * gets delivered to the client, but that can block, so let's * not do this for now. * FlushFileBuffers(dst->pipe); */ CloseHandle(dst->pipe); } if (dst->prev) dst->prev->next = dst->next; else dst->priv->ctrl_dst = dst->next; if (dst->next) dst->next->prev = dst->prev; os_free(dst->rsp_buf); os_free(dst); } static VOID WINAPI global_iface_write_completed(DWORD err, DWORD bytes, LPOVERLAPPED overlap) { struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " "err=%d bytes=%d", dst, (int) err, (int) bytes); if (err) { global_close_pipe(dst); return; } os_free(dst->rsp_buf); dst->rsp_buf = NULL; if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), &dst->overlap, global_iface_read_completed)) { wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", (int) GetLastError()); global_close_pipe(dst); /* FIX: if this was the pipe waiting for new global * connections, at this point there are no open global pipes.. * Should try to open a new pipe.. */ return; } wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); } static void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst, size_t len) { struct wpa_global *global = dst->priv->global; char *reply = NULL, *send_buf; size_t reply_len = 0, send_len; char *buf = dst->req_buf; dst->used = 1; if (len >= REQUEST_BUFSIZE) len = REQUEST_BUFSIZE - 1; buf[len] = '\0'; reply = wpa_supplicant_global_ctrl_iface_process(global, buf, &reply_len); if (reply) { send_buf = reply; send_len = reply_len; } else if (reply_len) { send_buf = "FAIL\n"; send_len = 5; } else { os_free(dst->rsp_buf); dst->rsp_buf = NULL; return; } os_free(dst->rsp_buf); dst->rsp_buf = os_malloc(send_len); if (dst->rsp_buf == NULL) { global_close_pipe(dst); os_free(reply); return; } os_memcpy(dst->rsp_buf, send_buf, send_len); os_free(reply); if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, global_iface_write_completed)) { wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", (int) GetLastError()); global_close_pipe(dst); } else { wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", dst); } } static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, LPOVERLAPPED overlap) { struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " "bytes=%d", dst, (int) err, (int) bytes); if (err == 0 && bytes > 0) wpa_supplicant_global_iface_rx(dst, bytes); } static void wpa_supplicant_global_iface_receive(void *eloop_data, void *user_ctx) { struct wpa_global_dst *dst = eloop_data; struct ctrl_iface_global_priv *priv = dst->priv; DWORD bytes; wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_global_iface_receive"); ResetEvent(dst->overlap.hEvent); if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", (int) GetLastError()); return; } wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " "connected"); /* Open a new named pipe for the next client. */ if (global_open_pipe(priv) < 0) { wpa_printf(MSG_DEBUG, "CTRL: global_open_pipe failed"); return; } /* Use write completion function to start reading a command */ global_iface_write_completed(0, 0, &dst->overlap); global_flush_broken_pipes(priv); } struct ctrl_iface_global_priv * wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) { struct ctrl_iface_global_priv *priv; priv = os_zalloc(sizeof(*priv)); if (priv == NULL) return NULL; priv->global = global; if (global_open_pipe(priv) < 0) { os_free(priv); return NULL; } return priv; } void wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) { while (priv->ctrl_dst) global_close_pipe(priv->ctrl_dst); os_free(priv); } wpa_supplicant-2.2/wpa_supplicant/ctrl_iface_unix.c0000664000175000017500000006556312343617166020571 0ustar jmjm/* * WPA Supplicant / UNIX domain socket -based control interface * Copyright (c) 2004-2014, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include #include #include #include #include #include #ifdef ANDROID #include #endif /* ANDROID */ #include "utils/common.h" #include "utils/eloop.h" #include "utils/list.h" #include "eapol_supp/eapol_supp_sm.h" #include "config.h" #include "wpa_supplicant_i.h" #include "ctrl_iface.h" /* Per-interface ctrl_iface */ /** * struct wpa_ctrl_dst - Internal data structure of control interface monitors * * This structure is used to store information about registered control * interface monitors into struct wpa_supplicant. This data is private to * ctrl_iface_unix.c and should not be touched directly from other files. */ struct wpa_ctrl_dst { struct dl_list list; struct sockaddr_un addr; socklen_t addrlen; int debug_level; int errors; }; struct ctrl_iface_priv { struct wpa_supplicant *wpa_s; int sock; struct dl_list ctrl_dst; }; struct ctrl_iface_global_priv { struct wpa_global *global; int sock; struct dl_list ctrl_dst; }; static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, const char *ifname, int sock, struct dl_list *ctrl_dst, int level, const char *buf, size_t len, struct ctrl_iface_priv *priv, struct ctrl_iface_global_priv *gp); static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s, struct ctrl_iface_priv *priv); static int wpas_ctrl_iface_global_reinit(struct wpa_global *global, struct ctrl_iface_global_priv *priv); static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_un *from, socklen_t fromlen) { struct wpa_ctrl_dst *dst; char addr_txt[200]; dst = os_zalloc(sizeof(*dst)); if (dst == NULL) return -1; os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); dst->addrlen = fromlen; dst->debug_level = MSG_INFO; dl_list_add(ctrl_dst, &dst->list); printf_encode(addr_txt, sizeof(addr_txt), (u8 *) from->sun_path, fromlen - offsetof(struct sockaddr_un, sun_path)); wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s", addr_txt); return 0; } static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_un *from, socklen_t fromlen) { struct wpa_ctrl_dst *dst; dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) { if (fromlen == dst->addrlen && os_memcmp(from->sun_path, dst->addr.sun_path, fromlen - offsetof(struct sockaddr_un, sun_path)) == 0) { char addr_txt[200]; printf_encode(addr_txt, sizeof(addr_txt), (u8 *) from->sun_path, fromlen - offsetof(struct sockaddr_un, sun_path)); wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s", addr_txt); dl_list_del(&dst->list); os_free(dst); return 0; } } return -1; } static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, struct sockaddr_un *from, socklen_t fromlen, char *level) { struct wpa_ctrl_dst *dst; wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) { if (fromlen == dst->addrlen && os_memcmp(from->sun_path, dst->addr.sun_path, fromlen - offsetof(struct sockaddr_un, sun_path)) == 0) { char addr_txt[200]; dst->debug_level = atoi(level); printf_encode(addr_txt, sizeof(addr_txt), (u8 *) from->sun_path, fromlen - offsetof(struct sockaddr_un, sun_path)); wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level to %d for %s", dst->debug_level, addr_txt); return 0; } } return -1; } static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, void *sock_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; struct ctrl_iface_priv *priv = sock_ctx; char buf[4096]; int res; struct sockaddr_un from; socklen_t fromlen = sizeof(from); char *reply = NULL, *reply_buf = NULL; size_t reply_len = 0; int new_attached = 0; res = recvfrom(sock, buf, sizeof(buf) - 1, 0, (struct sockaddr *) &from, &fromlen); if (res < 0) { wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", strerror(errno)); return; } buf[res] = '\0'; if (os_strcmp(buf, "ATTACH") == 0) { if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from, fromlen)) reply_len = 1; else { new_attached = 1; reply_len = 2; } } else if (os_strcmp(buf, "DETACH") == 0) { if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from, fromlen)) reply_len = 1; else reply_len = 2; } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, buf + 6)) reply_len = 1; else reply_len = 2; } else { reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf, &reply_len); reply = reply_buf; } if (!reply && reply_len == 1) { reply = "FAIL\n"; reply_len = 5; } else if (!reply && reply_len == 2) { reply = "OK\n"; reply_len = 3; } if (reply) { if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen) < 0) { int _errno = errno; wpa_dbg(wpa_s, MSG_DEBUG, "ctrl_iface sendto failed: %d - %s", _errno, strerror(_errno)); if (_errno == ENOBUFS || _errno == EAGAIN) { /* * The socket send buffer could be full. This * may happen if client programs are not * receiving their pending messages. Close and * reopen the socket as a workaround to avoid * getting stuck being unable to send any new * responses. */ sock = wpas_ctrl_iface_reinit(wpa_s, priv); if (sock < 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Failed to reinitialize ctrl_iface socket"); } } if (new_attached) { wpa_dbg(wpa_s, MSG_DEBUG, "Failed to send response to ATTACH - detaching"); new_attached = 0; wpa_supplicant_ctrl_iface_detach( &priv->ctrl_dst, &from, fromlen); } } } os_free(reply_buf); if (new_attached) eapol_sm_notify_ctrl_attached(wpa_s->eapol); } static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s) { char *buf; size_t len; char *pbuf, *dir = NULL; int res; if (wpa_s->conf->ctrl_interface == NULL) return NULL; pbuf = os_strdup(wpa_s->conf->ctrl_interface); if (pbuf == NULL) return NULL; if (os_strncmp(pbuf, "DIR=", 4) == 0) { char *gid_str; dir = pbuf + 4; gid_str = os_strstr(dir, " GROUP="); if (gid_str) *gid_str = '\0'; } else dir = pbuf; len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2; buf = os_malloc(len); if (buf == NULL) { os_free(pbuf); return NULL; } res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname); if (res < 0 || (size_t) res >= len) { os_free(pbuf); os_free(buf); return NULL; } #ifdef __CYGWIN__ { /* Windows/WinPcap uses interface names that are not suitable * as a file name - convert invalid chars to underscores */ char *pos = buf; while (*pos) { if (*pos == '\\') *pos = '_'; pos++; } } #endif /* __CYGWIN__ */ os_free(pbuf); return buf; } static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global, const char *txt, size_t len) { struct wpa_supplicant *wpa_s = ctx; if (wpa_s == NULL) return; if (global != 2 && wpa_s->global->ctrl_iface) { struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface; if (!dl_list_empty(&priv->ctrl_dst)) { wpa_supplicant_ctrl_iface_send(wpa_s, global ? NULL : wpa_s->ifname, priv->sock, &priv->ctrl_dst, level, txt, len, NULL, priv); } } if (wpa_s->ctrl_iface == NULL) return; wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock, &wpa_s->ctrl_iface->ctrl_dst, level, txt, len, wpa_s->ctrl_iface, NULL); } static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s, struct ctrl_iface_priv *priv) { struct sockaddr_un addr; char *fname = NULL; gid_t gid = 0; int gid_set = 0; char *buf, *dir = NULL, *gid_str = NULL; struct group *grp; char *endp; int flags; buf = os_strdup(wpa_s->conf->ctrl_interface); if (buf == NULL) goto fail; #ifdef ANDROID os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s", wpa_s->conf->ctrl_interface); priv->sock = android_get_control_socket(addr.sun_path); if (priv->sock >= 0) goto havesock; #endif /* ANDROID */ if (os_strncmp(buf, "DIR=", 4) == 0) { dir = buf + 4; gid_str = os_strstr(dir, " GROUP="); if (gid_str) { *gid_str = '\0'; gid_str += 7; } } else { dir = buf; gid_str = wpa_s->conf->ctrl_interface_group; } if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) { if (errno == EEXIST) { wpa_printf(MSG_DEBUG, "Using existing control " "interface directory."); } else { wpa_printf(MSG_ERROR, "mkdir[ctrl_interface=%s]: %s", dir, strerror(errno)); goto fail; } } #ifdef ANDROID /* * wpa_supplicant is started from /init.*.rc on Android and that seems * to be using umask 0077 which would leave the control interface * directory without group access. This breaks things since Wi-Fi * framework assumes that this directory can be accessed by other * applications in the wifi group. Fix this by adding group access even * if umask value would prevent this. */ if (chmod(dir, S_IRWXU | S_IRWXG) < 0) { wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s", strerror(errno)); /* Try to continue anyway */ } #endif /* ANDROID */ if (gid_str) { grp = getgrnam(gid_str); if (grp) { gid = grp->gr_gid; gid_set = 1; wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" " (from group name '%s')", (int) gid, gid_str); } else { /* Group name not found - try to parse this as gid */ gid = strtol(gid_str, &endp, 10); if (*gid_str == '\0' || *endp != '\0') { wpa_printf(MSG_ERROR, "CTRL: Invalid group " "'%s'", gid_str); goto fail; } gid_set = 1; wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", (int) gid); } } if (gid_set && chown(dir, -1, gid) < 0) { wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s", dir, (int) gid, strerror(errno)); goto fail; } /* Make sure the group can enter and read the directory */ if (gid_set && chmod(dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP) < 0) { wpa_printf(MSG_ERROR, "CTRL: chmod[ctrl_interface]: %s", strerror(errno)); goto fail; } if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >= sizeof(addr.sun_path)) { wpa_printf(MSG_ERROR, "ctrl_iface path limit exceeded"); goto fail; } priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); if (priv->sock < 0) { wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); goto fail; } os_memset(&addr, 0, sizeof(addr)); #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) addr.sun_len = sizeof(addr); #endif /* __FreeBSD__ */ addr.sun_family = AF_UNIX; fname = wpa_supplicant_ctrl_iface_path(wpa_s); if (fname == NULL) goto fail; os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", strerror(errno)); if (connect(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" " allow connections - assuming it was left" "over from forced program termination"); if (unlink(fname) < 0) { wpa_printf(MSG_ERROR, "Could not unlink existing ctrl_iface socket '%s': %s", fname, strerror(errno)); goto fail; } if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { wpa_printf(MSG_ERROR, "supp-ctrl-iface-init: bind(PF_UNIX): %s", strerror(errno)); goto fail; } wpa_printf(MSG_DEBUG, "Successfully replaced leftover " "ctrl_iface socket '%s'", fname); } else { wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " "be in use - cannot override it"); wpa_printf(MSG_INFO, "Delete '%s' manually if it is " "not used anymore", fname); os_free(fname); fname = NULL; goto fail; } } if (gid_set && chown(fname, -1, gid) < 0) { wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s", fname, (int) gid, strerror(errno)); goto fail; } if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { wpa_printf(MSG_ERROR, "chmod[ctrl_interface=%s]: %s", fname, strerror(errno)); goto fail; } os_free(fname); #ifdef ANDROID havesock: #endif /* ANDROID */ /* * Make socket non-blocking so that we don't hang forever if * target dies unexpectedly. */ flags = fcntl(priv->sock, F_GETFL); if (flags >= 0) { flags |= O_NONBLOCK; if (fcntl(priv->sock, F_SETFL, flags) < 0) { wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s", strerror(errno)); /* Not fatal, continue on.*/ } } eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, wpa_s, priv); wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); os_free(buf); return 0; fail: if (priv->sock >= 0) { close(priv->sock); priv->sock = -1; } if (fname) { unlink(fname); os_free(fname); } os_free(buf); return -1; } struct ctrl_iface_priv * wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) { struct ctrl_iface_priv *priv; priv = os_zalloc(sizeof(*priv)); if (priv == NULL) return NULL; dl_list_init(&priv->ctrl_dst); priv->wpa_s = wpa_s; priv->sock = -1; if (wpa_s->conf->ctrl_interface == NULL) return priv; if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0) { os_free(priv); return NULL; } return priv; } static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s, struct ctrl_iface_priv *priv) { int res; if (priv->sock <= 0) return -1; eloop_unregister_read_sock(priv->sock); close(priv->sock); priv->sock = -1; res = wpas_ctrl_iface_open_sock(wpa_s, priv); if (res < 0) return -1; return priv->sock; } void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) { struct wpa_ctrl_dst *dst, *prev; if (priv->sock > -1) { char *fname; char *buf, *dir = NULL; eloop_unregister_read_sock(priv->sock); if (!dl_list_empty(&priv->ctrl_dst)) { /* * Wait before closing the control socket if * there are any attached monitors in order to allow * them to receive any pending messages. */ wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached " "monitors to receive messages"); os_sleep(0, 100000); } close(priv->sock); priv->sock = -1; fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s); if (fname) { unlink(fname); os_free(fname); } if (priv->wpa_s->conf->ctrl_interface == NULL) goto free_dst; buf = os_strdup(priv->wpa_s->conf->ctrl_interface); if (buf == NULL) goto free_dst; if (os_strncmp(buf, "DIR=", 4) == 0) { char *gid_str; dir = buf + 4; gid_str = os_strstr(dir, " GROUP="); if (gid_str) *gid_str = '\0'; } else dir = buf; if (rmdir(dir) < 0) { if (errno == ENOTEMPTY) { wpa_printf(MSG_DEBUG, "Control interface " "directory not empty - leaving it " "behind"); } else { wpa_printf(MSG_ERROR, "rmdir[ctrl_interface=%s]: %s", dir, strerror(errno)); } } os_free(buf); } free_dst: dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst, list) os_free(dst); os_free(priv); } /** * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors * @ifname: Interface name for global control socket or %NULL * @sock: Local socket fd * @ctrl_dst: List of attached listeners * @level: Priority level of the message * @buf: Message data * @len: Message length * * Send a packet to all monitor programs attached to the control interface. */ static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, const char *ifname, int sock, struct dl_list *ctrl_dst, int level, const char *buf, size_t len, struct ctrl_iface_priv *priv, struct ctrl_iface_global_priv *gp) { struct wpa_ctrl_dst *dst, *next; char levelstr[10]; int idx, res; struct msghdr msg; struct iovec io[5]; if (sock < 0 || dl_list_empty(ctrl_dst)) return; res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); if (res < 0 || (size_t) res >= sizeof(levelstr)) return; idx = 0; if (ifname) { io[idx].iov_base = "IFNAME="; io[idx].iov_len = 7; idx++; io[idx].iov_base = (char *) ifname; io[idx].iov_len = os_strlen(ifname); idx++; io[idx].iov_base = " "; io[idx].iov_len = 1; idx++; } io[idx].iov_base = levelstr; io[idx].iov_len = os_strlen(levelstr); idx++; io[idx].iov_base = (char *) buf; io[idx].iov_len = len; idx++; os_memset(&msg, 0, sizeof(msg)); msg.msg_iov = io; msg.msg_iovlen = idx; dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) { int _errno; char addr_txt[200]; if (level < dst->debug_level) continue; printf_encode(addr_txt, sizeof(addr_txt), (u8 *) dst->addr.sun_path, dst->addrlen - offsetof(struct sockaddr_un, sun_path)); msg.msg_name = (void *) &dst->addr; msg.msg_namelen = dst->addrlen; if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor sent successfully to %s", addr_txt); dst->errors = 0; continue; } _errno = errno; wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s", addr_txt, errno, strerror(errno)); dst->errors++; if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) { wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor %s that cannot receive messages", addr_txt); wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr, dst->addrlen); } if (_errno == ENOBUFS || _errno == EAGAIN) { /* * The socket send buffer could be full. This may happen * if client programs are not receiving their pending * messages. Close and reopen the socket as a workaround * to avoid getting stuck being unable to send any new * responses. */ if (priv) sock = wpas_ctrl_iface_reinit(wpa_s, priv); else if (gp) sock = wpas_ctrl_iface_global_reinit( wpa_s->global, gp); else break; if (sock < 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Failed to reinitialize ctrl_iface socket"); break; } } } } void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) { char buf[256]; int res; struct sockaddr_un from; socklen_t fromlen = sizeof(from); for (;;) { wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to " "attach", priv->wpa_s->ifname); eloop_wait_for_read_sock(priv->sock); res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0, (struct sockaddr *) &from, &fromlen); if (res < 0) { wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", strerror(errno)); continue; } buf[res] = '\0'; if (os_strcmp(buf, "ATTACH") == 0) { /* handle ATTACH signal of first monitor interface */ if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from, fromlen)) { if (sendto(priv->sock, "OK\n", 3, 0, (struct sockaddr *) &from, fromlen) < 0) { wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s", strerror(errno)); } /* OK to continue */ return; } else { if (sendto(priv->sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, fromlen) < 0) { wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s", strerror(errno)); } } } else { /* return FAIL for all other signals */ if (sendto(priv->sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, fromlen) < 0) { wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s", strerror(errno)); } } } } /* Global ctrl_iface */ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, void *sock_ctx) { struct wpa_global *global = eloop_ctx; struct ctrl_iface_global_priv *priv = sock_ctx; char buf[4096]; int res; struct sockaddr_un from; socklen_t fromlen = sizeof(from); char *reply = NULL, *reply_buf = NULL; size_t reply_len; res = recvfrom(sock, buf, sizeof(buf) - 1, 0, (struct sockaddr *) &from, &fromlen); if (res < 0) { wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", strerror(errno)); return; } buf[res] = '\0'; if (os_strcmp(buf, "ATTACH") == 0) { if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from, fromlen)) reply_len = 1; else reply_len = 2; } else if (os_strcmp(buf, "DETACH") == 0) { if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from, fromlen)) reply_len = 1; else reply_len = 2; } else { reply_buf = wpa_supplicant_global_ctrl_iface_process( global, buf, &reply_len); reply = reply_buf; } if (!reply && reply_len == 1) { reply = "FAIL\n"; reply_len = 5; } else if (!reply && reply_len == 2) { reply = "OK\n"; reply_len = 3; } if (reply) { if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen) < 0) { wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s", strerror(errno)); } } os_free(reply_buf); } static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global, struct ctrl_iface_global_priv *priv) { struct sockaddr_un addr; const char *ctrl = global->params.ctrl_interface; int flags; wpa_printf(MSG_DEBUG, "Global control interface '%s'", ctrl); #ifdef ANDROID if (os_strncmp(ctrl, "@android:", 9) == 0) { priv->sock = android_get_control_socket(ctrl + 9); if (priv->sock < 0) { wpa_printf(MSG_ERROR, "Failed to open Android control " "socket '%s'", ctrl + 9); goto fail; } wpa_printf(MSG_DEBUG, "Using Android control socket '%s'", ctrl + 9); goto havesock; } if (os_strncmp(ctrl, "@abstract:", 10) != 0) { /* * Backwards compatibility - try to open an Android control * socket and if that fails, assume this was a UNIX domain * socket instead. */ priv->sock = android_get_control_socket(ctrl); if (priv->sock >= 0) { wpa_printf(MSG_DEBUG, "Using Android control socket '%s'", ctrl); goto havesock; } } #endif /* ANDROID */ priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); if (priv->sock < 0) { wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); goto fail; } os_memset(&addr, 0, sizeof(addr)); #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) addr.sun_len = sizeof(addr); #endif /* __FreeBSD__ */ addr.sun_family = AF_UNIX; if (os_strncmp(ctrl, "@abstract:", 10) == 0) { addr.sun_path[0] = '\0'; os_strlcpy(addr.sun_path + 1, ctrl + 10, sizeof(addr.sun_path) - 1); if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { wpa_printf(MSG_ERROR, "supp-global-ctrl-iface-init: " "bind(PF_UNIX;%s) failed: %s", ctrl, strerror(errno)); goto fail; } wpa_printf(MSG_DEBUG, "Using Abstract control socket '%s'", ctrl + 10); goto havesock; } os_strlcpy(addr.sun_path, ctrl, sizeof(addr.sun_path)); if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { wpa_printf(MSG_INFO, "supp-global-ctrl-iface-init(%s) (will try fixup): bind(PF_UNIX): %s", ctrl, strerror(errno)); if (connect(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" " allow connections - assuming it was left" "over from forced program termination"); if (unlink(ctrl) < 0) { wpa_printf(MSG_ERROR, "Could not unlink existing ctrl_iface socket '%s': %s", ctrl, strerror(errno)); goto fail; } if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { wpa_printf(MSG_ERROR, "supp-glb-iface-init: bind(PF_UNIX;%s): %s", ctrl, strerror(errno)); goto fail; } wpa_printf(MSG_DEBUG, "Successfully replaced leftover " "ctrl_iface socket '%s'", ctrl); } else { wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " "be in use - cannot override it"); wpa_printf(MSG_INFO, "Delete '%s' manually if it is " "not used anymore", ctrl); goto fail; } } wpa_printf(MSG_DEBUG, "Using UNIX control socket '%s'", ctrl); if (global->params.ctrl_interface_group) { char *gid_str = global->params.ctrl_interface_group; gid_t gid = 0; struct group *grp; char *endp; grp = getgrnam(gid_str); if (grp) { gid = grp->gr_gid; wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" " (from group name '%s')", (int) gid, gid_str); } else { /* Group name not found - try to parse this as gid */ gid = strtol(gid_str, &endp, 10); if (*gid_str == '\0' || *endp != '\0') { wpa_printf(MSG_ERROR, "CTRL: Invalid group " "'%s'", gid_str); goto fail; } wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", (int) gid); } if (chown(ctrl, -1, gid) < 0) { wpa_printf(MSG_ERROR, "chown[global_ctrl_interface=%s,gid=%d]: %s", ctrl, (int) gid, strerror(errno)); goto fail; } if (chmod(ctrl, S_IRWXU | S_IRWXG) < 0) { wpa_printf(MSG_ERROR, "chmod[global_ctrl_interface=%s]: %s", ctrl, strerror(errno)); goto fail; } } else { chmod(ctrl, S_IRWXU); } havesock: /* * Make socket non-blocking so that we don't hang forever if * target dies unexpectedly. */ flags = fcntl(priv->sock, F_GETFL); if (flags >= 0) { flags |= O_NONBLOCK; if (fcntl(priv->sock, F_SETFL, flags) < 0) { wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s", strerror(errno)); /* Not fatal, continue on.*/ } } eloop_register_read_sock(priv->sock, wpa_supplicant_global_ctrl_iface_receive, global, priv); return 0; fail: if (priv->sock >= 0) { close(priv->sock); priv->sock = -1; } return -1; } struct ctrl_iface_global_priv * wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) { struct ctrl_iface_global_priv *priv; priv = os_zalloc(sizeof(*priv)); if (priv == NULL) return NULL; dl_list_init(&priv->ctrl_dst); priv->global = global; priv->sock = -1; if (global->params.ctrl_interface == NULL) return priv; if (wpas_global_ctrl_iface_open_sock(global, priv) < 0) { os_free(priv); return NULL; } wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); return priv; } static int wpas_ctrl_iface_global_reinit(struct wpa_global *global, struct ctrl_iface_global_priv *priv) { int res; if (priv->sock <= 0) return -1; eloop_unregister_read_sock(priv->sock); close(priv->sock); priv->sock = -1; res = wpas_global_ctrl_iface_open_sock(global, priv); if (res < 0) return -1; return priv->sock; } void wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) { struct wpa_ctrl_dst *dst, *prev; if (priv->sock >= 0) { eloop_unregister_read_sock(priv->sock); close(priv->sock); } if (priv->global->params.ctrl_interface) unlink(priv->global->params.ctrl_interface); dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst, list) os_free(dst); os_free(priv); } wpa_supplicant-2.2/wpa_supplicant/hs20_supplicant.h0000664000175000017500000000320312343617166020435 0ustar jmjm/* * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef HS20_SUPPLICANT_H #define HS20_SUPPLICANT_H void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id); int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, const u8 *payload, size_t payload_len); struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, size_t payload_len); void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len, struct wpabuf *buf); void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *data, size_t slen); int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_bss *bss); int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void hs20_notify_parse_done(struct wpa_supplicant *wpa_s); void hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s, const char *url, u8 osu_method); void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url); void hs20_free_osu_prov(struct wpa_supplicant *wpa_s); void hs20_next_osu_icon(struct wpa_supplicant *wpa_s); void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s); int hs20_fetch_osu(struct wpa_supplicant *wpa_s); void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s); void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s); void hs20_start_osu_scan(struct wpa_supplicant *wpa_s); void hs20_deinit(struct wpa_supplicant *wpa_s); #endif /* HS20_SUPPLICANT_H */ wpa_supplicant-2.2/wpa_supplicant/main_winmain.c0000664000175000017500000000333112343617166020062 0ustar jmjm/* * WPA Supplicant / WinMain() function for Windows-based applications * Copyright (c) 2006, 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 "wpa_supplicant_i.h" #ifdef _WIN32_WCE #define CMDLINE LPWSTR #else /* _WIN32_WCE */ #define CMDLINE LPSTR #endif /* _WIN32_WCE */ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, CMDLINE lpCmdLine, int nShowCmd) { int i; struct wpa_interface *ifaces, *iface; int iface_count, exitcode = -1; struct wpa_params params; struct wpa_global *global; if (os_program_init()) return -1; os_memset(¶ms, 0, sizeof(params)); params.wpa_debug_level = MSG_MSGDUMP; params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt"; params.wpa_debug_show_keys = 1; iface = ifaces = os_zalloc(sizeof(struct wpa_interface)); if (ifaces == NULL) return -1; iface_count = 1; iface->confname = "default"; iface->driver = "ndis"; iface->ifname = ""; exitcode = 0; global = wpa_supplicant_init(¶ms); if (global == NULL) { printf("Failed to initialize wpa_supplicant\n"); exitcode = -1; } for (i = 0; exitcode == 0 && i < iface_count; i++) { if ((ifaces[i].confname == NULL && ifaces[i].ctrl_interface == NULL) || ifaces[i].ifname == NULL) { if (iface_count == 1 && (params.ctrl_interface || params.dbus_ctrl_interface)) break; exitcode = -1; break; } if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL) exitcode = -1; } if (exitcode == 0) exitcode = wpa_supplicant_run(global); wpa_supplicant_deinit(global); os_free(ifaces); os_program_deinit(); return exitcode; } wpa_supplicant-2.2/wpa_supplicant/ctrl_iface.c0000664000175000017500000052654212343617166017525 0ustar jmjm/* * WPA Supplicant / Control interface (shared code for all backends) * Copyright (c) 2004-2014, 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 "utils/uuid.h" #include "common/version.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" #include "eap_peer/eap.h" #include "eapol_supp/eapol_supp_sm.h" #include "rsn_supp/wpa.h" #include "rsn_supp/preauth.h" #include "rsn_supp/pmksa_cache.h" #include "l2_packet/l2_packet.h" #include "wps/wps.h" #include "config.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "wps_supplicant.h" #include "ibss_rsn.h" #include "ap.h" #include "p2p_supplicant.h" #include "p2p/p2p.h" #include "hs20_supplicant.h" #include "wifi_display.h" #include "notify.h" #include "bss.h" #include "scan.h" #include "ctrl_iface.h" #include "interworking.h" #include "blacklist.h" #include "autoscan.h" #include "wnm_sta.h" #include "offchannel.h" static int wpa_supplicant_global_iface_list(struct wpa_global *global, char *buf, int len); static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, char *buf, int len); static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val); static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val) { char *pos; u8 addr[ETH_ALEN], *filter = NULL, *n; size_t count = 0; pos = val; while (pos) { if (*pos == '\0') break; if (hwaddr_aton(pos, addr)) { os_free(filter); return -1; } n = os_realloc_array(filter, count + 1, ETH_ALEN); if (n == NULL) { os_free(filter); return -1; } filter = n; os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN); count++; pos = os_strchr(pos, ' '); if (pos) pos++; } wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN); os_free(wpa_s->bssid_filter); wpa_s->bssid_filter = filter; wpa_s->bssid_filter_count = count; return 0; } static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val) { char *pos; u8 addr[ETH_ALEN], *bssid = NULL, *n; struct wpa_ssid_value *ssid = NULL, *ns; size_t count = 0, ssid_count = 0; struct wpa_ssid *c; /* * disallow_list ::= | | | "" * SSID_SPEC ::= ssid * BSSID_SPEC ::= bssid */ pos = val; while (pos) { if (*pos == '\0') break; if (os_strncmp(pos, "bssid ", 6) == 0) { int res; pos += 6; res = hwaddr_aton2(pos, addr); if (res < 0) { os_free(ssid); os_free(bssid); wpa_printf(MSG_DEBUG, "Invalid disallow_aps " "BSSID value '%s'", pos); return -1; } pos += res; n = os_realloc_array(bssid, count + 1, ETH_ALEN); if (n == NULL) { os_free(ssid); os_free(bssid); return -1; } bssid = n; os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN); count++; } else if (os_strncmp(pos, "ssid ", 5) == 0) { char *end; pos += 5; end = pos; while (*end) { if (*end == '\0' || *end == ' ') break; end++; } ns = os_realloc_array(ssid, ssid_count + 1, sizeof(struct wpa_ssid_value)); if (ns == NULL) { os_free(ssid); os_free(bssid); return -1; } ssid = ns; if ((end - pos) & 0x01 || end - pos > 2 * 32 || hexstr2bin(pos, ssid[ssid_count].ssid, (end - pos) / 2) < 0) { os_free(ssid); os_free(bssid); wpa_printf(MSG_DEBUG, "Invalid disallow_aps " "SSID value '%s'", pos); return -1; } ssid[ssid_count].ssid_len = (end - pos) / 2; wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID", ssid[ssid_count].ssid, ssid[ssid_count].ssid_len); ssid_count++; pos = end; } else { wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value " "'%s'", pos); os_free(ssid); os_free(bssid); return -1; } pos = os_strchr(pos, ' '); if (pos) pos++; } wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN); os_free(wpa_s->disallow_aps_bssid); wpa_s->disallow_aps_bssid = bssid; wpa_s->disallow_aps_bssid_count = count; wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count); os_free(wpa_s->disallow_aps_ssid); wpa_s->disallow_aps_ssid = ssid; wpa_s->disallow_aps_ssid_count = ssid_count; if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING) return 0; c = wpa_s->current_ssid; if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS) return 0; if (!disallowed_bssid(wpa_s, wpa_s->bssid) && !disallowed_ssid(wpa_s, c->ssid, c->ssid_len)) return 0; wpa_printf(MSG_DEBUG, "Disconnect and try to find another network " "because current AP was marked disallowed"); #ifdef CONFIG_SME wpa_s->sme.prev_bssid_set = 0; #endif /* CONFIG_SME */ wpa_s->reassociate = 1; wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); wpa_supplicant_req_scan(wpa_s, 0, 0); return 0; } #ifndef CONFIG_NO_CONFIG_BLOBS static int wpas_ctrl_set_blob(struct wpa_supplicant *wpa_s, char *pos) { char *name = pos; struct wpa_config_blob *blob; size_t len; pos = os_strchr(pos, ' '); if (pos == NULL) return -1; *pos++ = '\0'; len = os_strlen(pos); if (len & 1) return -1; wpa_printf(MSG_DEBUG, "CTRL: Set blob '%s'", name); blob = os_zalloc(sizeof(*blob)); if (blob == NULL) return -1; blob->name = os_strdup(name); blob->data = os_malloc(len / 2); if (blob->name == NULL || blob->data == NULL) { wpa_config_free_blob(blob); return -1; } if (hexstr2bin(pos, blob->data, len / 2) < 0) { wpa_printf(MSG_DEBUG, "CTRL: Invalid blob hex data"); wpa_config_free_blob(blob); return -1; } blob->len = len / 2; wpa_config_set_blob(wpa_s->conf, blob); return 0; } #endif /* CONFIG_NO_CONFIG_BLOBS */ static int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd) { char *params; char *pos; int *freqs = NULL; int ret; if (atoi(cmd)) { params = os_strchr(cmd, ' '); os_free(wpa_s->manual_sched_scan_freqs); if (params) { params++; pos = os_strstr(params, "freq="); if (pos) freqs = freq_range_to_channel_list(wpa_s, pos + 5); } wpa_s->manual_sched_scan_freqs = freqs; ret = wpas_start_pno(wpa_s); } else { ret = wpas_stop_pno(wpa_s); } return ret; } static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, char *cmd) { char *value; int ret = 0; value = os_strchr(cmd, ' '); if (value == NULL) return -1; *value++ = '\0'; wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value); if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) { eapol_sm_configure(wpa_s->eapol, atoi(value), -1, -1, -1); } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) { eapol_sm_configure(wpa_s->eapol, -1, atoi(value), -1, -1); } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) { eapol_sm_configure(wpa_s->eapol, -1, -1, atoi(value), -1); } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) { eapol_sm_configure(wpa_s->eapol, -1, -1, -1, atoi(value)); } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) { if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, atoi(value))) ret = -1; } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") == 0) { if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, atoi(value))) ret = -1; } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) { if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value))) ret = -1; } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) { wpa_s->wps_fragment_size = atoi(value); #ifdef CONFIG_WPS_TESTING } else if (os_strcasecmp(cmd, "wps_version_number") == 0) { long int val; val = strtol(value, NULL, 0); if (val < 0 || val > 0xff) { ret = -1; wpa_printf(MSG_DEBUG, "WPS: Invalid " "wps_version_number %ld", val); } else { wps_version_number = val; wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS " "version %u.%u", (wps_version_number & 0xf0) >> 4, wps_version_number & 0x0f); } } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) { wps_testing_dummy_cred = atoi(value); wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d", wps_testing_dummy_cred); } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) { wps_corrupt_pkhash = atoi(value); wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d", wps_corrupt_pkhash); #endif /* CONFIG_WPS_TESTING */ } else if (os_strcasecmp(cmd, "ampdu") == 0) { if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0) ret = -1; #ifdef CONFIG_TDLS #ifdef CONFIG_TDLS_TESTING } else if (os_strcasecmp(cmd, "tdls_testing") == 0) { extern unsigned int tdls_testing; tdls_testing = strtol(value, NULL, 0); wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing); #endif /* CONFIG_TDLS_TESTING */ } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) { int disabled = atoi(value); wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled); if (disabled) { if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0) ret = -1; } else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0) ret = -1; wpa_tdls_enable(wpa_s->wpa, !disabled); #endif /* CONFIG_TDLS */ } else if (os_strcasecmp(cmd, "pno") == 0) { ret = wpas_ctrl_pno(wpa_s, value); } else if (os_strcasecmp(cmd, "radio_disabled") == 0) { int disabled = atoi(value); if (wpa_drv_radio_disable(wpa_s, disabled) < 0) ret = -1; else if (disabled) wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); } else if (os_strcasecmp(cmd, "uapsd") == 0) { if (os_strcmp(value, "disable") == 0) wpa_s->set_sta_uapsd = 0; else { int be, bk, vi, vo; char *pos; /* format: BE,BK,VI,VO;max SP Length */ be = atoi(value); pos = os_strchr(value, ','); if (pos == NULL) return -1; pos++; bk = atoi(pos); pos = os_strchr(pos, ','); if (pos == NULL) return -1; pos++; vi = atoi(pos); pos = os_strchr(pos, ','); if (pos == NULL) return -1; pos++; vo = atoi(pos); /* ignore max SP Length for now */ wpa_s->set_sta_uapsd = 1; wpa_s->sta_uapsd = 0; if (be) wpa_s->sta_uapsd |= BIT(0); if (bk) wpa_s->sta_uapsd |= BIT(1); if (vi) wpa_s->sta_uapsd |= BIT(2); if (vo) wpa_s->sta_uapsd |= BIT(3); } } else if (os_strcasecmp(cmd, "ps") == 0) { ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1); #ifdef CONFIG_WIFI_DISPLAY } else if (os_strcasecmp(cmd, "wifi_display") == 0) { int enabled = !!atoi(value); if (enabled && !wpa_s->global->p2p) ret = -1; else wifi_display_enable(wpa_s->global, enabled); #endif /* CONFIG_WIFI_DISPLAY */ } else if (os_strcasecmp(cmd, "bssid_filter") == 0) { ret = set_bssid_filter(wpa_s, value); } else if (os_strcasecmp(cmd, "disallow_aps") == 0) { ret = set_disallow_aps(wpa_s, value); } else if (os_strcasecmp(cmd, "no_keep_alive") == 0) { wpa_s->no_keep_alive = !!atoi(value); #ifdef CONFIG_TESTING_OPTIONS } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) { wpa_s->ext_mgmt_frame_handling = !!atoi(value); #endif /* CONFIG_TESTING_OPTIONS */ #ifndef CONFIG_NO_CONFIG_BLOBS } else if (os_strcmp(cmd, "blob") == 0) { ret = wpas_ctrl_set_blob(wpa_s, value); #endif /* CONFIG_NO_CONFIG_BLOBS */ } else { value[-1] = '='; ret = wpa_config_process_global(wpa_s->conf, cmd, -1); if (ret == 0) wpa_supplicant_update_config(wpa_s); } return ret; } static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { int res = -1; wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd); if (os_strcmp(cmd, "version") == 0) { res = os_snprintf(buf, buflen, "%s", VERSION_STR); } else if (os_strcasecmp(cmd, "country") == 0) { if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) res = os_snprintf(buf, buflen, "%c%c", wpa_s->conf->country[0], wpa_s->conf->country[1]); #ifdef CONFIG_WIFI_DISPLAY } else if (os_strcasecmp(cmd, "wifi_display") == 0) { int enabled; if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) enabled = 0; else enabled = wpa_s->global->wifi_display; res = os_snprintf(buf, buflen, "%d", enabled); if (res < 0 || (unsigned int) res >= buflen) return -1; return res; #endif /* CONFIG_WIFI_DISPLAY */ #ifdef CONFIG_TESTING_GET_GTK } else if (os_strcmp(cmd, "gtk") == 0) { if (wpa_s->last_gtk_len == 0) return -1; res = wpa_snprintf_hex(buf, buflen, wpa_s->last_gtk, wpa_s->last_gtk_len); return res; #endif /* CONFIG_TESTING_GET_GTK */ } if (res < 0 || (unsigned int) res >= buflen) return -1; return res; } #ifdef IEEE8021X_EAPOL static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s, char *addr) { u8 bssid[ETH_ALEN]; struct wpa_ssid *ssid = wpa_s->current_ssid; if (hwaddr_aton(addr, bssid)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address " "'%s'", addr); return -1; } wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid)); rsn_preauth_deinit(wpa_s->wpa); if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL)) return -1; return 0; } #endif /* IEEE8021X_EAPOL */ #ifdef CONFIG_PEERKEY /* MLME-STKSTART.request(peer) */ static int wpa_supplicant_ctrl_iface_stkstart( struct wpa_supplicant *wpa_s, char *addr) { u8 peer[ETH_ALEN]; if (hwaddr_aton(addr, peer)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid " "address '%s'", addr); return -1; } wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR, MAC2STR(peer)); return wpa_sm_stkstart(wpa_s->wpa, peer); } #endif /* CONFIG_PEERKEY */ #ifdef CONFIG_TDLS static int wpa_supplicant_ctrl_iface_tdls_discover( struct wpa_supplicant *wpa_s, char *addr) { u8 peer[ETH_ALEN]; int ret; if (hwaddr_aton(addr, peer)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid " "address '%s'", addr); return -1; } wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR, MAC2STR(peer)); if (wpa_tdls_is_external_setup(wpa_s->wpa)) ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer); else ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer); return ret; } static int wpa_supplicant_ctrl_iface_tdls_setup( struct wpa_supplicant *wpa_s, char *addr) { u8 peer[ETH_ALEN]; int ret; if (hwaddr_aton(addr, peer)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid " "address '%s'", addr); return -1; } wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR, MAC2STR(peer)); if ((wpa_s->conf->tdls_external_control) && wpa_tdls_is_external_setup(wpa_s->wpa)) return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer); wpa_tdls_remove(wpa_s->wpa, peer); if (wpa_tdls_is_external_setup(wpa_s->wpa)) ret = wpa_tdls_start(wpa_s->wpa, peer); else ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer); return ret; } static int wpa_supplicant_ctrl_iface_tdls_teardown( struct wpa_supplicant *wpa_s, char *addr) { u8 peer[ETH_ALEN]; int ret; if (hwaddr_aton(addr, peer)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid " "address '%s'", addr); return -1; } wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR, MAC2STR(peer)); if ((wpa_s->conf->tdls_external_control) && wpa_tdls_is_external_setup(wpa_s->wpa)) return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer); if (wpa_tdls_is_external_setup(wpa_s->wpa)) ret = wpa_tdls_teardown_link( wpa_s->wpa, peer, WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); else ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer); return ret; } static int ctrl_iface_get_capability_tdls( struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { int ret; ret = os_snprintf(buf, buflen, "%s\n", wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT ? (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP ? "EXTERNAL" : "INTERNAL") : "UNSUPPORTED"); if (ret < 0 || (size_t) ret > buflen) return -1; return ret; } #endif /* CONFIG_TDLS */ #ifdef CONFIG_IEEE80211R static int wpa_supplicant_ctrl_iface_ft_ds( struct wpa_supplicant *wpa_s, char *addr) { u8 target_ap[ETH_ALEN]; struct wpa_bss *bss; const u8 *mdie; if (hwaddr_aton(addr, target_ap)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid " "address '%s'", addr); return -1; } wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap)); bss = wpa_bss_get_bssid(wpa_s, target_ap); if (bss) mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); else mdie = NULL; return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie); } #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_WPS static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s, char *cmd) { u8 bssid[ETH_ALEN], *_bssid = bssid; #ifdef CONFIG_P2P u8 p2p_dev_addr[ETH_ALEN]; #endif /* CONFIG_P2P */ #ifdef CONFIG_AP u8 *_p2p_dev_addr = NULL; #endif /* CONFIG_AP */ if (cmd == NULL || os_strcmp(cmd, "any") == 0) { _bssid = NULL; #ifdef CONFIG_P2P } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) { if (hwaddr_aton(cmd + 13, p2p_dev_addr)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid " "P2P Device Address '%s'", cmd + 13); return -1; } _p2p_dev_addr = p2p_dev_addr; #endif /* CONFIG_P2P */ } else if (hwaddr_aton(cmd, bssid)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'", cmd); return -1; } #ifdef CONFIG_AP if (wpa_s->ap_iface) return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr); #endif /* CONFIG_AP */ return wpas_wps_start_pbc(wpa_s, _bssid, 0); } static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { u8 bssid[ETH_ALEN], *_bssid = bssid; char *pin; int ret; pin = os_strchr(cmd, ' '); if (pin) *pin++ = '\0'; if (os_strcmp(cmd, "any") == 0) _bssid = NULL; else if (os_strcmp(cmd, "get") == 0) { ret = wps_generate_pin(); goto done; } else if (hwaddr_aton(cmd, bssid)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'", cmd); return -1; } #ifdef CONFIG_AP if (wpa_s->ap_iface) { int timeout = 0; char *pos; if (pin) { pos = os_strchr(pin, ' '); if (pos) { *pos++ = '\0'; timeout = atoi(pos); } } return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin, buf, buflen, timeout); } #endif /* CONFIG_AP */ if (pin) { ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0, DEV_PW_DEFAULT); if (ret < 0) return -1; ret = os_snprintf(buf, buflen, "%s", pin); if (ret < 0 || (size_t) ret >= buflen) return -1; return ret; } ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT); if (ret < 0) return -1; done: /* Return the generated PIN */ ret = os_snprintf(buf, buflen, "%08d", ret); if (ret < 0 || (size_t) ret >= buflen) return -1; return ret; } static int wpa_supplicant_ctrl_iface_wps_check_pin( struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { char pin[9]; size_t len; char *pos; int ret; wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN", (u8 *) cmd, os_strlen(cmd)); for (pos = cmd, len = 0; *pos != '\0'; pos++) { if (*pos < '0' || *pos > '9') continue; pin[len++] = *pos; if (len == 9) { wpa_printf(MSG_DEBUG, "WPS: Too long PIN"); return -1; } } if (len != 4 && len != 8) { wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len); return -1; } pin[len] = '\0'; if (len == 8) { unsigned int pin_val; pin_val = atoi(pin); if (!wps_pin_valid(pin_val)) { wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit"); ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n"); if (ret < 0 || (size_t) ret >= buflen) return -1; return ret; } } ret = os_snprintf(buf, buflen, "%s", pin); if (ret < 0 || (size_t) ret >= buflen) return -1; return ret; } #ifdef CONFIG_WPS_NFC static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s, char *cmd) { u8 bssid[ETH_ALEN], *_bssid = bssid; if (cmd == NULL || cmd[0] == '\0') _bssid = NULL; else if (hwaddr_aton(cmd, bssid)) return -1; return wpas_wps_start_nfc(wpa_s, NULL, _bssid, NULL, 0, 0, NULL, NULL, 0, 0); } static int wpa_supplicant_ctrl_iface_wps_nfc_config_token( struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) { int ndef; struct wpabuf *buf; int res; char *pos; pos = os_strchr(cmd, ' '); if (pos) *pos++ = '\0'; if (os_strcmp(cmd, "WPS") == 0) ndef = 0; else if (os_strcmp(cmd, "NDEF") == 0) ndef = 1; else return -1; buf = wpas_wps_nfc_config_token(wpa_s, ndef, pos); if (buf == NULL) return -1; res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), wpabuf_len(buf)); reply[res++] = '\n'; reply[res] = '\0'; wpabuf_free(buf); return res; } static int wpa_supplicant_ctrl_iface_wps_nfc_token( struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) { int ndef; struct wpabuf *buf; int res; if (os_strcmp(cmd, "WPS") == 0) ndef = 0; else if (os_strcmp(cmd, "NDEF") == 0) ndef = 1; else return -1; buf = wpas_wps_nfc_token(wpa_s, ndef); if (buf == NULL) return -1; res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), wpabuf_len(buf)); reply[res++] = '\n'; reply[res] = '\0'; wpabuf_free(buf); return res; } static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read( struct wpa_supplicant *wpa_s, char *pos) { size_t len; struct wpabuf *buf; int ret; char *freq; int forced_freq = 0; freq = strstr(pos, " freq="); if (freq) { *freq = '\0'; freq += 6; forced_freq = atoi(freq); } len = os_strlen(pos); if (len & 0x01) return -1; len /= 2; buf = wpabuf_alloc(len); if (buf == NULL) return -1; if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) { wpabuf_free(buf); return -1; } ret = wpas_wps_nfc_tag_read(wpa_s, buf, forced_freq); wpabuf_free(buf); return ret; } static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s, char *reply, size_t max_len, int ndef) { struct wpabuf *buf; int res; buf = wpas_wps_nfc_handover_req(wpa_s, ndef); if (buf == NULL) return -1; res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), wpabuf_len(buf)); reply[res++] = '\n'; reply[res] = '\0'; wpabuf_free(buf); return res; } #ifdef CONFIG_P2P static int wpas_ctrl_nfc_get_handover_req_p2p(struct wpa_supplicant *wpa_s, char *reply, size_t max_len, int ndef) { struct wpabuf *buf; int res; buf = wpas_p2p_nfc_handover_req(wpa_s, ndef); if (buf == NULL) { wpa_printf(MSG_DEBUG, "P2P: Could not generate NFC handover request"); return -1; } res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), wpabuf_len(buf)); reply[res++] = '\n'; reply[res] = '\0'; wpabuf_free(buf); return res; } #endif /* CONFIG_P2P */ static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) { char *pos; int ndef; pos = os_strchr(cmd, ' '); if (pos == NULL) return -1; *pos++ = '\0'; if (os_strcmp(cmd, "WPS") == 0) ndef = 0; else if (os_strcmp(cmd, "NDEF") == 0) ndef = 1; else return -1; if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) { if (!ndef) return -1; return wpas_ctrl_nfc_get_handover_req_wps( wpa_s, reply, max_len, ndef); } #ifdef CONFIG_P2P if (os_strcmp(pos, "P2P-CR") == 0) { return wpas_ctrl_nfc_get_handover_req_p2p( wpa_s, reply, max_len, ndef); } #endif /* CONFIG_P2P */ return -1; } static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s, char *reply, size_t max_len, int ndef, int cr, char *uuid) { struct wpabuf *buf; int res; buf = wpas_wps_nfc_handover_sel(wpa_s, ndef, cr, uuid); if (buf == NULL) return -1; res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), wpabuf_len(buf)); reply[res++] = '\n'; reply[res] = '\0'; wpabuf_free(buf); return res; } #ifdef CONFIG_P2P static int wpas_ctrl_nfc_get_handover_sel_p2p(struct wpa_supplicant *wpa_s, char *reply, size_t max_len, int ndef, int tag) { struct wpabuf *buf; int res; buf = wpas_p2p_nfc_handover_sel(wpa_s, ndef, tag); if (buf == NULL) return -1; res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), wpabuf_len(buf)); reply[res++] = '\n'; reply[res] = '\0'; wpabuf_free(buf); return res; } #endif /* CONFIG_P2P */ static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) { char *pos, *pos2; int ndef; pos = os_strchr(cmd, ' '); if (pos == NULL) return -1; *pos++ = '\0'; if (os_strcmp(cmd, "WPS") == 0) ndef = 0; else if (os_strcmp(cmd, "NDEF") == 0) ndef = 1; else return -1; pos2 = os_strchr(pos, ' '); if (pos2) *pos2++ = '\0'; if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) { if (!ndef) return -1; return wpas_ctrl_nfc_get_handover_sel_wps( wpa_s, reply, max_len, ndef, os_strcmp(pos, "WPS-CR") == 0, pos2); } #ifdef CONFIG_P2P if (os_strcmp(pos, "P2P-CR") == 0) { return wpas_ctrl_nfc_get_handover_sel_p2p( wpa_s, reply, max_len, ndef, 0); } if (os_strcmp(pos, "P2P-CR-TAG") == 0) { return wpas_ctrl_nfc_get_handover_sel_p2p( wpa_s, reply, max_len, ndef, 1); } #endif /* CONFIG_P2P */ return -1; } static int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s, char *cmd) { size_t len; struct wpabuf *req, *sel; int ret; char *pos, *role, *type, *pos2; #ifdef CONFIG_P2P char *freq; int forced_freq = 0; freq = strstr(cmd, " freq="); if (freq) { *freq = '\0'; freq += 6; forced_freq = atoi(freq); } #endif /* CONFIG_P2P */ role = cmd; pos = os_strchr(role, ' '); if (pos == NULL) { wpa_printf(MSG_DEBUG, "NFC: Missing type in handover report"); return -1; } *pos++ = '\0'; type = pos; pos = os_strchr(type, ' '); if (pos == NULL) { wpa_printf(MSG_DEBUG, "NFC: Missing request message in handover report"); return -1; } *pos++ = '\0'; pos2 = os_strchr(pos, ' '); if (pos2 == NULL) { wpa_printf(MSG_DEBUG, "NFC: Missing select message in handover report"); return -1; } *pos2++ = '\0'; len = os_strlen(pos); if (len & 0x01) { wpa_printf(MSG_DEBUG, "NFC: Invalid request message length in handover report"); return -1; } len /= 2; req = wpabuf_alloc(len); if (req == NULL) { wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for request message"); return -1; } if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) { wpa_printf(MSG_DEBUG, "NFC: Invalid request message hexdump in handover report"); wpabuf_free(req); return -1; } len = os_strlen(pos2); if (len & 0x01) { wpa_printf(MSG_DEBUG, "NFC: Invalid select message length in handover report"); wpabuf_free(req); return -1; } len /= 2; sel = wpabuf_alloc(len); if (sel == NULL) { wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for select message"); wpabuf_free(req); return -1; } if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) { wpa_printf(MSG_DEBUG, "NFC: Invalid select message hexdump in handover report"); wpabuf_free(req); wpabuf_free(sel); return -1; } wpa_printf(MSG_DEBUG, "NFC: Connection handover reported - role=%s type=%s req_len=%d sel_len=%d", role, type, (int) wpabuf_len(req), (int) wpabuf_len(sel)); if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) { ret = wpas_wps_nfc_report_handover(wpa_s, req, sel); #ifdef CONFIG_AP } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) { ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel); if (ret < 0) ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel); #endif /* CONFIG_AP */ #ifdef CONFIG_P2P } else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0) { ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel, 0); } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0) { ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel, forced_freq); #endif /* CONFIG_P2P */ } else { wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover " "reported: role=%s type=%s", role, type); ret = -1; } wpabuf_free(req); wpabuf_free(sel); if (ret) wpa_printf(MSG_DEBUG, "NFC: Failed to process reported handover messages"); return ret; } #endif /* CONFIG_WPS_NFC */ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s, char *cmd) { u8 bssid[ETH_ALEN]; char *pin; char *new_ssid; char *new_auth; char *new_encr; char *new_key; struct wps_new_ap_settings ap; pin = os_strchr(cmd, ' '); if (pin == NULL) return -1; *pin++ = '\0'; if (hwaddr_aton(cmd, bssid)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'", cmd); return -1; } new_ssid = os_strchr(pin, ' '); if (new_ssid == NULL) return wpas_wps_start_reg(wpa_s, bssid, pin, NULL); *new_ssid++ = '\0'; new_auth = os_strchr(new_ssid, ' '); if (new_auth == NULL) return -1; *new_auth++ = '\0'; new_encr = os_strchr(new_auth, ' '); if (new_encr == NULL) return -1; *new_encr++ = '\0'; new_key = os_strchr(new_encr, ' '); if (new_key == NULL) return -1; *new_key++ = '\0'; os_memset(&ap, 0, sizeof(ap)); ap.ssid_hex = new_ssid; ap.auth = new_auth; ap.encr = new_encr; ap.key_hex = new_key; return wpas_wps_start_reg(wpa_s, bssid, pin, &ap); } #ifdef CONFIG_AP static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { int timeout = 300; char *pos; const char *pin_txt; if (!wpa_s->ap_iface) return -1; pos = os_strchr(cmd, ' '); if (pos) *pos++ = '\0'; if (os_strcmp(cmd, "disable") == 0) { wpas_wps_ap_pin_disable(wpa_s); return os_snprintf(buf, buflen, "OK\n"); } if (os_strcmp(cmd, "random") == 0) { if (pos) timeout = atoi(pos); pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout); if (pin_txt == NULL) return -1; return os_snprintf(buf, buflen, "%s", pin_txt); } if (os_strcmp(cmd, "get") == 0) { pin_txt = wpas_wps_ap_pin_get(wpa_s); if (pin_txt == NULL) return -1; return os_snprintf(buf, buflen, "%s", pin_txt); } if (os_strcmp(cmd, "set") == 0) { char *pin; if (pos == NULL) return -1; pin = pos; pos = os_strchr(pos, ' '); if (pos) { *pos++ = '\0'; timeout = atoi(pos); } if (os_strlen(pin) > buflen) return -1; if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0) return -1; return os_snprintf(buf, buflen, "%s", pin); } return -1; } #endif /* CONFIG_AP */ #ifdef CONFIG_WPS_ER static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s, char *cmd) { char *uuid = cmd, *pin, *pos; u8 addr_buf[ETH_ALEN], *addr = NULL; pin = os_strchr(uuid, ' '); if (pin == NULL) return -1; *pin++ = '\0'; pos = os_strchr(pin, ' '); if (pos) { *pos++ = '\0'; if (hwaddr_aton(pos, addr_buf) == 0) addr = addr_buf; } return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin); } static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s, char *cmd) { char *uuid = cmd, *pin; pin = os_strchr(uuid, ' '); if (pin == NULL) return -1; *pin++ = '\0'; return wpas_wps_er_learn(wpa_s, uuid, pin); } static int wpa_supplicant_ctrl_iface_wps_er_set_config( struct wpa_supplicant *wpa_s, char *cmd) { char *uuid = cmd, *id; id = os_strchr(uuid, ' '); if (id == NULL) return -1; *id++ = '\0'; return wpas_wps_er_set_config(wpa_s, uuid, atoi(id)); } static int wpa_supplicant_ctrl_iface_wps_er_config( struct wpa_supplicant *wpa_s, char *cmd) { char *pin; char *new_ssid; char *new_auth; char *new_encr; char *new_key; struct wps_new_ap_settings ap; pin = os_strchr(cmd, ' '); if (pin == NULL) return -1; *pin++ = '\0'; new_ssid = os_strchr(pin, ' '); if (new_ssid == NULL) return -1; *new_ssid++ = '\0'; new_auth = os_strchr(new_ssid, ' '); if (new_auth == NULL) return -1; *new_auth++ = '\0'; new_encr = os_strchr(new_auth, ' '); if (new_encr == NULL) return -1; *new_encr++ = '\0'; new_key = os_strchr(new_encr, ' '); if (new_key == NULL) return -1; *new_key++ = '\0'; os_memset(&ap, 0, sizeof(ap)); ap.ssid_hex = new_ssid; ap.auth = new_auth; ap.encr = new_encr; ap.key_hex = new_key; return wpas_wps_er_config(wpa_s, cmd, pin, &ap); } #ifdef CONFIG_WPS_NFC static int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token( struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) { int ndef; struct wpabuf *buf; int res; char *uuid; uuid = os_strchr(cmd, ' '); if (uuid == NULL) return -1; *uuid++ = '\0'; if (os_strcmp(cmd, "WPS") == 0) ndef = 0; else if (os_strcmp(cmd, "NDEF") == 0) ndef = 1; else return -1; buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid); if (buf == NULL) return -1; res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), wpabuf_len(buf)); reply[res++] = '\n'; reply[res] = '\0'; wpabuf_free(buf); return res; } #endif /* CONFIG_WPS_NFC */ #endif /* CONFIG_WPS_ER */ #endif /* CONFIG_WPS */ #ifdef CONFIG_IBSS_RSN static int wpa_supplicant_ctrl_iface_ibss_rsn( struct wpa_supplicant *wpa_s, char *addr) { u8 peer[ETH_ALEN]; if (hwaddr_aton(addr, peer)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid " "address '%s'", addr); return -1; } wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR, MAC2STR(peer)); return ibss_rsn_start(wpa_s->ibss_rsn, peer); } #endif /* CONFIG_IBSS_RSN */ static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s, char *rsp) { #ifdef IEEE8021X_EAPOL char *pos, *id_pos; int id; struct wpa_ssid *ssid; pos = os_strchr(rsp, '-'); if (pos == NULL) return -1; *pos++ = '\0'; id_pos = pos; pos = os_strchr(pos, ':'); if (pos == NULL) return -1; *pos++ = '\0'; id = atoi(id_pos); wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id); wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value", (u8 *) pos, os_strlen(pos)); ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " "to update", id); return -1; } return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp, pos); #else /* IEEE8021X_EAPOL */ wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included"); return -1; #endif /* IEEE8021X_EAPOL */ } static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, const char *params, char *buf, size_t buflen) { char *pos, *end, tmp[30]; int res, verbose, wps, ret; #ifdef CONFIG_HS20 const u8 *hs20; #endif /* CONFIG_HS20 */ if (os_strcmp(params, "-DRIVER") == 0) return wpa_drv_status(wpa_s, buf, buflen); verbose = os_strcmp(params, "-VERBOSE") == 0; wps = os_strcmp(params, "-WPS") == 0; pos = buf; end = buf + buflen; if (wpa_s->wpa_state >= WPA_ASSOCIATED) { struct wpa_ssid *ssid = wpa_s->current_ssid; ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n", MAC2STR(wpa_s->bssid)); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; if (ssid) { u8 *_ssid = ssid->ssid; size_t ssid_len = ssid->ssid_len; u8 ssid_buf[MAX_SSID_LEN]; if (ssid_len == 0) { int _res = wpa_drv_get_ssid(wpa_s, ssid_buf); if (_res < 0) ssid_len = 0; else ssid_len = _res; _ssid = ssid_buf; } ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n", wpa_ssid_txt(_ssid, ssid_len), ssid->id); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; if (wps && ssid->passphrase && wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO)) { ret = os_snprintf(pos, end - pos, "passphrase=%s\n", ssid->passphrase); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } if (ssid->id_str) { ret = os_snprintf(pos, end - pos, "id_str=%s\n", ssid->id_str); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } switch (ssid->mode) { case WPAS_MODE_INFRA: ret = os_snprintf(pos, end - pos, "mode=station\n"); break; case WPAS_MODE_IBSS: ret = os_snprintf(pos, end - pos, "mode=IBSS\n"); break; case WPAS_MODE_AP: ret = os_snprintf(pos, end - pos, "mode=AP\n"); break; case WPAS_MODE_P2P_GO: ret = os_snprintf(pos, end - pos, "mode=P2P GO\n"); break; case WPAS_MODE_P2P_GROUP_FORMATION: ret = os_snprintf(pos, end - pos, "mode=P2P GO - group " "formation\n"); break; default: ret = 0; break; } if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } #ifdef CONFIG_AP if (wpa_s->ap_iface) { pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos, end - pos, verbose); } else #endif /* CONFIG_AP */ pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose); } #ifdef CONFIG_SAE if (wpa_s->wpa_state >= WPA_ASSOCIATED && #ifdef CONFIG_AP !wpa_s->ap_iface && #endif /* CONFIG_AP */ wpa_s->sme.sae.state == SAE_ACCEPTED) { ret = os_snprintf(pos, end - pos, "sae_group=%d\n", wpa_s->sme.sae.group); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } #endif /* CONFIG_SAE */ ret = os_snprintf(pos, end - pos, "wpa_state=%s\n", wpa_supplicant_state_txt(wpa_s->wpa_state)); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; if (wpa_s->l2 && l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) { ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } #ifdef CONFIG_P2P if (wpa_s->global->p2p) { ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR "\n", MAC2STR(wpa_s->global->p2p_dev_addr)); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } #endif /* CONFIG_P2P */ ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n", MAC2STR(wpa_s->own_addr)); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; #ifdef CONFIG_HS20 if (wpa_s->current_bss && (hs20 = wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE)) && wpa_s->wpa_proto == WPA_PROTO_RSN && wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { int release = 1; if (hs20[1] >= 5) { u8 rel_num = (hs20[6] & 0xf0) >> 4; release = rel_num + 1; } ret = os_snprintf(pos, end - pos, "hs20=%d\n", release); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } if (wpa_s->current_ssid) { struct wpa_cred *cred; char *type; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { size_t i; if (wpa_s->current_ssid->parent_cred != cred) continue; if (cred->provisioning_sp) { ret = os_snprintf(pos, end - pos, "provisioning_sp=%s\n", cred->provisioning_sp); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } if (!cred->domain) goto no_domain; i = 0; if (wpa_s->current_bss && wpa_s->current_bss->anqp) { struct wpabuf *names = wpa_s->current_bss->anqp->domain_name; for (i = 0; names && i < cred->num_domain; i++) { if (domain_name_list_contains( names, cred->domain[i], 1)) break; } if (i == cred->num_domain) i = 0; /* show first entry by default */ } ret = os_snprintf(pos, end - pos, "home_sp=%s\n", cred->domain[i]); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; no_domain: if (wpa_s->current_bss == NULL || wpa_s->current_bss->anqp == NULL) res = -1; else res = interworking_home_sp_cred( wpa_s, cred, wpa_s->current_bss->anqp->domain_name); if (res > 0) type = "home"; else if (res == 0) type = "roaming"; else type = "unknown"; ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; break; } } #endif /* CONFIG_HS20 */ if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos, verbose); if (res >= 0) pos += res; } res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose); if (res >= 0) pos += res; #ifdef CONFIG_WPS { char uuid_str[100]; uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str)); ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } #endif /* CONFIG_WPS */ #ifdef ANDROID wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE "id=%d state=%d BSSID=" MACSTR " SSID=%s", wpa_s->current_ssid ? wpa_s->current_ssid->id : -1, wpa_s->wpa_state, MAC2STR(wpa_s->bssid), wpa_s->current_ssid && wpa_s->current_ssid->ssid ? wpa_ssid_txt(wpa_s->current_ssid->ssid, wpa_s->current_ssid->ssid_len) : ""); if (wpa_s->wpa_state == WPA_COMPLETED) { struct wpa_ssid *ssid = wpa_s->current_ssid; wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- connection to " MACSTR " completed %s [id=%d id_str=%s]", MAC2STR(wpa_s->bssid), "(auth)", ssid ? ssid->id : -1, ssid && ssid->id_str ? ssid->id_str : ""); } #endif /* ANDROID */ return pos - buf; } static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s, char *cmd) { char *pos; int id; struct wpa_ssid *ssid; u8 bssid[ETH_ALEN]; /* cmd: " " */ pos = os_strchr(cmd, ' '); if (pos == NULL) return -1; *pos++ = '\0'; id = atoi(cmd); wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos); if (hwaddr_aton(pos, bssid)) { wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos); return -1; } ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " "to update", id); return -1; } os_memcpy(ssid->bssid, bssid, ETH_ALEN); ssid->bssid_set = !is_zero_ether_addr(bssid); return 0; } static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { u8 bssid[ETH_ALEN]; struct wpa_blacklist *e; char *pos, *end; int ret; /* cmd: "BLACKLIST []" */ if (*cmd == '\0') { pos = buf; end = buf + buflen; e = wpa_s->blacklist; while (e) { ret = os_snprintf(pos, end - pos, MACSTR "\n", MAC2STR(e->bssid)); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; e = e->next; } return pos - buf; } cmd++; if (os_strncmp(cmd, "clear", 5) == 0) { wpa_blacklist_clear(wpa_s); os_memcpy(buf, "OK\n", 3); return 3; } wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd); if (hwaddr_aton(cmd, bssid)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd); return -1; } /* * Add the BSSID twice, so its count will be 2, causing it to be * skipped when processing scan results. */ ret = wpa_blacklist_add(wpa_s, bssid); if (ret < 0) return -1; ret = wpa_blacklist_add(wpa_s, bssid); if (ret < 0) return -1; os_memcpy(buf, "OK\n", 3); return 3; } static const char * debug_level_str(int level) { switch (level) { case MSG_EXCESSIVE: return "EXCESSIVE"; case MSG_MSGDUMP: return "MSGDUMP"; case MSG_DEBUG: return "DEBUG"; case MSG_INFO: return "INFO"; case MSG_WARNING: return "WARNING"; case MSG_ERROR: return "ERROR"; default: return "?"; } } static int str_to_debug_level(const char *s) { if (os_strcasecmp(s, "EXCESSIVE") == 0) return MSG_EXCESSIVE; if (os_strcasecmp(s, "MSGDUMP") == 0) return MSG_MSGDUMP; if (os_strcasecmp(s, "DEBUG") == 0) return MSG_DEBUG; if (os_strcasecmp(s, "INFO") == 0) return MSG_INFO; if (os_strcasecmp(s, "WARNING") == 0) return MSG_WARNING; if (os_strcasecmp(s, "ERROR") == 0) return MSG_ERROR; return -1; } static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { char *pos, *end, *stamp; int ret; if (cmd == NULL) { return -1; } /* cmd: "LOG_LEVEL []" */ if (*cmd == '\0') { pos = buf; end = buf + buflen; ret = os_snprintf(pos, end - pos, "Current level: %s\n" "Timestamp: %d\n", debug_level_str(wpa_debug_level), wpa_debug_timestamp); if (ret < 0 || ret >= end - pos) ret = 0; return ret; } while (*cmd == ' ') cmd++; stamp = os_strchr(cmd, ' '); if (stamp) { *stamp++ = '\0'; while (*stamp == ' ') { stamp++; } } if (cmd && os_strlen(cmd)) { int level = str_to_debug_level(cmd); if (level < 0) return -1; wpa_debug_level = level; } if (stamp && os_strlen(stamp)) wpa_debug_timestamp = atoi(stamp); os_memcpy(buf, "OK\n", 3); return 3; } static int wpa_supplicant_ctrl_iface_list_networks( struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { char *pos, *end; struct wpa_ssid *ssid; int ret; pos = buf; end = buf + buflen; ret = os_snprintf(pos, end - pos, "network id / ssid / bssid / flags\n"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; ssid = wpa_s->conf->ssid; while (ssid) { ret = os_snprintf(pos, end - pos, "%d\t%s", ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; if (ssid->bssid_set) { ret = os_snprintf(pos, end - pos, "\t" MACSTR, MAC2STR(ssid->bssid)); } else { ret = os_snprintf(pos, end - pos, "\tany"); } if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; ret = os_snprintf(pos, end - pos, "\t%s%s%s%s", ssid == wpa_s->current_ssid ? "[CURRENT]" : "", ssid->disabled ? "[DISABLED]" : "", ssid->disabled_until.sec ? "[TEMP-DISABLED]" : "", ssid->disabled == 2 ? "[P2P-PERSISTENT]" : ""); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; ret = os_snprintf(pos, end - pos, "\n"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; ssid = ssid->next; } return pos - buf; } static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher) { int ret; ret = os_snprintf(pos, end - pos, "-"); if (ret < 0 || ret >= end - pos) return pos; pos += ret; ret = wpa_write_ciphers(pos, end, cipher, "+"); if (ret < 0) return pos; pos += ret; return pos; } static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, const u8 *ie, size_t ie_len) { struct wpa_ie_data data; char *start; int ret; ret = os_snprintf(pos, end - pos, "[%s-", proto); if (ret < 0 || ret >= end - pos) return pos; pos += ret; if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) { ret = os_snprintf(pos, end - pos, "?]"); if (ret < 0 || ret >= end - pos) return pos; pos += ret; return pos; } start = pos; if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) { ret = os_snprintf(pos, end - pos, "%sEAP", pos == start ? "" : "+"); if (ret < 0 || ret >= end - pos) return pos; pos += ret; } if (data.key_mgmt & WPA_KEY_MGMT_PSK) { ret = os_snprintf(pos, end - pos, "%sPSK", pos == start ? "" : "+"); if (ret < 0 || ret >= end - pos) return pos; pos += ret; } if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) { ret = os_snprintf(pos, end - pos, "%sNone", pos == start ? "" : "+"); if (ret < 0 || ret >= end - pos) return pos; pos += ret; } #ifdef CONFIG_IEEE80211R if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { ret = os_snprintf(pos, end - pos, "%sFT/EAP", pos == start ? "" : "+"); if (ret < 0 || ret >= end - pos) return pos; pos += ret; } if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) { ret = os_snprintf(pos, end - pos, "%sFT/PSK", pos == start ? "" : "+"); if (ret < 0 || ret >= end - pos) return pos; pos += ret; } #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { ret = os_snprintf(pos, end - pos, "%sEAP-SHA256", pos == start ? "" : "+"); if (ret < 0 || ret >= end - pos) return pos; pos += ret; } if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { ret = os_snprintf(pos, end - pos, "%sPSK-SHA256", pos == start ? "" : "+"); if (ret < 0 || ret >= end - pos) return pos; pos += ret; } #endif /* CONFIG_IEEE80211W */ pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher); if (data.capabilities & WPA_CAPABILITY_PREAUTH) { ret = os_snprintf(pos, end - pos, "-preauth"); if (ret < 0 || ret >= end - pos) return pos; pos += ret; } ret = os_snprintf(pos, end - pos, "]"); if (ret < 0 || ret >= end - pos) return pos; pos += ret; return pos; } #ifdef CONFIG_WPS static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s, char *pos, char *end, struct wpabuf *wps_ie) { int ret; const char *txt; if (wps_ie == NULL) return pos; if (wps_is_selected_pbc_registrar(wps_ie)) txt = "[WPS-PBC]"; else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0)) txt = "[WPS-AUTH]"; else if (wps_is_selected_pin_registrar(wps_ie)) txt = "[WPS-PIN]"; else txt = "[WPS]"; ret = os_snprintf(pos, end - pos, "%s", txt); if (ret >= 0 && ret < end - pos) pos += ret; wpabuf_free(wps_ie); return pos; } #endif /* CONFIG_WPS */ static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s, char *pos, char *end, const struct wpa_bss *bss) { #ifdef CONFIG_WPS struct wpabuf *wps_ie; wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie); #else /* CONFIG_WPS */ return pos; #endif /* CONFIG_WPS */ } /* Format one result on one text line into a buffer. */ static int wpa_supplicant_ctrl_iface_scan_result( struct wpa_supplicant *wpa_s, const struct wpa_bss *bss, char *buf, size_t buflen) { char *pos, *end; int ret; const u8 *ie, *ie2, *p2p; p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE); if (!p2p) p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE); if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN && os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0) return 0; /* Do not show P2P listen discovery results here */ pos = buf; end = buf + buflen; ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t", MAC2STR(bss->bssid), bss->freq, bss->level); if (ret < 0 || ret >= end - pos) return -1; pos += ret; ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); if (ie) pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]); ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN); if (ie2) pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]); pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss); if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) { ret = os_snprintf(pos, end - pos, "[WEP]"); if (ret < 0 || ret >= end - pos) return -1; pos += ret; } if (bss_is_dmg(bss)) { const char *s; ret = os_snprintf(pos, end - pos, "[DMG]"); if (ret < 0 || ret >= end - pos) return -1; pos += ret; switch (bss->caps & IEEE80211_CAP_DMG_MASK) { case IEEE80211_CAP_DMG_IBSS: s = "[IBSS]"; break; case IEEE80211_CAP_DMG_AP: s = "[ESS]"; break; case IEEE80211_CAP_DMG_PBSS: s = "[PBSS]"; break; default: s = ""; break; } ret = os_snprintf(pos, end - pos, "%s", s); if (ret < 0 || ret >= end - pos) return -1; pos += ret; } else { if (bss->caps & IEEE80211_CAP_IBSS) { ret = os_snprintf(pos, end - pos, "[IBSS]"); if (ret < 0 || ret >= end - pos) return -1; pos += ret; } if (bss->caps & IEEE80211_CAP_ESS) { ret = os_snprintf(pos, end - pos, "[ESS]"); if (ret < 0 || ret >= end - pos) return -1; pos += ret; } } if (p2p) { ret = os_snprintf(pos, end - pos, "[P2P]"); if (ret < 0 || ret >= end - pos) return -1; pos += ret; } #ifdef CONFIG_HS20 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) { ret = os_snprintf(pos, end - pos, "[HS20]"); if (ret < 0 || ret >= end - pos) return -1; pos += ret; } #endif /* CONFIG_HS20 */ ret = os_snprintf(pos, end - pos, "\t%s", wpa_ssid_txt(bss->ssid, bss->ssid_len)); if (ret < 0 || ret >= end - pos) return -1; pos += ret; ret = os_snprintf(pos, end - pos, "\n"); if (ret < 0 || ret >= end - pos) return -1; pos += ret; return pos - buf; } static int wpa_supplicant_ctrl_iface_scan_results( struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { char *pos, *end; struct wpa_bss *bss; int ret; pos = buf; end = buf + buflen; ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / " "flags / ssid\n"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos, end - pos); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } return pos - buf; } static int wpa_supplicant_ctrl_iface_select_network( struct wpa_supplicant *wpa_s, char *cmd) { int id; struct wpa_ssid *ssid; char *pos; /* cmd: "" or "any" */ if (os_strncmp(cmd, "any", 3) == 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any"); ssid = NULL; } else { id = atoi(cmd); wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id); ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " "network id=%d", id); return -1; } if (ssid->disabled == 2) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " "SELECT_NETWORK with persistent P2P group"); return -1; } } pos = os_strstr(cmd, " freq="); if (pos) { int *freqs = freq_range_to_channel_list(wpa_s, pos + 6); if (freqs) { wpa_s->scan_req = MANUAL_SCAN_REQ; os_free(wpa_s->manual_scan_freqs); wpa_s->manual_scan_freqs = freqs; } } wpa_supplicant_select_network(wpa_s, ssid); return 0; } static int wpa_supplicant_ctrl_iface_enable_network( struct wpa_supplicant *wpa_s, char *cmd) { int id; struct wpa_ssid *ssid; /* cmd: "" or "all" */ if (os_strcmp(cmd, "all") == 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all"); ssid = NULL; } else { id = atoi(cmd); wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id); ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " "network id=%d", id); return -1; } if (ssid->disabled == 2) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " "ENABLE_NETWORK with persistent P2P group"); return -1; } if (os_strstr(cmd, " no-connect")) { ssid->disabled = 0; return 0; } } wpa_supplicant_enable_network(wpa_s, ssid); return 0; } static int wpa_supplicant_ctrl_iface_disable_network( struct wpa_supplicant *wpa_s, char *cmd) { int id; struct wpa_ssid *ssid; /* cmd: "" or "all" */ if (os_strcmp(cmd, "all") == 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all"); ssid = NULL; } else { id = atoi(cmd); wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id); ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " "network id=%d", id); return -1; } if (ssid->disabled == 2) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " "DISABLE_NETWORK with persistent P2P " "group"); return -1; } } wpa_supplicant_disable_network(wpa_s, ssid); return 0; } static int wpa_supplicant_ctrl_iface_add_network( struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { struct wpa_ssid *ssid; int ret; wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK"); ssid = wpa_config_add_network(wpa_s->conf); if (ssid == NULL) return -1; wpas_notify_network_added(wpa_s, ssid); ssid->disabled = 1; wpa_config_set_network_defaults(ssid); ret = os_snprintf(buf, buflen, "%d\n", ssid->id); if (ret < 0 || (size_t) ret >= buflen) return -1; return ret; } static int wpa_supplicant_ctrl_iface_remove_network( struct wpa_supplicant *wpa_s, char *cmd) { int id; struct wpa_ssid *ssid; int was_disabled; /* cmd: "" or "all" */ if (os_strcmp(cmd, "all") == 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all"); if (wpa_s->sched_scanning) wpa_supplicant_cancel_sched_scan(wpa_s); eapol_sm_invalidate_cached_session(wpa_s->eapol); if (wpa_s->current_ssid) { #ifdef CONFIG_SME wpa_s->sme.prev_bssid_set = 0; #endif /* CONFIG_SME */ wpa_sm_set_config(wpa_s->wpa, NULL); eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); } ssid = wpa_s->conf->ssid; while (ssid) { struct wpa_ssid *remove_ssid = ssid; id = ssid->id; ssid = ssid->next; wpas_notify_network_removed(wpa_s, remove_ssid); wpa_config_remove_network(wpa_s->conf, id); } return 0; } id = atoi(cmd); wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id); ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid) wpas_notify_network_removed(wpa_s, ssid); if (ssid == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " "id=%d", id); return -1; } if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) { #ifdef CONFIG_SME wpa_s->sme.prev_bssid_set = 0; #endif /* CONFIG_SME */ /* * Invalidate the EAP session cache if the current or * previously used network is removed. */ eapol_sm_invalidate_cached_session(wpa_s->eapol); } if (ssid == wpa_s->current_ssid) { wpa_sm_set_config(wpa_s->wpa, NULL); eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); } was_disabled = ssid->disabled; if (wpa_config_remove_network(wpa_s->conf, id) < 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the " "network id=%d", id); return -1; } if (!was_disabled && wpa_s->sched_scanning) { wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove " "network from filters"); wpa_supplicant_cancel_sched_scan(wpa_s); wpa_supplicant_req_scan(wpa_s, 0, 0); } return 0; } static int wpa_supplicant_ctrl_iface_update_network( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, char *name, char *value) { if (wpa_config_set(ssid, name, value, 0) < 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network " "variable '%s'", name); return -1; } if (os_strcmp(name, "bssid") != 0 && os_strcmp(name, "priority") != 0) wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) { /* * Invalidate the EAP session cache if anything in the current * or previously used configuration changes. */ eapol_sm_invalidate_cached_session(wpa_s->eapol); } if ((os_strcmp(name, "psk") == 0 && value[0] == '"' && ssid->ssid_len) || (os_strcmp(name, "ssid") == 0 && ssid->passphrase)) wpa_config_update_psk(ssid); else if (os_strcmp(name, "priority") == 0) wpa_config_update_prio_list(wpa_s->conf); return 0; } static int wpa_supplicant_ctrl_iface_set_network( struct wpa_supplicant *wpa_s, char *cmd) { int id; struct wpa_ssid *ssid; char *name, *value; /* cmd: " " */ name = os_strchr(cmd, ' '); if (name == NULL) return -1; *name++ = '\0'; value = os_strchr(name, ' '); if (value == NULL) return -1; *value++ = '\0'; id = atoi(cmd); wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'", id, name); wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value", (u8 *) value, os_strlen(value)); ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " "id=%d", id); return -1; } return wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name, value); } static int wpa_supplicant_ctrl_iface_get_network( struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { int id; size_t res; struct wpa_ssid *ssid; char *name, *value; /* cmd: " " */ name = os_strchr(cmd, ' '); if (name == NULL || buflen == 0) return -1; *name++ = '\0'; id = atoi(cmd); wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'", id, name); ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " "id=%d", id); return -1; } value = wpa_config_get_no_key(ssid, name); if (value == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network " "variable '%s'", name); return -1; } res = os_strlcpy(buf, value, buflen); if (res >= buflen) { os_free(value); return -1; } os_free(value); return res; } static int wpa_supplicant_ctrl_iface_dup_network( struct wpa_supplicant *wpa_s, char *cmd) { struct wpa_ssid *ssid_s, *ssid_d; char *name, *id, *value; int id_s, id_d, ret; /* cmd: " " */ id = os_strchr(cmd, ' '); if (id == NULL) return -1; *id++ = '\0'; name = os_strchr(id, ' '); if (name == NULL) return -1; *name++ = '\0'; id_s = atoi(cmd); id_d = atoi(id); wpa_printf(MSG_DEBUG, "CTRL_IFACE: DUP_NETWORK id=%d -> %d name='%s'", id_s, id_d, name); ssid_s = wpa_config_get_network(wpa_s->conf, id_s); if (ssid_s == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " "network id=%d", id_s); return -1; } ssid_d = wpa_config_get_network(wpa_s->conf, id_d); if (ssid_d == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " "network id=%d", id_s); return -1; } value = wpa_config_get(ssid_s, name); if (value == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network " "variable '%s'", name); return -1; } ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid_d, name, value); os_free(value); return ret; } static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { char *pos, *end; struct wpa_cred *cred; int ret; pos = buf; end = buf + buflen; ret = os_snprintf(pos, end - pos, "cred id / realm / username / domain / imsi\n"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; cred = wpa_s->conf->cred; while (cred) { ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n", cred->id, cred->realm ? cred->realm : "", cred->username ? cred->username : "", cred->domain ? cred->domain[0] : "", cred->imsi ? cred->imsi : ""); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; cred = cred->next; } return pos - buf; } static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { struct wpa_cred *cred; int ret; wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED"); cred = wpa_config_add_cred(wpa_s->conf); if (cred == NULL) return -1; wpa_msg(wpa_s, MSG_INFO, CRED_ADDED "%d", cred->id); ret = os_snprintf(buf, buflen, "%d\n", cred->id); if (ret < 0 || (size_t) ret >= buflen) return -1; return ret; } static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s, struct wpa_cred *cred) { struct wpa_ssid *ssid; char str[20]; int id; if (cred == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred"); return -1; } id = cred->id; if (wpa_config_remove_cred(wpa_s->conf, id) < 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred"); return -1; } wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id); /* Remove any network entry created based on the removed credential */ ssid = wpa_s->conf->ssid; while (ssid) { if (ssid->parent_cred == cred) { wpa_printf(MSG_DEBUG, "Remove network id %d since it " "used the removed credential", ssid->id); os_snprintf(str, sizeof(str), "%d", ssid->id); ssid = ssid->next; wpa_supplicant_ctrl_iface_remove_network(wpa_s, str); } else ssid = ssid->next; } return 0; } static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, char *cmd) { int id; struct wpa_cred *cred, *prev; /* cmd: "", "all", "sp_fqdn=", or * "provisioning_sp= */ if (os_strcmp(cmd, "all") == 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all"); cred = wpa_s->conf->cred; while (cred) { prev = cred; cred = cred->next; wpas_ctrl_remove_cred(wpa_s, prev); } return 0; } if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'", cmd + 8); cred = wpa_s->conf->cred; while (cred) { prev = cred; cred = cred->next; if (prev->domain) { size_t i; for (i = 0; i < prev->num_domain; i++) { if (os_strcmp(prev->domain[i], cmd + 8) != 0) continue; wpas_ctrl_remove_cred(wpa_s, prev); break; } } } return 0; } if (os_strncmp(cmd, "provisioning_sp=", 16) == 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED provisioning SP FQDN '%s'", cmd + 16); cred = wpa_s->conf->cred; while (cred) { prev = cred; cred = cred->next; if (prev->provisioning_sp && os_strcmp(prev->provisioning_sp, cmd + 16) == 0) wpas_ctrl_remove_cred(wpa_s, prev); } return 0; } id = atoi(cmd); wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id); cred = wpa_config_get_cred(wpa_s->conf, id); return wpas_ctrl_remove_cred(wpa_s, cred); } static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s, char *cmd) { int id; struct wpa_cred *cred; char *name, *value; /* cmd: " " */ name = os_strchr(cmd, ' '); if (name == NULL) return -1; *name++ = '\0'; value = os_strchr(name, ' '); if (value == NULL) return -1; *value++ = '\0'; id = atoi(cmd); wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'", id, name); wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value", (u8 *) value, os_strlen(value)); cred = wpa_config_get_cred(wpa_s->conf, id); if (cred == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d", id); return -1; } if (wpa_config_set_cred(cred, name, value, 0) < 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred " "variable '%s'", name); return -1; } wpa_msg(wpa_s, MSG_INFO, CRED_MODIFIED "%d %s", cred->id, name); return 0; } static int wpa_supplicant_ctrl_iface_get_cred(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { int id; size_t res; struct wpa_cred *cred; char *name, *value; /* cmd: " " */ name = os_strchr(cmd, ' '); if (name == NULL) return -1; *name++ = '\0'; id = atoi(cmd); wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CRED id=%d name='%s'", id, name); cred = wpa_config_get_cred(wpa_s->conf, id); if (cred == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d", id); return -1; } value = wpa_config_get_cred_no_key(cred, name); if (value == NULL) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get cred variable '%s'", name); return -1; } res = os_strlcpy(buf, value, buflen); if (res >= buflen) { os_free(value); return -1; } os_free(value); return res; } #ifndef CONFIG_NO_CONFIG_WRITE static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s) { int ret; if (!wpa_s->conf->update_config) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed " "to update configuration (update_config=0)"); return -1; } ret = wpa_config_write(wpa_s->confname, wpa_s->conf); if (ret) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to " "update configuration"); } else { wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration" " updated"); } return ret; } #endif /* CONFIG_NO_CONFIG_WRITE */ struct cipher_info { unsigned int capa; const char *name; int group_only; }; static const struct cipher_info ciphers[] = { { WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 }, { WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 }, { WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 }, { WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 }, { WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 }, { WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 }, { WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 }, { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 } }; static int ctrl_iface_get_capability_pairwise(int res, char *strict, struct wpa_driver_capa *capa, char *buf, size_t buflen) { int ret; char *pos, *end; size_t len; unsigned int i; pos = buf; end = pos + buflen; if (res < 0) { if (strict) return 0; len = os_strlcpy(buf, "CCMP TKIP NONE", buflen); if (len >= buflen) return -1; return len; } for (i = 0; i < ARRAY_SIZE(ciphers); i++) { if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) { ret = os_snprintf(pos, end - pos, "%s%s", pos == buf ? "" : " ", ciphers[i].name); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } } return pos - buf; } static int ctrl_iface_get_capability_group(int res, char *strict, struct wpa_driver_capa *capa, char *buf, size_t buflen) { int ret; char *pos, *end; size_t len; unsigned int i; pos = buf; end = pos + buflen; if (res < 0) { if (strict) return 0; len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen); if (len >= buflen) return -1; return len; } for (i = 0; i < ARRAY_SIZE(ciphers); i++) { if (capa->enc & ciphers[i].capa) { ret = os_snprintf(pos, end - pos, "%s%s", pos == buf ? "" : " ", ciphers[i].name); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } } return pos - buf; } static int ctrl_iface_get_capability_key_mgmt(int res, char *strict, struct wpa_driver_capa *capa, char *buf, size_t buflen) { int ret; char *pos, *end; size_t len; pos = buf; end = pos + buflen; if (res < 0) { if (strict) return 0; len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE " "NONE", buflen); if (len >= buflen) return -1; return len; } ret = os_snprintf(pos, end - pos, "NONE IEEE8021X"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { ret = os_snprintf(pos, end - pos, " WPA-EAP"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { ret = os_snprintf(pos, end - pos, " WPA-PSK"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { ret = os_snprintf(pos, end - pos, " WPA-NONE"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } return pos - buf; } static int ctrl_iface_get_capability_proto(int res, char *strict, struct wpa_driver_capa *capa, char *buf, size_t buflen) { int ret; char *pos, *end; size_t len; pos = buf; end = pos + buflen; if (res < 0) { if (strict) return 0; len = os_strlcpy(buf, "RSN WPA", buflen); if (len >= buflen) return -1; return len; } if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { ret = os_snprintf(pos, end - pos, "%sRSN", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) { ret = os_snprintf(pos, end - pos, "%sWPA", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } return pos - buf; } static int ctrl_iface_get_capability_auth_alg(int res, char *strict, struct wpa_driver_capa *capa, char *buf, size_t buflen) { int ret; char *pos, *end; size_t len; pos = buf; end = pos + buflen; if (res < 0) { if (strict) return 0; len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen); if (len >= buflen) return -1; return len; } if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) { ret = os_snprintf(pos, end - pos, "%sOPEN", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) { ret = os_snprintf(pos, end - pos, "%sSHARED", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) { ret = os_snprintf(pos, end - pos, "%sLEAP", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } return pos - buf; } static int ctrl_iface_get_capability_modes(int res, char *strict, struct wpa_driver_capa *capa, char *buf, size_t buflen) { int ret; char *pos, *end; size_t len; pos = buf; end = pos + buflen; if (res < 0) { if (strict) return 0; len = os_strlcpy(buf, "IBSS AP", buflen); if (len >= buflen) return -1; return len; } if (capa->flags & WPA_DRIVER_FLAGS_IBSS) { ret = os_snprintf(pos, end - pos, "%sIBSS", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } if (capa->flags & WPA_DRIVER_FLAGS_AP) { ret = os_snprintf(pos, end - pos, "%sAP", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } return pos - buf; } static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { struct hostapd_channel_data *chnl; int ret, i, j; char *pos, *end, *hmode; pos = buf; end = pos + buflen; for (j = 0; j < wpa_s->hw.num_modes; j++) { switch (wpa_s->hw.modes[j].mode) { case HOSTAPD_MODE_IEEE80211B: hmode = "B"; break; case HOSTAPD_MODE_IEEE80211G: hmode = "G"; break; case HOSTAPD_MODE_IEEE80211A: hmode = "A"; break; case HOSTAPD_MODE_IEEE80211AD: hmode = "AD"; break; default: continue; } ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; chnl = wpa_s->hw.modes[j].channels; for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) { if (chnl[i].flag & HOSTAPD_CHAN_DISABLED) continue; ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } ret = os_snprintf(pos, end - pos, "\n"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } return pos - buf; } static int ctrl_iface_get_capability_freq(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { struct hostapd_channel_data *chnl; int ret, i, j; char *pos, *end, *hmode; pos = buf; end = pos + buflen; for (j = 0; j < wpa_s->hw.num_modes; j++) { switch (wpa_s->hw.modes[j].mode) { case HOSTAPD_MODE_IEEE80211B: hmode = "B"; break; case HOSTAPD_MODE_IEEE80211G: hmode = "G"; break; case HOSTAPD_MODE_IEEE80211A: hmode = "A"; break; case HOSTAPD_MODE_IEEE80211AD: hmode = "AD"; break; default: continue; } ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:\n", hmode); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; chnl = wpa_s->hw.modes[j].channels; for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) { if (chnl[i].flag & HOSTAPD_CHAN_DISABLED) continue; ret = os_snprintf(pos, end - pos, " %d = %d MHz%s%s\n", chnl[i].chan, chnl[i].freq, chnl[i].flag & HOSTAPD_CHAN_NO_IBSS ? " (NO_IBSS)" : "", chnl[i].flag & HOSTAPD_CHAN_RADAR ? " (DFS)" : ""); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } ret = os_snprintf(pos, end - pos, "\n"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } return pos - buf; } static int wpa_supplicant_ctrl_iface_get_capability( struct wpa_supplicant *wpa_s, const char *_field, char *buf, size_t buflen) { struct wpa_driver_capa capa; int res; char *strict; char field[30]; size_t len; /* Determine whether or not strict checking was requested */ len = os_strlcpy(field, _field, sizeof(field)); if (len >= sizeof(field)) return -1; strict = os_strchr(field, ' '); if (strict != NULL) { *strict++ = '\0'; if (os_strcmp(strict, "strict") != 0) return -1; } wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s", field, strict ? strict : ""); if (os_strcmp(field, "eap") == 0) { return eap_get_names(buf, buflen); } res = wpa_drv_get_capa(wpa_s, &capa); if (os_strcmp(field, "pairwise") == 0) return ctrl_iface_get_capability_pairwise(res, strict, &capa, buf, buflen); if (os_strcmp(field, "group") == 0) return ctrl_iface_get_capability_group(res, strict, &capa, buf, buflen); if (os_strcmp(field, "key_mgmt") == 0) return ctrl_iface_get_capability_key_mgmt(res, strict, &capa, buf, buflen); if (os_strcmp(field, "proto") == 0) return ctrl_iface_get_capability_proto(res, strict, &capa, buf, buflen); if (os_strcmp(field, "auth_alg") == 0) return ctrl_iface_get_capability_auth_alg(res, strict, &capa, buf, buflen); if (os_strcmp(field, "modes") == 0) return ctrl_iface_get_capability_modes(res, strict, &capa, buf, buflen); if (os_strcmp(field, "channels") == 0) return ctrl_iface_get_capability_channels(wpa_s, buf, buflen); if (os_strcmp(field, "freq") == 0) return ctrl_iface_get_capability_freq(wpa_s, buf, buflen); #ifdef CONFIG_TDLS if (os_strcmp(field, "tdls") == 0) return ctrl_iface_get_capability_tdls(wpa_s, buf, buflen); #endif /* CONFIG_TDLS */ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'", field); return -1; } #ifdef CONFIG_INTERWORKING static char * anqp_add_hex(char *pos, char *end, const char *title, struct wpabuf *data) { char *start = pos; size_t i; int ret; const u8 *d; if (data == NULL) return start; ret = os_snprintf(pos, end - pos, "%s=", title); if (ret < 0 || ret >= end - pos) return start; pos += ret; d = wpabuf_head_u8(data); for (i = 0; i < wpabuf_len(data); i++) { ret = os_snprintf(pos, end - pos, "%02x", *d++); if (ret < 0 || ret >= end - pos) return start; pos += ret; } ret = os_snprintf(pos, end - pos, "\n"); if (ret < 0 || ret >= end - pos) return start; pos += ret; return pos; } #endif /* CONFIG_INTERWORKING */ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, unsigned long mask, char *buf, size_t buflen) { size_t i; int ret; char *pos, *end; const u8 *ie, *ie2; pos = buf; end = buf + buflen; if (mask & WPA_BSS_MASK_ID) { ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } if (mask & WPA_BSS_MASK_BSSID) { ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n", MAC2STR(bss->bssid)); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } if (mask & WPA_BSS_MASK_FREQ) { ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } if (mask & WPA_BSS_MASK_BEACON_INT) { ret = os_snprintf(pos, end - pos, "beacon_int=%d\n", bss->beacon_int); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } if (mask & WPA_BSS_MASK_CAPABILITIES) { ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n", bss->caps); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } if (mask & WPA_BSS_MASK_QUAL) { ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } if (mask & WPA_BSS_MASK_NOISE) { ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } if (mask & WPA_BSS_MASK_LEVEL) { ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } if (mask & WPA_BSS_MASK_TSF) { ret = os_snprintf(pos, end - pos, "tsf=%016llu\n", (unsigned long long) bss->tsf); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } if (mask & WPA_BSS_MASK_AGE) { struct os_reltime now; os_get_reltime(&now); ret = os_snprintf(pos, end - pos, "age=%d\n", (int) (now.sec - bss->last_update.sec)); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } if (mask & WPA_BSS_MASK_IE) { ret = os_snprintf(pos, end - pos, "ie="); if (ret < 0 || ret >= end - pos) return 0; pos += ret; ie = (const u8 *) (bss + 1); for (i = 0; i < bss->ie_len; i++) { ret = os_snprintf(pos, end - pos, "%02x", *ie++); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } ret = os_snprintf(pos, end - pos, "\n"); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } if (mask & WPA_BSS_MASK_FLAGS) { ret = os_snprintf(pos, end - pos, "flags="); if (ret < 0 || ret >= end - pos) return 0; pos += ret; ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); if (ie) pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]); ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN); if (ie2) pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]); pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss); if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) { ret = os_snprintf(pos, end - pos, "[WEP]"); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } if (bss_is_dmg(bss)) { const char *s; ret = os_snprintf(pos, end - pos, "[DMG]"); if (ret < 0 || ret >= end - pos) return 0; pos += ret; switch (bss->caps & IEEE80211_CAP_DMG_MASK) { case IEEE80211_CAP_DMG_IBSS: s = "[IBSS]"; break; case IEEE80211_CAP_DMG_AP: s = "[ESS]"; break; case IEEE80211_CAP_DMG_PBSS: s = "[PBSS]"; break; default: s = ""; break; } ret = os_snprintf(pos, end - pos, "%s", s); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } else { if (bss->caps & IEEE80211_CAP_IBSS) { ret = os_snprintf(pos, end - pos, "[IBSS]"); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } if (bss->caps & IEEE80211_CAP_ESS) { ret = os_snprintf(pos, end - pos, "[ESS]"); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } } if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) || wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) { ret = os_snprintf(pos, end - pos, "[P2P]"); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } #ifdef CONFIG_HS20 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) { ret = os_snprintf(pos, end - pos, "[HS20]"); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } #endif /* CONFIG_HS20 */ ret = os_snprintf(pos, end - pos, "\n"); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } if (mask & WPA_BSS_MASK_SSID) { ret = os_snprintf(pos, end - pos, "ssid=%s\n", wpa_ssid_txt(bss->ssid, bss->ssid_len)); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } #ifdef CONFIG_WPS if (mask & WPA_BSS_MASK_WPS_SCAN) { ie = (const u8 *) (bss + 1); ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P if (mask & WPA_BSS_MASK_P2P_SCAN) { ie = (const u8 *) (bss + 1); ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } #endif /* CONFIG_P2P */ #ifdef CONFIG_WIFI_DISPLAY if (mask & WPA_BSS_MASK_WIFI_DISPLAY) { struct wpabuf *wfd; ie = (const u8 *) (bss + 1); wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len, WFD_IE_VENDOR_TYPE); if (wfd) { ret = os_snprintf(pos, end - pos, "wfd_subelems="); if (ret < 0 || ret >= end - pos) { wpabuf_free(wfd); return 0; } pos += ret; pos += wpa_snprintf_hex(pos, end - pos, wpabuf_head(wfd), wpabuf_len(wfd)); wpabuf_free(wfd); ret = os_snprintf(pos, end - pos, "\n"); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } } #endif /* CONFIG_WIFI_DISPLAY */ #ifdef CONFIG_INTERWORKING if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) { struct wpa_bss_anqp *anqp = bss->anqp; pos = anqp_add_hex(pos, end, "anqp_venue_name", anqp->venue_name); pos = anqp_add_hex(pos, end, "anqp_network_auth_type", anqp->network_auth_type); pos = anqp_add_hex(pos, end, "anqp_roaming_consortium", anqp->roaming_consortium); pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability", anqp->ip_addr_type_availability); pos = anqp_add_hex(pos, end, "anqp_nai_realm", anqp->nai_realm); pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp); pos = anqp_add_hex(pos, end, "anqp_domain_name", anqp->domain_name); #ifdef CONFIG_HS20 pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name", anqp->hs20_operator_friendly_name); pos = anqp_add_hex(pos, end, "hs20_wan_metrics", anqp->hs20_wan_metrics); pos = anqp_add_hex(pos, end, "hs20_connection_capability", anqp->hs20_connection_capability); pos = anqp_add_hex(pos, end, "hs20_operating_class", anqp->hs20_operating_class); pos = anqp_add_hex(pos, end, "hs20_osu_providers_list", anqp->hs20_osu_providers_list); #endif /* CONFIG_HS20 */ } #endif /* CONFIG_INTERWORKING */ if (mask & WPA_BSS_MASK_DELIM) { ret = os_snprintf(pos, end - pos, "====\n"); if (ret < 0 || ret >= end - pos) return 0; pos += ret; } return pos - buf; } static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s, const char *cmd, char *buf, size_t buflen) { u8 bssid[ETH_ALEN]; size_t i; struct wpa_bss *bss; struct wpa_bss *bsslast = NULL; struct dl_list *next; int ret = 0; int len; char *ctmp; unsigned long mask = WPA_BSS_MASK_ALL; if (os_strncmp(cmd, "RANGE=", 6) == 0) { if (os_strncmp(cmd + 6, "ALL", 3) == 0) { bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id); bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id); } else { /* N1-N2 */ unsigned int id1, id2; if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) { wpa_printf(MSG_INFO, "Wrong BSS range " "format"); return 0; } if (*(cmd + 6) == '-') id1 = 0; else id1 = atoi(cmd + 6); ctmp++; if (*ctmp >= '0' && *ctmp <= '9') id2 = atoi(ctmp); else id2 = (unsigned int) -1; bss = wpa_bss_get_id_range(wpa_s, id1, id2); if (id2 == (unsigned int) -1) bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id); else { bsslast = wpa_bss_get_id(wpa_s, id2); if (bsslast == NULL && bss && id2 > id1) { struct wpa_bss *tmp = bss; for (;;) { next = tmp->list_id.next; if (next == &wpa_s->bss_id) break; tmp = dl_list_entry( next, struct wpa_bss, list_id); if (tmp->id > id2) break; bsslast = tmp; } } } } } else if (os_strncmp(cmd, "FIRST", 5) == 0) bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id); else if (os_strncmp(cmd, "LAST", 4) == 0) bss = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id); else if (os_strncmp(cmd, "ID-", 3) == 0) { i = atoi(cmd + 3); bss = wpa_bss_get_id(wpa_s, i); } else if (os_strncmp(cmd, "NEXT-", 5) == 0) { i = atoi(cmd + 5); bss = wpa_bss_get_id(wpa_s, i); if (bss) { next = bss->list_id.next; if (next == &wpa_s->bss_id) bss = NULL; else bss = dl_list_entry(next, struct wpa_bss, list_id); } #ifdef CONFIG_P2P } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) { if (hwaddr_aton(cmd + 13, bssid) == 0) bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid); else bss = NULL; #endif /* CONFIG_P2P */ } else if (hwaddr_aton(cmd, bssid) == 0) bss = wpa_bss_get_bssid(wpa_s, bssid); else { struct wpa_bss *tmp; i = atoi(cmd); bss = NULL; dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id) { if (i-- == 0) { bss = tmp; break; } } } if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) { mask = strtoul(ctmp + 5, NULL, 0x10); if (mask == 0) mask = WPA_BSS_MASK_ALL; } if (bss == NULL) return 0; if (bsslast == NULL) bsslast = bss; do { len = print_bss_info(wpa_s, bss, mask, buf, buflen); ret += len; buf += len; buflen -= len; if (bss == bsslast) { if ((mask & WPA_BSS_MASK_DELIM) && len && (bss == dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id))) os_snprintf(buf - 5, 5, "####\n"); break; } next = bss->list_id.next; if (next == &wpa_s->bss_id) break; bss = dl_list_entry(next, struct wpa_bss, list_id); } while (bss && len); return ret; } static int wpa_supplicant_ctrl_iface_ap_scan( struct wpa_supplicant *wpa_s, char *cmd) { int ap_scan = atoi(cmd); return wpa_supplicant_set_ap_scan(wpa_s, ap_scan); } static int wpa_supplicant_ctrl_iface_scan_interval( struct wpa_supplicant *wpa_s, char *cmd) { int scan_int = atoi(cmd); return wpa_supplicant_set_scan_interval(wpa_s, scan_int); } static int wpa_supplicant_ctrl_iface_bss_expire_age( struct wpa_supplicant *wpa_s, char *cmd) { int expire_age = atoi(cmd); return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age); } static int wpa_supplicant_ctrl_iface_bss_expire_count( struct wpa_supplicant *wpa_s, char *cmd) { int expire_count = atoi(cmd); return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count); } static int wpa_supplicant_ctrl_iface_bss_flush( struct wpa_supplicant *wpa_s, char *cmd) { int flush_age = atoi(cmd); if (flush_age == 0) wpa_bss_flush(wpa_s); else wpa_bss_flush_by_age(wpa_s, flush_age); return 0; } #ifdef CONFIG_TESTING_OPTIONS static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s) { wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication"); /* MLME-DELETEKEYS.request */ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0); wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0); wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0); wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0); #ifdef CONFIG_IEEE80211W wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0); wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0); #endif /* CONFIG_IEEE80211W */ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL, 0); /* MLME-SETPROTECTION.request(None) */ wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid, MLME_SETPROTECTION_PROTECT_TYPE_NONE, MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); wpa_sm_drop_sa(wpa_s->wpa); } #endif /* CONFIG_TESTING_OPTIONS */ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s, char *addr) { #ifdef CONFIG_NO_SCAN_PROCESSING return -1; #else /* CONFIG_NO_SCAN_PROCESSING */ u8 bssid[ETH_ALEN]; struct wpa_bss *bss; struct wpa_ssid *ssid = wpa_s->current_ssid; if (hwaddr_aton(addr, bssid)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid " "address '%s'", addr); return -1; } wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid)); if (!ssid) { wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network " "configuration known for the target AP"); return -1; } bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len); if (!bss) { wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found " "from BSS table"); return -1; } /* * TODO: Find best network configuration block from configuration to * allow roaming to other networks */ wpa_s->reassociate = 1; wpa_supplicant_connect(wpa_s, bss, ssid); return 0; #endif /* CONFIG_NO_SCAN_PROCESSING */ } #ifdef CONFIG_P2P static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd) { unsigned int timeout = atoi(cmd); enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL; u8 dev_id[ETH_ALEN], *_dev_id = NULL; u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL; char *pos; unsigned int search_delay; if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_dbg(wpa_s, MSG_INFO, "Reject P2P_FIND since interface is disabled"); return -1; } if (os_strstr(cmd, "type=social")) type = P2P_FIND_ONLY_SOCIAL; else if (os_strstr(cmd, "type=progressive")) type = P2P_FIND_PROGRESSIVE; pos = os_strstr(cmd, "dev_id="); if (pos) { pos += 7; if (hwaddr_aton(pos, dev_id)) return -1; _dev_id = dev_id; } pos = os_strstr(cmd, "dev_type="); if (pos) { pos += 9; if (wps_dev_type_str2bin(pos, dev_type) < 0) return -1; _dev_type = dev_type; } pos = os_strstr(cmd, "delay="); if (pos) { pos += 6; search_delay = atoi(pos); } else search_delay = wpas_p2p_search_delay(wpa_s); return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type, _dev_id, search_delay); } static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { u8 addr[ETH_ALEN]; char *pos, *pos2; char *pin = NULL; enum p2p_wps_method wps_method; int new_pin; int ret; int persistent_group, persistent_id = -1; int join; int auth; int automatic; int go_intent = -1; int freq = 0; int pd; int ht40, vht; /* <"pbc" | "pin" | PIN> [label|display|keypad] * [persistent|persistent=] * [join] [auth] [go_intent=<0..15>] [freq=] [provdisc] * [ht40] [vht] */ if (hwaddr_aton(cmd, addr)) return -1; pos = cmd + 17; if (*pos != ' ') return -1; pos++; persistent_group = os_strstr(pos, " persistent") != NULL; pos2 = os_strstr(pos, " persistent="); if (pos2) { struct wpa_ssid *ssid; persistent_id = atoi(pos2 + 12); ssid = wpa_config_get_network(wpa_s->conf, persistent_id); if (ssid == NULL || ssid->disabled != 2 || ssid->mode != WPAS_MODE_P2P_GO) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find " "SSID id=%d for persistent P2P group (GO)", persistent_id); return -1; } } join = os_strstr(pos, " join") != NULL; auth = os_strstr(pos, " auth") != NULL; automatic = os_strstr(pos, " auto") != NULL; pd = os_strstr(pos, " provdisc") != NULL; vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht; ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 || vht; pos2 = os_strstr(pos, " go_intent="); if (pos2) { pos2 += 11; go_intent = atoi(pos2); if (go_intent < 0 || go_intent > 15) return -1; } pos2 = os_strstr(pos, " freq="); if (pos2) { pos2 += 6; freq = atoi(pos2); if (freq <= 0) return -1; } if (os_strncmp(pos, "pin", 3) == 0) { /* Request random PIN (to be displayed) and enable the PIN */ wps_method = WPS_PIN_DISPLAY; } else if (os_strncmp(pos, "pbc", 3) == 0) { wps_method = WPS_PBC; } else { pin = pos; pos = os_strchr(pin, ' '); wps_method = WPS_PIN_KEYPAD; if (pos) { *pos++ = '\0'; if (os_strncmp(pos, "display", 7) == 0) wps_method = WPS_PIN_DISPLAY; } if (!wps_pin_str_valid(pin)) { os_memcpy(buf, "FAIL-INVALID-PIN\n", 17); return 17; } } new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, persistent_group, automatic, join, auth, go_intent, freq, persistent_id, pd, ht40, vht); if (new_pin == -2) { os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25); return 25; } if (new_pin == -3) { os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25); return 25; } if (new_pin < 0) return -1; if (wps_method == WPS_PIN_DISPLAY && pin == NULL) { ret = os_snprintf(buf, buflen, "%08d", new_pin); if (ret < 0 || (size_t) ret >= buflen) return -1; return ret; } os_memcpy(buf, "OK\n", 3); return 3; } static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd) { unsigned int timeout = atoi(cmd); if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_dbg(wpa_s, MSG_INFO, "Reject P2P_LISTEN since interface is disabled"); return -1; } return wpas_p2p_listen(wpa_s, timeout); } static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd) { u8 addr[ETH_ALEN]; char *pos; enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG; /* [join|auto] */ if (hwaddr_aton(cmd, addr)) return -1; pos = cmd + 17; if (*pos != ' ') return -1; pos++; if (os_strstr(pos, " join") != NULL) use = WPAS_P2P_PD_FOR_JOIN; else if (os_strstr(pos, " auto") != NULL) use = WPAS_P2P_PD_AUTO; return wpas_p2p_prov_disc(wpa_s, addr, pos, use); } static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { struct wpa_ssid *ssid = wpa_s->current_ssid; if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO || ssid->passphrase == NULL) return -1; os_strlcpy(buf, ssid->passphrase, buflen); return os_strlen(buf); } static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { u64 ref; int res; u8 dst_buf[ETH_ALEN], *dst; struct wpabuf *tlvs; char *pos; size_t len; if (hwaddr_aton(cmd, dst_buf)) return -1; dst = dst_buf; if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 && dst[3] == 0 && dst[4] == 0 && dst[5] == 0) dst = NULL; pos = cmd + 17; if (*pos != ' ') return -1; pos++; if (os_strncmp(pos, "upnp ", 5) == 0) { u8 version; pos += 5; if (hexstr2bin(pos, &version, 1) < 0) return -1; pos += 2; if (*pos != ' ') return -1; pos++; ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos); #ifdef CONFIG_WIFI_DISPLAY } else if (os_strncmp(pos, "wifi-display ", 13) == 0) { ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13); #endif /* CONFIG_WIFI_DISPLAY */ } else { len = os_strlen(pos); if (len & 1) return -1; len /= 2; tlvs = wpabuf_alloc(len); if (tlvs == NULL) return -1; if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) { wpabuf_free(tlvs); return -1; } ref = wpas_p2p_sd_request(wpa_s, dst, tlvs); wpabuf_free(tlvs); } if (ref == 0) return -1; res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref); if (res < 0 || (unsigned) res >= buflen) return -1; return res; } static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s, char *cmd) { long long unsigned val; u64 req; if (sscanf(cmd, "%llx", &val) != 1) return -1; req = val; return wpas_p2p_sd_cancel_request(wpa_s, req); } static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd) { int freq; u8 dst[ETH_ALEN]; u8 dialog_token; struct wpabuf *resp_tlvs; char *pos, *pos2; size_t len; pos = os_strchr(cmd, ' '); if (pos == NULL) return -1; *pos++ = '\0'; freq = atoi(cmd); if (freq == 0) return -1; if (hwaddr_aton(pos, dst)) return -1; pos += 17; if (*pos != ' ') return -1; pos++; pos2 = os_strchr(pos, ' '); if (pos2 == NULL) return -1; *pos2++ = '\0'; dialog_token = atoi(pos); len = os_strlen(pos2); if (len & 1) return -1; len /= 2; resp_tlvs = wpabuf_alloc(len); if (resp_tlvs == NULL) return -1; if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) { wpabuf_free(resp_tlvs); return -1; } wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs); wpabuf_free(resp_tlvs); return 0; } static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s, char *cmd) { if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1")) return -1; wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd); return 0; } static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s, char *cmd) { char *pos; size_t len; struct wpabuf *query, *resp; pos = os_strchr(cmd, ' '); if (pos == NULL) return -1; *pos++ = '\0'; len = os_strlen(cmd); if (len & 1) return -1; len /= 2; query = wpabuf_alloc(len); if (query == NULL) return -1; if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) { wpabuf_free(query); return -1; } len = os_strlen(pos); if (len & 1) { wpabuf_free(query); return -1; } len /= 2; resp = wpabuf_alloc(len); if (resp == NULL) { wpabuf_free(query); return -1; } if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) { wpabuf_free(query); wpabuf_free(resp); return -1; } if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) { wpabuf_free(query); wpabuf_free(resp); return -1; } return 0; } static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd) { char *pos; u8 version; pos = os_strchr(cmd, ' '); if (pos == NULL) return -1; *pos++ = '\0'; if (hexstr2bin(cmd, &version, 1) < 0) return -1; return wpas_p2p_service_add_upnp(wpa_s, version, pos); } static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd) { char *pos; pos = os_strchr(cmd, ' '); if (pos == NULL) return -1; *pos++ = '\0'; if (os_strcmp(cmd, "bonjour") == 0) return p2p_ctrl_service_add_bonjour(wpa_s, pos); if (os_strcmp(cmd, "upnp") == 0) return p2p_ctrl_service_add_upnp(wpa_s, pos); wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd); return -1; } static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s, char *cmd) { size_t len; struct wpabuf *query; int ret; len = os_strlen(cmd); if (len & 1) return -1; len /= 2; query = wpabuf_alloc(len); if (query == NULL) return -1; if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) { wpabuf_free(query); return -1; } ret = wpas_p2p_service_del_bonjour(wpa_s, query); wpabuf_free(query); return ret; } static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd) { char *pos; u8 version; pos = os_strchr(cmd, ' '); if (pos == NULL) return -1; *pos++ = '\0'; if (hexstr2bin(cmd, &version, 1) < 0) return -1; return wpas_p2p_service_del_upnp(wpa_s, version, pos); } static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd) { char *pos; pos = os_strchr(cmd, ' '); if (pos == NULL) return -1; *pos++ = '\0'; if (os_strcmp(cmd, "bonjour") == 0) return p2p_ctrl_service_del_bonjour(wpa_s, pos); if (os_strcmp(cmd, "upnp") == 0) return p2p_ctrl_service_del_upnp(wpa_s, pos); wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd); return -1; } static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd) { u8 addr[ETH_ALEN]; /* */ if (hwaddr_aton(cmd, addr)) return -1; return wpas_p2p_reject(wpa_s, addr); } static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) { char *pos; int id; struct wpa_ssid *ssid; u8 *_peer = NULL, peer[ETH_ALEN]; int freq = 0, pref_freq = 0; int ht40, vht; id = atoi(cmd); pos = os_strstr(cmd, " peer="); if (pos) { pos += 6; if (hwaddr_aton(pos, peer)) return -1; _peer = peer; } ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL || ssid->disabled != 2) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " "for persistent P2P group", id); return -1; } pos = os_strstr(cmd, " freq="); if (pos) { pos += 6; freq = atoi(pos); if (freq <= 0) return -1; } pos = os_strstr(cmd, " pref="); if (pos) { pos += 6; pref_freq = atoi(pos); if (pref_freq <= 0) return -1; } vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht; ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 || vht; return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht, pref_freq); } static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd) { char *pos; u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL; pos = os_strstr(cmd, " peer="); if (!pos) return -1; *pos = '\0'; pos += 6; if (hwaddr_aton(pos, peer)) { wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos); return -1; } pos = os_strstr(pos, " go_dev_addr="); if (pos) { pos += 13; if (hwaddr_aton(pos, go_dev_addr)) { wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos); return -1; } go_dev = go_dev_addr; } return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev); } static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd) { if (os_strncmp(cmd, "persistent=", 11) == 0) return p2p_ctrl_invite_persistent(wpa_s, cmd + 11); if (os_strncmp(cmd, "group=", 6) == 0) return p2p_ctrl_invite_group(wpa_s, cmd + 6); return -1; } static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, char *cmd, int freq, int ht40, int vht) { int id; struct wpa_ssid *ssid; id = atoi(cmd); ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL || ssid->disabled != 2) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " "for persistent P2P group", id); return -1; } return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, ht40, vht, NULL, 0); } static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) { int freq = 0, ht40, vht; char *pos; pos = os_strstr(cmd, "freq="); if (pos) freq = atoi(pos + 5); vht = (os_strstr(cmd, "vht") != NULL) || wpa_s->conf->p2p_go_vht; ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40 || vht; if (os_strncmp(cmd, "persistent=", 11) == 0) return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq, ht40, vht); if (os_strcmp(cmd, "persistent") == 0 || os_strncmp(cmd, "persistent ", 11) == 0) return wpas_p2p_group_add(wpa_s, 1, freq, ht40, vht); if (os_strncmp(cmd, "freq=", 5) == 0) return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht); if (ht40) return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht); wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'", cmd); return -1; } static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { u8 addr[ETH_ALEN], *addr_ptr; int next, res; const struct p2p_peer_info *info; char *pos, *end; char devtype[WPS_DEV_TYPE_BUFSIZE]; struct wpa_ssid *ssid; size_t i; if (!wpa_s->global->p2p) return -1; if (os_strcmp(cmd, "FIRST") == 0) { addr_ptr = NULL; next = 0; } else if (os_strncmp(cmd, "NEXT-", 5) == 0) { if (hwaddr_aton(cmd + 5, addr) < 0) return -1; addr_ptr = addr; next = 1; } else { if (hwaddr_aton(cmd, addr) < 0) return -1; addr_ptr = addr; next = 0; } info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next); if (info == NULL) return -1; pos = buf; end = buf + buflen; res = os_snprintf(pos, end - pos, MACSTR "\n" "pri_dev_type=%s\n" "device_name=%s\n" "manufacturer=%s\n" "model_name=%s\n" "model_number=%s\n" "serial_number=%s\n" "config_methods=0x%x\n" "dev_capab=0x%x\n" "group_capab=0x%x\n" "level=%d\n", MAC2STR(info->p2p_device_addr), wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype)), info->device_name, info->manufacturer, info->model_name, info->model_number, info->serial_number, info->config_methods, info->dev_capab, info->group_capab, info->level); if (res < 0 || res >= end - pos) return pos - buf; pos += res; for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++) { const u8 *t; t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN]; res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n", wps_dev_type_bin2str(t, devtype, sizeof(devtype))); if (res < 0 || res >= end - pos) return pos - buf; pos += res; } ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0); if (ssid) { res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id); if (res < 0 || res >= end - pos) return pos - buf; pos += res; } res = p2p_get_peer_info_txt(info, pos, end - pos); if (res < 0) return pos - buf; pos += res; return pos - buf; } static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s, const char *param) { unsigned int i; if (wpa_s->global->p2p == NULL) return -1; if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0) return -1; for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) { struct wpa_freq_range *freq; freq = &wpa_s->global->p2p_disallow_freq.range[i]; wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u", freq->min, freq->max); } wpas_p2p_update_channel_list(wpa_s); return 0; } static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) { char *param; if (wpa_s->global->p2p == NULL) return -1; param = os_strchr(cmd, ' '); if (param == NULL) return -1; *param++ = '\0'; if (os_strcmp(cmd, "discoverability") == 0) { p2p_set_client_discoverability(wpa_s->global->p2p, atoi(param)); return 0; } if (os_strcmp(cmd, "managed") == 0) { p2p_set_managed_oper(wpa_s->global->p2p, atoi(param)); return 0; } if (os_strcmp(cmd, "listen_channel") == 0) { return p2p_set_listen_channel(wpa_s->global->p2p, 81, atoi(param)); } if (os_strcmp(cmd, "ssid_postfix") == 0) { return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param, os_strlen(param)); } if (os_strcmp(cmd, "noa") == 0) { char *pos; int count, start, duration; /* GO NoA parameters: count,start_offset(ms),duration(ms) */ count = atoi(param); pos = os_strchr(param, ','); if (pos == NULL) return -1; pos++; start = atoi(pos); pos = os_strchr(pos, ','); if (pos == NULL) return -1; pos++; duration = atoi(pos); if (count < 0 || count > 255 || start < 0 || duration < 0) return -1; if (count == 0 && duration > 0) return -1; wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d " "start=%d duration=%d", count, start, duration); return wpas_p2p_set_noa(wpa_s, count, start, duration); } if (os_strcmp(cmd, "ps") == 0) return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1); if (os_strcmp(cmd, "oppps") == 0) return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1); if (os_strcmp(cmd, "ctwindow") == 0) return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param)); if (os_strcmp(cmd, "disabled") == 0) { wpa_s->global->p2p_disabled = atoi(param); wpa_printf(MSG_DEBUG, "P2P functionality %s", wpa_s->global->p2p_disabled ? "disabled" : "enabled"); if (wpa_s->global->p2p_disabled) { wpas_p2p_stop_find(wpa_s); os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); p2p_flush(wpa_s->global->p2p); } return 0; } if (os_strcmp(cmd, "conc_pref") == 0) { if (os_strcmp(param, "sta") == 0) wpa_s->global->conc_pref = WPA_CONC_PREF_STA; else if (os_strcmp(param, "p2p") == 0) wpa_s->global->conc_pref = WPA_CONC_PREF_P2P; else { wpa_printf(MSG_INFO, "Invalid conc_pref value"); return -1; } wpa_printf(MSG_DEBUG, "Single channel concurrency preference: " "%s", param); return 0; } if (os_strcmp(cmd, "force_long_sd") == 0) { wpa_s->force_long_sd = atoi(param); return 0; } if (os_strcmp(cmd, "peer_filter") == 0) { u8 addr[ETH_ALEN]; if (hwaddr_aton(param, addr)) return -1; p2p_set_peer_filter(wpa_s->global->p2p, addr); return 0; } if (os_strcmp(cmd, "cross_connect") == 0) return wpas_p2p_set_cross_connect(wpa_s, atoi(param)); if (os_strcmp(cmd, "go_apsd") == 0) { if (os_strcmp(param, "disable") == 0) wpa_s->set_ap_uapsd = 0; else { wpa_s->set_ap_uapsd = 1; wpa_s->ap_uapsd = atoi(param); } return 0; } if (os_strcmp(cmd, "client_apsd") == 0) { if (os_strcmp(param, "disable") == 0) wpa_s->set_sta_uapsd = 0; else { int be, bk, vi, vo; char *pos; /* format: BE,BK,VI,VO;max SP Length */ be = atoi(param); pos = os_strchr(param, ','); if (pos == NULL) return -1; pos++; bk = atoi(pos); pos = os_strchr(pos, ','); if (pos == NULL) return -1; pos++; vi = atoi(pos); pos = os_strchr(pos, ','); if (pos == NULL) return -1; pos++; vo = atoi(pos); /* ignore max SP Length for now */ wpa_s->set_sta_uapsd = 1; wpa_s->sta_uapsd = 0; if (be) wpa_s->sta_uapsd |= BIT(0); if (bk) wpa_s->sta_uapsd |= BIT(1); if (vi) wpa_s->sta_uapsd |= BIT(2); if (vo) wpa_s->sta_uapsd |= BIT(3); } return 0; } if (os_strcmp(cmd, "disallow_freq") == 0) return p2p_ctrl_disallow_freq(wpa_s, param); if (os_strcmp(cmd, "disc_int") == 0) { int min_disc_int, max_disc_int, max_disc_tu; char *pos; pos = param; min_disc_int = atoi(pos); pos = os_strchr(pos, ' '); if (pos == NULL) return -1; *pos++ = '\0'; max_disc_int = atoi(pos); pos = os_strchr(pos, ' '); if (pos == NULL) return -1; *pos++ = '\0'; max_disc_tu = atoi(pos); return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int, max_disc_int, max_disc_tu); } if (os_strcmp(cmd, "per_sta_psk") == 0) { wpa_s->global->p2p_per_sta_psk = !!atoi(param); return 0; } #ifdef CONFIG_WPS_NFC if (os_strcmp(cmd, "nfc_tag") == 0) return wpas_p2p_nfc_tag_enabled(wpa_s, !!atoi(param)); #endif /* CONFIG_WPS_NFC */ if (os_strcmp(cmd, "disable_ip_addr_req") == 0) { wpa_s->p2p_disable_ip_addr_req = !!atoi(param); return 0; } wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'", cmd); return -1; } static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s) { os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); wpa_s->force_long_sd = 0; if (wpa_s->global->p2p) p2p_flush(wpa_s->global->p2p); } static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd) { char *pos, *pos2; unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0; if (cmd[0]) { pos = os_strchr(cmd, ' '); if (pos == NULL) return -1; *pos++ = '\0'; dur1 = atoi(cmd); pos2 = os_strchr(pos, ' '); if (pos2) *pos2++ = '\0'; int1 = atoi(pos); } else pos2 = NULL; if (pos2) { pos = os_strchr(pos2, ' '); if (pos == NULL) return -1; *pos++ = '\0'; dur2 = atoi(pos2); int2 = atoi(pos); } return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2); } static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd) { char *pos; unsigned int period = 0, interval = 0; if (cmd[0]) { pos = os_strchr(cmd, ' '); if (pos == NULL) return -1; *pos++ = '\0'; period = atoi(cmd); interval = atoi(pos); } return wpas_p2p_ext_listen(wpa_s, period, interval); } static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd) { const char *pos; u8 peer[ETH_ALEN]; int iface_addr = 0; pos = cmd; if (os_strncmp(pos, "iface=", 6) == 0) { iface_addr = 1; pos += 6; } if (hwaddr_aton(pos, peer)) return -1; wpas_p2p_remove_client(wpa_s, peer, iface_addr); return 0; } #endif /* CONFIG_P2P */ static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val) { struct wpa_freq_range_list ranges; int *freqs = NULL; struct hostapd_hw_modes *mode; u16 i; if (wpa_s->hw.modes == NULL) return NULL; os_memset(&ranges, 0, sizeof(ranges)); if (freq_range_list_parse(&ranges, val) < 0) return NULL; for (i = 0; i < wpa_s->hw.num_modes; i++) { int j; mode = &wpa_s->hw.modes[i]; for (j = 0; j < mode->num_channels; j++) { unsigned int freq; if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED) continue; freq = mode->channels[j].freq; if (!freq_range_list_includes(&ranges, freq)) continue; int_array_add_unique(&freqs, freq); } } os_free(ranges.range); return freqs; } #ifdef CONFIG_INTERWORKING static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param) { int auto_sel = 0; int *freqs = NULL; if (param) { char *pos; auto_sel = os_strstr(param, "auto") != NULL; pos = os_strstr(param, "freq="); if (pos) { freqs = freq_range_to_channel_list(wpa_s, pos + 5); if (freqs == NULL) return -1; } } return interworking_select(wpa_s, auto_sel, freqs); } static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst) { u8 bssid[ETH_ALEN]; struct wpa_bss *bss; if (hwaddr_aton(dst, bssid)) { wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst); return -1; } bss = wpa_bss_get_bssid(wpa_s, bssid); if (bss == NULL) { wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR, MAC2STR(bssid)); return -1; } return interworking_connect(wpa_s, bss); } static int get_anqp(struct wpa_supplicant *wpa_s, char *dst) { u8 dst_addr[ETH_ALEN]; int used; char *pos; #define MAX_ANQP_INFO_ID 100 u16 id[MAX_ANQP_INFO_ID]; size_t num_id = 0; u32 subtypes = 0; used = hwaddr_aton2(dst, dst_addr); if (used < 0) return -1; pos = dst + used; while (num_id < MAX_ANQP_INFO_ID) { if (os_strncmp(pos, "hs20:", 5) == 0) { #ifdef CONFIG_HS20 int num = atoi(pos + 5); if (num <= 0 || num > 31) return -1; subtypes |= BIT(num); #else /* CONFIG_HS20 */ return -1; #endif /* CONFIG_HS20 */ } else { id[num_id] = atoi(pos); if (id[num_id]) num_id++; } pos = os_strchr(pos + 1, ','); if (pos == NULL) break; pos++; } if (num_id == 0) return -1; return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes); } static int gas_request(struct wpa_supplicant *wpa_s, char *cmd) { u8 dst_addr[ETH_ALEN]; struct wpabuf *advproto, *query = NULL; int used, ret = -1; char *pos, *end; size_t len; used = hwaddr_aton2(cmd, dst_addr); if (used < 0) return -1; pos = cmd + used; while (*pos == ' ') pos++; /* Advertisement Protocol ID */ end = os_strchr(pos, ' '); if (end) len = end - pos; else len = os_strlen(pos); if (len & 0x01) return -1; len /= 2; if (len == 0) return -1; advproto = wpabuf_alloc(len); if (advproto == NULL) return -1; if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0) goto fail; if (end) { /* Optional Query Request */ pos = end + 1; while (*pos == ' ') pos++; len = os_strlen(pos); if (len) { if (len & 0x01) goto fail; len /= 2; if (len == 0) goto fail; query = wpabuf_alloc(len); if (query == NULL) goto fail; if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0) goto fail; } } ret = gas_send_request(wpa_s, dst_addr, advproto, query); fail: wpabuf_free(advproto); wpabuf_free(query); return ret; } static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { u8 addr[ETH_ALEN]; int dialog_token; int used; char *pos; size_t resp_len, start, requested_len; struct wpabuf *resp; int ret; used = hwaddr_aton2(cmd, addr); if (used < 0) return -1; pos = cmd + used; while (*pos == ' ') pos++; dialog_token = atoi(pos); if (wpa_s->last_gas_resp && os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 && dialog_token == wpa_s->last_gas_dialog_token) resp = wpa_s->last_gas_resp; else if (wpa_s->prev_gas_resp && os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 && dialog_token == wpa_s->prev_gas_dialog_token) resp = wpa_s->prev_gas_resp; else return -1; resp_len = wpabuf_len(resp); start = 0; requested_len = resp_len; pos = os_strchr(pos, ' '); if (pos) { start = atoi(pos); if (start > resp_len) return os_snprintf(buf, buflen, "FAIL-Invalid range"); pos = os_strchr(pos, ','); if (pos == NULL) return -1; pos++; requested_len = atoi(pos); if (start + requested_len > resp_len) return os_snprintf(buf, buflen, "FAIL-Invalid range"); } if (requested_len * 2 + 1 > buflen) return os_snprintf(buf, buflen, "FAIL-Too long response"); ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start, requested_len); if (start + requested_len == resp_len) { /* * Free memory by dropping the response after it has been * fetched. */ if (resp == wpa_s->prev_gas_resp) { wpabuf_free(wpa_s->prev_gas_resp); wpa_s->prev_gas_resp = NULL; } else { wpabuf_free(wpa_s->last_gas_resp); wpa_s->last_gas_resp = NULL; } } return ret; } #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst) { u8 dst_addr[ETH_ALEN]; int used; char *pos; u32 subtypes = 0; used = hwaddr_aton2(dst, dst_addr); if (used < 0) return -1; pos = dst + used; for (;;) { int num = atoi(pos); if (num <= 0 || num > 31) return -1; subtypes |= BIT(num); pos = os_strchr(pos + 1, ','); if (pos == NULL) break; pos++; } if (subtypes == 0) return -1; return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0); } static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s, const u8 *addr, const char *realm) { u8 *buf; size_t rlen, len; int ret; rlen = os_strlen(realm); len = 3 + rlen; buf = os_malloc(len); if (buf == NULL) return -1; buf[0] = 1; /* NAI Home Realm Count */ buf[1] = 0; /* Formatted in accordance with RFC 4282 */ buf[2] = rlen; os_memcpy(buf + 3, realm, rlen); ret = hs20_anqp_send_req(wpa_s, addr, BIT(HS20_STYPE_NAI_HOME_REALM_QUERY), buf, len); os_free(buf); return ret; } static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s, char *dst) { struct wpa_cred *cred = wpa_s->conf->cred; u8 dst_addr[ETH_ALEN]; int used; u8 *buf; size_t len; int ret; used = hwaddr_aton2(dst, dst_addr); if (used < 0) return -1; while (dst[used] == ' ') used++; if (os_strncmp(dst + used, "realm=", 6) == 0) return hs20_nai_home_realm_list(wpa_s, dst_addr, dst + used + 6); len = os_strlen(dst + used); if (len == 0 && cred && cred->realm) return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm); if (len % 1) return -1; len /= 2; buf = os_malloc(len); if (buf == NULL) return -1; if (hexstr2bin(dst + used, buf, len) < 0) { os_free(buf); return -1; } ret = hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_NAI_HOME_REALM_QUERY), buf, len); os_free(buf); return ret; } static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd) { u8 dst_addr[ETH_ALEN]; int used; char *icon; used = hwaddr_aton2(cmd, dst_addr); if (used < 0) return -1; while (cmd[used] == ' ') used++; icon = &cmd[used]; wpa_s->fetch_osu_icon_in_progress = 0; return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST), (u8 *) icon, os_strlen(icon)); } #endif /* CONFIG_HS20 */ static int wpa_supplicant_ctrl_iface_sta_autoconnect( struct wpa_supplicant *wpa_s, char *cmd) { wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0; return 0; } #ifdef CONFIG_AUTOSCAN static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s, char *cmd) { enum wpa_states state = wpa_s->wpa_state; char *new_params = NULL; if (os_strlen(cmd) > 0) { new_params = os_strdup(cmd); if (new_params == NULL) return -1; } os_free(wpa_s->conf->autoscan); wpa_s->conf->autoscan = new_params; if (wpa_s->conf->autoscan == NULL) autoscan_deinit(wpa_s); else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE) autoscan_init(wpa_s, 1); else if (state == WPA_SCANNING) wpa_supplicant_reinit_autoscan(wpa_s); return 0; } #endif /* CONFIG_AUTOSCAN */ #ifdef CONFIG_WNM static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd) { int enter; int intval = 0; char *pos; int ret; struct wpabuf *tfs_req = NULL; if (os_strncmp(cmd, "enter", 5) == 0) enter = 1; else if (os_strncmp(cmd, "exit", 4) == 0) enter = 0; else return -1; pos = os_strstr(cmd, " interval="); if (pos) intval = atoi(pos + 10); pos = os_strstr(cmd, " tfs_req="); if (pos) { char *end; size_t len; pos += 9; end = os_strchr(pos, ' '); if (end) len = end - pos; else len = os_strlen(pos); if (len & 1) return -1; len /= 2; tfs_req = wpabuf_alloc(len); if (tfs_req == NULL) return -1; if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) { wpabuf_free(tfs_req); return -1; } } ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER : WNM_SLEEP_MODE_EXIT, intval, tfs_req); wpabuf_free(tfs_req); return ret; } static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd) { int query_reason; query_reason = atoi(cmd); wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d", query_reason); return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason); } #endif /* CONFIG_WNM */ /* Get string representation of channel width */ static const char * channel_width_name(enum chan_width width) { switch (width) { case CHAN_WIDTH_20_NOHT: return "20 MHz (no HT)"; case CHAN_WIDTH_20: return "20 MHz"; case CHAN_WIDTH_40: return "40 MHz"; case CHAN_WIDTH_80: return "80 MHz"; case CHAN_WIDTH_80P80: return "80+80 MHz"; case CHAN_WIDTH_160: return "160 MHz"; default: return "unknown"; } } static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { struct wpa_signal_info si; int ret; char *pos, *end; ret = wpa_drv_signal_poll(wpa_s, &si); if (ret) return -1; pos = buf; end = buf + buflen; ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n" "NOISE=%d\nFREQUENCY=%u\n", si.current_signal, si.current_txrate / 1000, si.current_noise, si.frequency); if (ret < 0 || ret > end - pos) return -1; pos += ret; if (si.chanwidth != CHAN_WIDTH_UNKNOWN) { ret = os_snprintf(pos, end - pos, "WIDTH=%s\n", channel_width_name(si.chanwidth)); if (ret < 0 || ret > end - pos) return -1; pos += ret; } if (si.center_frq1 > 0 && si.center_frq2 > 0) { ret = os_snprintf(pos, end - pos, "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n", si.center_frq1, si.center_frq2); if (ret < 0 || ret > end - pos) return -1; pos += ret; } if (si.avg_signal) { ret = os_snprintf(pos, end - pos, "AVG_RSSI=%d\n", si.avg_signal); if (ret < 0 || ret >= end - pos) return -1; pos += ret; } return pos - buf; } static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { struct hostap_sta_driver_data sta; int ret; ret = wpa_drv_pktcnt_poll(wpa_s, &sta); if (ret) return -1; ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n", sta.tx_packets, sta.tx_retry_failed, sta.rx_packets); if (ret < 0 || (size_t) ret > buflen) return -1; return ret; } #ifdef ANDROID static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { int ret; ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen); if (ret == 0) { if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) { struct p2p_data *p2p = wpa_s->global->p2p; if (p2p) { char country[3]; country[0] = cmd[8]; country[1] = cmd[9]; country[2] = 0x04; p2p_set_country(p2p, country); } } ret = os_snprintf(buf, buflen, "%s\n", "OK"); } return ret; } #endif /* ANDROID */ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { int ret; char *pos; u8 *data = NULL; unsigned int vendor_id, subcmd; struct wpabuf *reply; size_t data_len = 0; /* cmd: [] */ vendor_id = strtoul(cmd, &pos, 16); if (!isblank(*pos)) return -EINVAL; subcmd = strtoul(pos, &pos, 10); if (*pos != '\0') { if (!isblank(*pos++)) return -EINVAL; data_len = os_strlen(pos); } if (data_len) { data_len /= 2; data = os_malloc(data_len); if (!data) return -1; if (hexstr2bin(pos, data, data_len)) { wpa_printf(MSG_DEBUG, "Vendor command: wrong parameter format"); os_free(data); return -EINVAL; } } reply = wpabuf_alloc((buflen - 1) / 2); if (!reply) { os_free(data); return -1; } ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len, reply); if (ret == 0) ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply), wpabuf_len(reply)); wpabuf_free(reply); os_free(data); return ret; } static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) { wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state"); #ifdef CONFIG_P2P wpas_p2p_cancel(wpa_s); wpas_p2p_stop_find(wpa_s); p2p_ctrl_flush(wpa_s); wpas_p2p_group_remove(wpa_s, "*"); wpas_p2p_service_flush(wpa_s); wpa_s->global->p2p_disabled = 0; wpa_s->global->p2p_per_sta_psk = 0; wpa_s->conf->num_sec_device_types = 0; wpa_s->p2p_disable_ip_addr_req = 0; os_free(wpa_s->global->p2p_go_avoid_freq.range); wpa_s->global->p2p_go_avoid_freq.range = NULL; #endif /* CONFIG_P2P */ #ifdef CONFIG_WPS_TESTING wps_version_number = 0x20; wps_testing_dummy_cred = 0; wps_corrupt_pkhash = 0; #endif /* CONFIG_WPS_TESTING */ #ifdef CONFIG_WPS wpa_s->wps_fragment_size = 0; wpas_wps_cancel(wpa_s); #endif /* CONFIG_WPS */ wpa_s->after_wps = 0; wpa_s->known_wps_freq = 0; #ifdef CONFIG_TDLS #ifdef CONFIG_TDLS_TESTING extern unsigned int tdls_testing; tdls_testing = 0; #endif /* CONFIG_TDLS_TESTING */ wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL); wpa_tdls_enable(wpa_s->wpa, 1); #endif /* CONFIG_TDLS */ eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL); wpa_supplicant_stop_countermeasures(wpa_s, NULL); wpa_s->no_keep_alive = 0; os_free(wpa_s->disallow_aps_bssid); wpa_s->disallow_aps_bssid = NULL; wpa_s->disallow_aps_bssid_count = 0; os_free(wpa_s->disallow_aps_ssid); wpa_s->disallow_aps_ssid = NULL; wpa_s->disallow_aps_ssid_count = 0; wpa_s->set_sta_uapsd = 0; wpa_s->sta_uapsd = 0; wpa_drv_radio_disable(wpa_s, 0); wpa_bss_flush(wpa_s); wpa_blacklist_clear(wpa_s); wpa_s->extra_blacklist_count = 0; wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all"); wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all"); wpa_config_flush_blobs(wpa_s->conf); wpa_s->conf->auto_interworking = 0; wpa_s->conf->okc = 0; wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200); wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70); wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60); eapol_sm_notify_logoff(wpa_s->eapol, FALSE); radio_remove_works(wpa_s, NULL, 1); wpa_s->next_ssid = NULL; #ifdef CONFIG_INTERWORKING hs20_cancel_fetch_osu(wpa_s); #endif /* CONFIG_INTERWORKING */ wpa_s->ext_mgmt_frame_handling = 0; } static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { struct wpa_radio_work *work; char *pos, *end; struct os_reltime now, diff; pos = buf; end = buf + buflen; os_get_reltime(&now); dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list) { int ret; os_reltime_sub(&now, &work->time, &diff); ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n", work->type, work->wpa_s->ifname, work->freq, work->started, diff.sec, diff.usec); if (ret < 0 || ret >= end - pos) break; pos += ret; } return pos - buf; } static void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_radio_work *work = eloop_ctx; struct wpa_external_work *ework = work->ctx; wpa_dbg(work->wpa_s, MSG_DEBUG, "Timing out external radio work %u (%s)", ework->id, work->type); wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id); radio_work_done(work); os_free(ework); } static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit) { struct wpa_external_work *ework = work->ctx; if (deinit) { if (work->started) eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL); os_free(ework); return; } wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)", ework->id, ework->type); wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id); if (!ework->timeout) ework->timeout = 10; eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout, work, NULL); } static int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { struct wpa_external_work *ework; char *pos, *pos2; size_t type_len; int ret; unsigned int freq = 0; /* format: [freq=] [timeout=] */ ework = os_zalloc(sizeof(*ework)); if (ework == NULL) return -1; pos = os_strchr(cmd, ' '); if (pos) { type_len = pos - cmd; pos++; pos2 = os_strstr(pos, "freq="); if (pos2) freq = atoi(pos2 + 5); pos2 = os_strstr(pos, "timeout="); if (pos2) ework->timeout = atoi(pos2 + 8); } else { type_len = os_strlen(cmd); } if (4 + type_len >= sizeof(ework->type)) type_len = sizeof(ework->type) - 4 - 1; os_strlcpy(ework->type, "ext:", sizeof(ework->type)); os_memcpy(ework->type + 4, cmd, type_len); ework->type[4 + type_len] = '\0'; wpa_s->ext_work_id++; if (wpa_s->ext_work_id == 0) wpa_s->ext_work_id++; ework->id = wpa_s->ext_work_id; if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb, ework) < 0) { os_free(ework); return -1; } ret = os_snprintf(buf, buflen, "%u", ework->id); if (ret < 0 || (size_t) ret >= buflen) return -1; return ret; } static int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd) { struct wpa_radio_work *work; unsigned int id = atoi(cmd); dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list) { struct wpa_external_work *ework; if (os_strncmp(work->type, "ext:", 4) != 0) continue; ework = work->ctx; if (id && ework->id != id) continue; wpa_dbg(wpa_s, MSG_DEBUG, "Completed external radio work %u (%s)", ework->id, ework->type); eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL); radio_work_done(work); os_free(ework); return 3; /* "OK\n" */ } return -1; } static int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { if (os_strcmp(cmd, "show") == 0) return wpas_ctrl_radio_work_show(wpa_s, buf, buflen); if (os_strncmp(cmd, "add ", 4) == 0) return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen); if (os_strncmp(cmd, "done ", 5) == 0) return wpas_ctrl_radio_work_done(wpa_s, cmd + 4); return -1; } void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s) { struct wpa_radio_work *work, *tmp; if (!wpa_s || !wpa_s->radio) return; dl_list_for_each_safe(work, tmp, &wpa_s->radio->work, struct wpa_radio_work, list) { struct wpa_external_work *ework; if (os_strncmp(work->type, "ext:", 4) != 0) continue; ework = work->ctx; wpa_dbg(wpa_s, MSG_DEBUG, "Flushing%s external radio work %u (%s)", work->started ? " started" : "", ework->id, ework->type); if (work->started) eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL); radio_work_done(work); os_free(ework); } } static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; eapol_sm_notify_ctrl_response(wpa_s->eapol); } static int set_scan_freqs(struct wpa_supplicant *wpa_s, char *val) { int *freqs = NULL; freqs = freq_range_to_channel_list(wpa_s, val); if (freqs == NULL) return -1; os_free(wpa_s->manual_scan_freqs); wpa_s->manual_scan_freqs = freqs; return 0; } static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, char *reply, int reply_size, int *reply_len) { char *pos; if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { *reply_len = -1; return; } wpa_s->manual_scan_passive = 0; wpa_s->manual_scan_use_id = 0; wpa_s->manual_scan_only_new = 0; if (params) { if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0) wpa_s->scan_res_handler = scan_only_handler; pos = os_strstr(params, "freq="); if (pos && set_scan_freqs(wpa_s, pos + 5) < 0) { *reply_len = -1; return; } pos = os_strstr(params, "passive="); if (pos) wpa_s->manual_scan_passive = !!atoi(pos + 8); pos = os_strstr(params, "use_id="); if (pos) wpa_s->manual_scan_use_id = atoi(pos + 7); pos = os_strstr(params, "only_new=1"); if (pos) wpa_s->manual_scan_only_new = 1; } else { os_free(wpa_s->manual_scan_freqs); wpa_s->manual_scan_freqs = NULL; if (wpa_s->scan_res_handler == scan_only_handler) wpa_s->scan_res_handler = NULL; } if (!wpa_s->sched_scanning && !wpa_s->scanning && ((wpa_s->wpa_state <= WPA_SCANNING) || (wpa_s->wpa_state == WPA_COMPLETED))) { wpa_s->normal_scans = 0; wpa_s->scan_req = MANUAL_SCAN_REQ; wpa_s->after_wps = 0; wpa_s->known_wps_freq = 0; wpa_supplicant_req_scan(wpa_s, 0, 0); if (wpa_s->manual_scan_use_id) { wpa_s->manual_scan_id++; wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u", wpa_s->manual_scan_id); *reply_len = os_snprintf(reply, reply_size, "%u\n", wpa_s->manual_scan_id); } } else if (wpa_s->sched_scanning) { wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed"); wpa_supplicant_cancel_sched_scan(wpa_s); wpa_s->scan_req = MANUAL_SCAN_REQ; wpa_supplicant_req_scan(wpa_s, 0, 0); if (wpa_s->manual_scan_use_id) { wpa_s->manual_scan_id++; *reply_len = os_snprintf(reply, reply_size, "%u\n", wpa_s->manual_scan_id); wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u", wpa_s->manual_scan_id); } } else { wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request"); *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n"); } } #ifdef CONFIG_TESTING_OPTIONS static void wpas_ctrl_iface_mgmt_tx_cb(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *data, size_t data_len, enum offchannel_send_action_result result) { wpa_msg(wpa_s, MSG_INFO, "MGMT-TX-STATUS freq=%u dst=" MACSTR " src=" MACSTR " bssid=" MACSTR " result=%s", freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" : (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "NO_ACK" : "FAILED")); } static int wpas_ctrl_iface_mgmt_tx(struct wpa_supplicant *wpa_s, char *cmd) { char *pos, *param; size_t len; u8 *buf, da[ETH_ALEN], bssid[ETH_ALEN]; int res, used; int freq = 0, no_cck = 0, wait_time = 0; /* [freq=] [wait_time=] [no_cck=1] * */ wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd); pos = cmd; used = hwaddr_aton2(pos, da); if (used < 0) return -1; pos += used; while (*pos == ' ') pos++; used = hwaddr_aton2(pos, bssid); if (used < 0) return -1; pos += used; param = os_strstr(pos, " freq="); if (param) { param += 6; freq = atoi(param); } param = os_strstr(pos, " no_cck="); if (param) { param += 8; no_cck = atoi(param); } param = os_strstr(pos, " wait_time="); if (param) { param += 11; wait_time = atoi(param); } param = os_strstr(pos, " action="); if (param == NULL) return -1; param += 8; len = os_strlen(param); if (len & 1) return -1; len /= 2; buf = os_malloc(len); if (buf == NULL) return -1; if (hexstr2bin(param, buf, len) < 0) { os_free(buf); return -1; } res = offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, bssid, buf, len, wait_time, wpas_ctrl_iface_mgmt_tx_cb, no_cck); os_free(buf); return res; } static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s) { wpa_printf(MSG_DEBUG, "External MGMT TX - done waiting"); offchannel_send_action_done(wpa_s); } static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd) { char *pos, *param; union wpa_event_data event; enum wpa_event_type ev; /* [parameters..] */ wpa_dbg(wpa_s, MSG_DEBUG, "Testing - external driver event: %s", cmd); pos = cmd; param = os_strchr(pos, ' '); if (param) *param++ = '\0'; os_memset(&event, 0, sizeof(event)); if (os_strcmp(cmd, "INTERFACE_ENABLED") == 0) { ev = EVENT_INTERFACE_ENABLED; } else if (os_strcmp(cmd, "INTERFACE_DISABLED") == 0) { ev = EVENT_INTERFACE_DISABLED; } else if (os_strcmp(cmd, "AVOID_FREQUENCIES") == 0) { ev = EVENT_AVOID_FREQUENCIES; if (param == NULL) param = ""; if (freq_range_list_parse(&event.freq_range, param) < 0) return -1; wpa_supplicant_event(wpa_s, ev, &event); os_free(event.freq_range.range); return 0; } else { wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s", cmd); return -1; } wpa_supplicant_event(wpa_s, ev, &event); return 0; } #endif /* CONFIG_TESTING_OPTIONS */ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char *buf, size_t *resp_len) { char *reply; const int reply_size = 4096; int reply_len; if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 || os_strncmp(buf, "SET_NETWORK ", 12) == 0) { if (wpa_debug_show_keys) wpa_dbg(wpa_s, MSG_DEBUG, "Control interface command '%s'", buf); else wpa_dbg(wpa_s, MSG_DEBUG, "Control interface command '%s [REMOVED]'", os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ? WPA_CTRL_RSP : "SET_NETWORK"); } else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 || os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0) { wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface", (const u8 *) buf, os_strlen(buf)); } else { int level = MSG_DEBUG; if (os_strcmp(buf, "PING") == 0) level = MSG_EXCESSIVE; wpa_dbg(wpa_s, level, "Control interface command '%s'", buf); } reply = os_malloc(reply_size); if (reply == NULL) { *resp_len = 1; return NULL; } os_memcpy(reply, "OK\n", 3); reply_len = 3; if (os_strcmp(buf, "PING") == 0) { os_memcpy(reply, "PONG\n", 5); reply_len = 5; } else if (os_strcmp(buf, "IFNAME") == 0) { reply_len = os_strlen(wpa_s->ifname); os_memcpy(reply, wpa_s->ifname, reply_len); } else if (os_strncmp(buf, "RELOG", 5) == 0) { if (wpa_debug_reopen_file() < 0) reply_len = -1; } else if (os_strncmp(buf, "NOTE ", 5) == 0) { wpa_printf(MSG_INFO, "NOTE: %s", buf + 5); } else if (os_strcmp(buf, "MIB") == 0) { reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size); if (reply_len >= 0) { int res; res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len, reply_size - reply_len); if (res < 0) reply_len = -1; else reply_len += res; } } else if (os_strncmp(buf, "STATUS", 6) == 0) { reply_len = wpa_supplicant_ctrl_iface_status( wpa_s, buf + 6, reply, reply_size); } else if (os_strcmp(buf, "PMKSA") == 0) { reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply, reply_size); } else if (os_strncmp(buf, "SET ", 4) == 0) { if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4)) reply_len = -1; } else if (os_strncmp(buf, "GET ", 4) == 0) { reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4, reply, reply_size); } else if (os_strcmp(buf, "LOGON") == 0) { eapol_sm_notify_logoff(wpa_s->eapol, FALSE); } else if (os_strcmp(buf, "LOGOFF") == 0) { eapol_sm_notify_logoff(wpa_s->eapol, TRUE); } else if (os_strcmp(buf, "REASSOCIATE") == 0) { if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) reply_len = -1; else wpas_request_connection(wpa_s); } else if (os_strcmp(buf, "REATTACH") == 0) { if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED || !wpa_s->current_ssid) reply_len = -1; else { wpa_s->reattach = 1; wpas_request_connection(wpa_s); } } else if (os_strcmp(buf, "RECONNECT") == 0) { if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) reply_len = -1; else if (wpa_s->disconnected) wpas_request_connection(wpa_s); #ifdef IEEE8021X_EAPOL } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) { if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8)) reply_len = -1; #endif /* IEEE8021X_EAPOL */ #ifdef CONFIG_PEERKEY } else if (os_strncmp(buf, "STKSTART ", 9) == 0) { if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9)) reply_len = -1; #endif /* CONFIG_PEERKEY */ #ifdef CONFIG_IEEE80211R } else if (os_strncmp(buf, "FT_DS ", 6) == 0) { if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6)) reply_len = -1; #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_WPS } else if (os_strcmp(buf, "WPS_PBC") == 0) { int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL); if (res == -2) { os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17); reply_len = 17; } else if (res) reply_len = -1; } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) { int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8); if (res == -2) { os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17); reply_len = 17; } else if (res) reply_len = -1; } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) { reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8, reply, reply_size); } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) { reply_len = wpa_supplicant_ctrl_iface_wps_check_pin( wpa_s, buf + 14, reply, reply_size); } else if (os_strcmp(buf, "WPS_CANCEL") == 0) { if (wpas_wps_cancel(wpa_s)) reply_len = -1; #ifdef CONFIG_WPS_NFC } else if (os_strcmp(buf, "WPS_NFC") == 0) { if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL)) reply_len = -1; } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) { if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8)) reply_len = -1; } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) { reply_len = wpa_supplicant_ctrl_iface_wps_nfc_config_token( wpa_s, buf + 21, reply, reply_size); } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) { reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token( wpa_s, buf + 14, reply, reply_size); } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) { if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s, buf + 17)) reply_len = -1; } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) { reply_len = wpas_ctrl_nfc_get_handover_req( wpa_s, buf + 21, reply, reply_size); } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) { reply_len = wpas_ctrl_nfc_get_handover_sel( wpa_s, buf + 21, reply, reply_size); } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) { if (wpas_ctrl_nfc_report_handover(wpa_s, buf + 20)) reply_len = -1; #endif /* CONFIG_WPS_NFC */ } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) { if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8)) reply_len = -1; #ifdef CONFIG_AP } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) { reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin( wpa_s, buf + 11, reply, reply_size); #endif /* CONFIG_AP */ #ifdef CONFIG_WPS_ER } else if (os_strcmp(buf, "WPS_ER_START") == 0) { if (wpas_wps_er_start(wpa_s, NULL)) reply_len = -1; } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) { if (wpas_wps_er_start(wpa_s, buf + 13)) reply_len = -1; } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) { if (wpas_wps_er_stop(wpa_s)) reply_len = -1; } else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) { if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11)) reply_len = -1; } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) { int ret = wpas_wps_er_pbc(wpa_s, buf + 11); if (ret == -2) { os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17); reply_len = 17; } else if (ret == -3) { os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18); reply_len = 18; } else if (ret == -4) { os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20); reply_len = 20; } else if (ret) reply_len = -1; } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) { if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13)) reply_len = -1; } else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) { if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s, buf + 18)) reply_len = -1; } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) { if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14)) reply_len = -1; #ifdef CONFIG_WPS_NFC } else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) { reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token( wpa_s, buf + 24, reply, reply_size); #endif /* CONFIG_WPS_NFC */ #endif /* CONFIG_WPS_ER */ #endif /* CONFIG_WPS */ #ifdef CONFIG_IBSS_RSN } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) { if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9)) reply_len = -1; #endif /* CONFIG_IBSS_RSN */ #ifdef CONFIG_P2P } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) { if (p2p_ctrl_find(wpa_s, buf + 9)) reply_len = -1; } else if (os_strcmp(buf, "P2P_FIND") == 0) { if (p2p_ctrl_find(wpa_s, "")) reply_len = -1; } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) { wpas_p2p_stop_find(wpa_s); } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) { reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply, reply_size); } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) { if (p2p_ctrl_listen(wpa_s, buf + 11)) reply_len = -1; } else if (os_strcmp(buf, "P2P_LISTEN") == 0) { if (p2p_ctrl_listen(wpa_s, "")) reply_len = -1; } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) { if (wpas_p2p_group_remove(wpa_s, buf + 17)) reply_len = -1; } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) { if (wpas_p2p_group_add(wpa_s, 0, 0, 0, 0)) reply_len = -1; } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) { if (p2p_ctrl_group_add(wpa_s, buf + 14)) reply_len = -1; } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) { if (p2p_ctrl_prov_disc(wpa_s, buf + 14)) reply_len = -1; } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) { reply_len = p2p_get_passphrase(wpa_s, reply, reply_size); } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) { reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply, reply_size); } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) { if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0) reply_len = -1; } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) { if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0) reply_len = -1; } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) { wpas_p2p_sd_service_update(wpa_s); } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) { if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0) reply_len = -1; } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) { wpas_p2p_service_flush(wpa_s); } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) { if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0) reply_len = -1; } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) { if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0) reply_len = -1; } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) { if (p2p_ctrl_reject(wpa_s, buf + 11) < 0) reply_len = -1; } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) { if (p2p_ctrl_invite(wpa_s, buf + 11) < 0) reply_len = -1; } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) { reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply, reply_size); } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) { if (p2p_ctrl_set(wpa_s, buf + 8) < 0) reply_len = -1; } else if (os_strcmp(buf, "P2P_FLUSH") == 0) { p2p_ctrl_flush(wpa_s); } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) { if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0) reply_len = -1; } else if (os_strcmp(buf, "P2P_CANCEL") == 0) { if (wpas_p2p_cancel(wpa_s)) reply_len = -1; } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) { if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0) reply_len = -1; } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) { if (p2p_ctrl_presence_req(wpa_s, "") < 0) reply_len = -1; } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) { if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0) reply_len = -1; } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) { if (p2p_ctrl_ext_listen(wpa_s, "") < 0) reply_len = -1; } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) { if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0) reply_len = -1; #endif /* CONFIG_P2P */ #ifdef CONFIG_WIFI_DISPLAY } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) { if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0) reply_len = -1; } else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) { reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16, reply, reply_size); #endif /* CONFIG_WIFI_DISPLAY */ #ifdef CONFIG_INTERWORKING } else if (os_strcmp(buf, "FETCH_ANQP") == 0) { if (interworking_fetch_anqp(wpa_s) < 0) reply_len = -1; } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) { interworking_stop_fetch_anqp(wpa_s); } else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) { if (ctrl_interworking_select(wpa_s, NULL) < 0) reply_len = -1; } else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) { if (ctrl_interworking_select(wpa_s, buf + 20) < 0) reply_len = -1; } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) { if (ctrl_interworking_connect(wpa_s, buf + 21) < 0) reply_len = -1; } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) { if (get_anqp(wpa_s, buf + 9) < 0) reply_len = -1; } else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) { if (gas_request(wpa_s, buf + 12) < 0) reply_len = -1; } else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) { reply_len = gas_response_get(wpa_s, buf + 17, reply, reply_size); #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) { if (get_hs20_anqp(wpa_s, buf + 14) < 0) reply_len = -1; } else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) { if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0) reply_len = -1; } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) { if (hs20_icon_request(wpa_s, buf + 18) < 0) reply_len = -1; } else if (os_strcmp(buf, "FETCH_OSU") == 0) { if (hs20_fetch_osu(wpa_s) < 0) reply_len = -1; } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) { hs20_cancel_fetch_osu(wpa_s); #endif /* CONFIG_HS20 */ } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0) { if (wpa_supplicant_ctrl_iface_ctrl_rsp( wpa_s, buf + os_strlen(WPA_CTRL_RSP))) reply_len = -1; else { /* * Notify response from timeout to allow the control * interface response to be sent first. */ eloop_register_timeout(0, 0, wpas_ctrl_eapol_response, wpa_s, NULL); } } else if (os_strcmp(buf, "RECONFIGURE") == 0) { if (wpa_supplicant_reload_configuration(wpa_s)) reply_len = -1; } else if (os_strcmp(buf, "TERMINATE") == 0) { wpa_supplicant_terminate_proc(wpa_s->global); } else if (os_strncmp(buf, "BSSID ", 6) == 0) { if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6)) reply_len = -1; } else if (os_strncmp(buf, "BLACKLIST", 9) == 0) { reply_len = wpa_supplicant_ctrl_iface_blacklist( wpa_s, buf + 9, reply, reply_size); } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) { reply_len = wpa_supplicant_ctrl_iface_log_level( wpa_s, buf + 9, reply, reply_size); } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) { reply_len = wpa_supplicant_ctrl_iface_list_networks( wpa_s, reply, reply_size); } else if (os_strcmp(buf, "DISCONNECT") == 0) { #ifdef CONFIG_SME wpa_s->sme.prev_bssid_set = 0; #endif /* CONFIG_SME */ wpa_s->reassociate = 0; wpa_s->disconnected = 1; wpa_supplicant_cancel_sched_scan(wpa_s); wpa_supplicant_cancel_scan(wpa_s); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); } else if (os_strcmp(buf, "SCAN") == 0) { wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len); } else if (os_strncmp(buf, "SCAN ", 5) == 0) { wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len); } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) { reply_len = wpa_supplicant_ctrl_iface_scan_results( wpa_s, reply, reply_size); } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) { if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15)) reply_len = -1; } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) { if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15)) reply_len = -1; } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) { if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16)) reply_len = -1; } else if (os_strcmp(buf, "ADD_NETWORK") == 0) { reply_len = wpa_supplicant_ctrl_iface_add_network( wpa_s, reply, reply_size); } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) { if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15)) reply_len = -1; } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) { if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12)) reply_len = -1; } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) { reply_len = wpa_supplicant_ctrl_iface_get_network( wpa_s, buf + 12, reply, reply_size); } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) { if (wpa_supplicant_ctrl_iface_dup_network(wpa_s, buf + 12)) reply_len = -1; } else if (os_strcmp(buf, "LIST_CREDS") == 0) { reply_len = wpa_supplicant_ctrl_iface_list_creds( wpa_s, reply, reply_size); } else if (os_strcmp(buf, "ADD_CRED") == 0) { reply_len = wpa_supplicant_ctrl_iface_add_cred( wpa_s, reply, reply_size); } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) { if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12)) reply_len = -1; } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) { if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9)) reply_len = -1; } else if (os_strncmp(buf, "GET_CRED ", 9) == 0) { reply_len = wpa_supplicant_ctrl_iface_get_cred(wpa_s, buf + 9, reply, reply_size); #ifndef CONFIG_NO_CONFIG_WRITE } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) { if (wpa_supplicant_ctrl_iface_save_config(wpa_s)) reply_len = -1; #endif /* CONFIG_NO_CONFIG_WRITE */ } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) { reply_len = wpa_supplicant_ctrl_iface_get_capability( wpa_s, buf + 15, reply, reply_size); } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) { if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8)) reply_len = -1; } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) { if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14)) reply_len = -1; } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { reply_len = wpa_supplicant_global_iface_list( wpa_s->global, reply, reply_size); } else if (os_strcmp(buf, "INTERFACES") == 0) { reply_len = wpa_supplicant_global_iface_interfaces( wpa_s->global, reply, reply_size); } else if (os_strncmp(buf, "BSS ", 4) == 0) { reply_len = wpa_supplicant_ctrl_iface_bss( wpa_s, buf + 4, reply, reply_size); #ifdef CONFIG_AP } else if (os_strcmp(buf, "STA-FIRST") == 0) { reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size); } else if (os_strncmp(buf, "STA ", 4) == 0) { reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply, reply_size); } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply, reply_size); } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) { if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15)) reply_len = -1; } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) { if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13)) reply_len = -1; } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12)) reply_len = -1; #endif /* CONFIG_AP */ } else if (os_strcmp(buf, "SUSPEND") == 0) { wpas_notify_suspend(wpa_s->global); } else if (os_strcmp(buf, "RESUME") == 0) { wpas_notify_resume(wpa_s->global); #ifdef CONFIG_TESTING_OPTIONS } else if (os_strcmp(buf, "DROP_SA") == 0) { wpa_supplicant_ctrl_iface_drop_sa(wpa_s); #endif /* CONFIG_TESTING_OPTIONS */ } else if (os_strncmp(buf, "ROAM ", 5) == 0) { if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5)) reply_len = -1; } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) { if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16)) reply_len = -1; } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) { if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15)) reply_len = -1; } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) { if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s, buf + 17)) reply_len = -1; } else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) { if (wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10)) reply_len = -1; #ifdef CONFIG_TDLS } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) { if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14)) reply_len = -1; } else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) { if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11)) reply_len = -1; } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) { if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14)) reply_len = -1; #endif /* CONFIG_TDLS */ } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) { reply_len = wpa_supplicant_signal_poll(wpa_s, reply, reply_size); } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) { reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply, reply_size); #ifdef CONFIG_AUTOSCAN } else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) { if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9)) reply_len = -1; #endif /* CONFIG_AUTOSCAN */ #ifdef ANDROID } else if (os_strncmp(buf, "DRIVER ", 7) == 0) { reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply, reply_size); #endif /* ANDROID */ } else if (os_strncmp(buf, "VENDOR ", 7) == 0) { reply_len = wpa_supplicant_vendor_cmd(wpa_s, buf + 7, reply, reply_size); } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) { pmksa_cache_clear_current(wpa_s->wpa); eapol_sm_request_reauth(wpa_s->eapol); #ifdef CONFIG_WNM } else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) { if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10)) reply_len = -1; } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 10) == 0) { if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 10)) reply_len = -1; #endif /* CONFIG_WNM */ } else if (os_strcmp(buf, "FLUSH") == 0) { wpa_supplicant_ctrl_iface_flush(wpa_s); } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) { reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply, reply_size); #ifdef CONFIG_TESTING_OPTIONS } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) { if (wpas_ctrl_iface_mgmt_tx(wpa_s, buf + 8) < 0) reply_len = -1; } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) { wpas_ctrl_iface_mgmt_tx_done(wpa_s); } else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) { if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0) reply_len = -1; #endif /* CONFIG_TESTING_OPTIONS */ } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; } if (reply_len < 0) { os_memcpy(reply, "FAIL\n", 5); reply_len = 5; } *resp_len = reply_len; return reply; } static int wpa_supplicant_global_iface_add(struct wpa_global *global, char *cmd) { struct wpa_interface iface; char *pos; /* * TABTABTABTAB * TAB */ wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd); os_memset(&iface, 0, sizeof(iface)); do { iface.ifname = pos = cmd; pos = os_strchr(pos, '\t'); if (pos) *pos++ = '\0'; if (iface.ifname[0] == '\0') return -1; if (pos == NULL) break; iface.confname = pos; pos = os_strchr(pos, '\t'); if (pos) *pos++ = '\0'; if (iface.confname[0] == '\0') iface.confname = NULL; if (pos == NULL) break; iface.driver = pos; pos = os_strchr(pos, '\t'); if (pos) *pos++ = '\0'; if (iface.driver[0] == '\0') iface.driver = NULL; if (pos == NULL) break; iface.ctrl_interface = pos; pos = os_strchr(pos, '\t'); if (pos) *pos++ = '\0'; if (iface.ctrl_interface[0] == '\0') iface.ctrl_interface = NULL; if (pos == NULL) break; iface.driver_param = pos; pos = os_strchr(pos, '\t'); if (pos) *pos++ = '\0'; if (iface.driver_param[0] == '\0') iface.driver_param = NULL; if (pos == NULL) break; iface.bridge_ifname = pos; pos = os_strchr(pos, '\t'); if (pos) *pos++ = '\0'; if (iface.bridge_ifname[0] == '\0') iface.bridge_ifname = NULL; if (pos == NULL) break; } while (0); if (wpa_supplicant_get_iface(global, iface.ifname)) return -1; return wpa_supplicant_add_iface(global, &iface) ? 0 : -1; } static int wpa_supplicant_global_iface_remove(struct wpa_global *global, char *cmd) { struct wpa_supplicant *wpa_s; wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd); wpa_s = wpa_supplicant_get_iface(global, cmd); if (wpa_s == NULL) return -1; return wpa_supplicant_remove_iface(global, wpa_s, 0); } static void wpa_free_iface_info(struct wpa_interface_info *iface) { struct wpa_interface_info *prev; while (iface) { prev = iface; iface = iface->next; os_free(prev->ifname); os_free(prev->desc); os_free(prev); } } static int wpa_supplicant_global_iface_list(struct wpa_global *global, char *buf, int len) { int i, res; struct wpa_interface_info *iface = NULL, *last = NULL, *tmp; char *pos, *end; for (i = 0; wpa_drivers[i]; i++) { struct wpa_driver_ops *drv = wpa_drivers[i]; if (drv->get_interfaces == NULL) continue; tmp = drv->get_interfaces(global->drv_priv[i]); if (tmp == NULL) continue; if (last == NULL) iface = last = tmp; else last->next = tmp; while (last->next) last = last->next; } pos = buf; end = buf + len; for (tmp = iface; tmp; tmp = tmp->next) { res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n", tmp->drv_name, tmp->ifname, tmp->desc ? tmp->desc : ""); if (res < 0 || res >= end - pos) { *pos = '\0'; break; } pos += res; } wpa_free_iface_info(iface); return pos - buf; } static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, char *buf, int len) { int res; char *pos, *end; struct wpa_supplicant *wpa_s; wpa_s = global->ifaces; pos = buf; end = buf + len; while (wpa_s) { res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname); if (res < 0 || res >= end - pos) { *pos = '\0'; break; } pos += res; wpa_s = wpa_s->next; } return pos - buf; } static char * wpas_global_ctrl_iface_ifname(struct wpa_global *global, const char *ifname, char *cmd, size_t *resp_len) { struct wpa_supplicant *wpa_s; for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { if (os_strcmp(ifname, wpa_s->ifname) == 0) break; } if (wpa_s == NULL) { char *resp = os_strdup("FAIL-NO-IFNAME-MATCH\n"); if (resp) *resp_len = os_strlen(resp); else *resp_len = 1; return resp; } return wpa_supplicant_ctrl_iface_process(wpa_s, cmd, resp_len); } static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global, char *buf, size_t *resp_len) { #ifdef CONFIG_P2P static const char * cmd[] = { "LIST_NETWORKS", "P2P_FIND", "P2P_STOP_FIND", "P2P_LISTEN", "P2P_GROUP_ADD", "P2P_GET_PASSPHRASE", "P2P_SERVICE_UPDATE", "P2P_SERVICE_FLUSH", "P2P_FLUSH", "P2P_CANCEL", "P2P_PRESENCE_REQ", "P2P_EXT_LISTEN", NULL }; static const char * prefix[] = { #ifdef ANDROID "DRIVER ", #endif /* ANDROID */ "GET_NETWORK ", "REMOVE_NETWORK ", "P2P_FIND ", "P2P_CONNECT ", "P2P_LISTEN ", "P2P_GROUP_REMOVE ", "P2P_GROUP_ADD ", "P2P_PROV_DISC ", "P2P_SERV_DISC_REQ ", "P2P_SERV_DISC_CANCEL_REQ ", "P2P_SERV_DISC_RESP ", "P2P_SERV_DISC_EXTERNAL ", "P2P_SERVICE_ADD ", "P2P_SERVICE_DEL ", "P2P_REJECT ", "P2P_INVITE ", "P2P_PEER ", "P2P_SET ", "P2P_UNAUTHORIZE ", "P2P_PRESENCE_REQ ", "P2P_EXT_LISTEN ", "P2P_REMOVE_CLIENT ", "NFC_GET_HANDOVER_SEL ", "NFC_GET_HANDOVER_REQ ", "NFC_REPORT_HANDOVER ", NULL }; int found = 0; int i; if (global->p2p_init_wpa_s == NULL) return NULL; for (i = 0; !found && cmd[i]; i++) { if (os_strcmp(buf, cmd[i]) == 0) found = 1; } for (i = 0; !found && prefix[i]; i++) { if (os_strncmp(buf, prefix[i], os_strlen(prefix[i])) == 0) found = 1; } if (found) return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s, buf, resp_len); #endif /* CONFIG_P2P */ return NULL; } static char * wpas_global_ctrl_iface_redir_wfd(struct wpa_global *global, char *buf, size_t *resp_len) { #ifdef CONFIG_WIFI_DISPLAY if (global->p2p_init_wpa_s == NULL) return NULL; if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0 || os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s, buf, resp_len); #endif /* CONFIG_WIFI_DISPLAY */ return NULL; } static char * wpas_global_ctrl_iface_redir(struct wpa_global *global, char *buf, size_t *resp_len) { char *ret; ret = wpas_global_ctrl_iface_redir_p2p(global, buf, resp_len); if (ret) return ret; ret = wpas_global_ctrl_iface_redir_wfd(global, buf, resp_len); if (ret) return ret; return NULL; } static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd) { char *value; value = os_strchr(cmd, ' '); if (value == NULL) return -1; *value++ = '\0'; wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value); #ifdef CONFIG_WIFI_DISPLAY if (os_strcasecmp(cmd, "wifi_display") == 0) { wifi_display_enable(global, !!atoi(value)); return 0; } #endif /* CONFIG_WIFI_DISPLAY */ /* Restore cmd to its original value to allow redirection */ value[-1] = ' '; return -1; } #ifndef CONFIG_NO_CONFIG_WRITE static int wpas_global_ctrl_iface_save_config(struct wpa_global *global) { int ret = 0, saved = 0; struct wpa_supplicant *wpa_s; for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { if (!wpa_s->conf->update_config) { wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)"); continue; } if (wpa_config_write(wpa_s->confname, wpa_s->conf)) { wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration"); ret = 1; } else { wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated"); saved++; } } if (!saved && !ret) { wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - No configuration files could be updated"); ret = 1; } return ret; } #endif /* CONFIG_NO_CONFIG_WRITE */ static int wpas_global_ctrl_iface_status(struct wpa_global *global, char *buf, size_t buflen) { char *pos, *end; int ret; struct wpa_supplicant *wpa_s; pos = buf; end = buf + buflen; #ifdef CONFIG_P2P if (global->p2p && !global->p2p_disabled) { ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR "\n" "p2p_state=%s\n", MAC2STR(global->p2p_dev_addr), p2p_get_state_txt(global->p2p)); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } else if (global->p2p) { ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } #endif /* CONFIG_P2P */ #ifdef CONFIG_WIFI_DISPLAY ret = os_snprintf(pos, end - pos, "wifi_display=%d\n", !!global->wifi_display); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; #endif /* CONFIG_WIFI_DISPLAY */ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { ret = os_snprintf(pos, end - pos, "ifname=%s\n" "address=" MACSTR "\n", wpa_s->ifname, MAC2STR(wpa_s->own_addr)); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } return pos - buf; } char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, char *buf, size_t *resp_len) { char *reply; const int reply_size = 2048; int reply_len; int level = MSG_DEBUG; if (os_strncmp(buf, "IFNAME=", 7) == 0) { char *pos = os_strchr(buf + 7, ' '); if (pos) { *pos++ = '\0'; return wpas_global_ctrl_iface_ifname(global, buf + 7, pos, resp_len); } } reply = wpas_global_ctrl_iface_redir(global, buf, resp_len); if (reply) return reply; if (os_strcmp(buf, "PING") == 0) level = MSG_EXCESSIVE; wpa_hexdump_ascii(level, "RX global ctrl_iface", (const u8 *) buf, os_strlen(buf)); reply = os_malloc(reply_size); if (reply == NULL) { *resp_len = 1; return NULL; } os_memcpy(reply, "OK\n", 3); reply_len = 3; if (os_strcmp(buf, "PING") == 0) { os_memcpy(reply, "PONG\n", 5); reply_len = 5; } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) { if (wpa_supplicant_global_iface_add(global, buf + 14)) reply_len = -1; } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) { if (wpa_supplicant_global_iface_remove(global, buf + 17)) reply_len = -1; } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { reply_len = wpa_supplicant_global_iface_list( global, reply, reply_size); } else if (os_strcmp(buf, "INTERFACES") == 0) { reply_len = wpa_supplicant_global_iface_interfaces( global, reply, reply_size); } else if (os_strcmp(buf, "TERMINATE") == 0) { wpa_supplicant_terminate_proc(global); } else if (os_strcmp(buf, "SUSPEND") == 0) { wpas_notify_suspend(global); } else if (os_strcmp(buf, "RESUME") == 0) { wpas_notify_resume(global); } else if (os_strncmp(buf, "SET ", 4) == 0) { if (wpas_global_ctrl_iface_set(global, buf + 4)) { #ifdef CONFIG_P2P if (global->p2p_init_wpa_s) { os_free(reply); /* Check if P2P redirection would work for this * command. */ return wpa_supplicant_ctrl_iface_process( global->p2p_init_wpa_s, buf, resp_len); } #endif /* CONFIG_P2P */ reply_len = -1; } #ifndef CONFIG_NO_CONFIG_WRITE } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) { if (wpas_global_ctrl_iface_save_config(global)) reply_len = -1; #endif /* CONFIG_NO_CONFIG_WRITE */ } else if (os_strcmp(buf, "STATUS") == 0) { reply_len = wpas_global_ctrl_iface_status(global, reply, reply_size); #ifdef CONFIG_MODULE_TESTS } else if (os_strcmp(buf, "MODULE_TESTS") == 0) { int wpas_module_tests(void); if (wpas_module_tests() < 0) reply_len = -1; #endif /* CONFIG_MODULE_TESTS */ } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; } if (reply_len < 0) { os_memcpy(reply, "FAIL\n", 5); reply_len = 5; } *resp_len = reply_len; return reply; } wpa_supplicant-2.2/wpa_supplicant/ap.h0000664000175000017500000000650012343617166016022 0ustar jmjm/* * WPA Supplicant - Basic AP mode support routines * Copyright (c) 2003-2009, Jouni Malinen * Copyright (c) 2009, Atheros Communications * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef AP_H #define AP_H int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s); void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s, const u8 *src_addr, const u8 *buf, size_t len); int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, const u8 *p2p_dev_addr); int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, const char *pin, char *buf, size_t buflen, int timeout); int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s); void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s); const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout); const char * wpas_wps_ap_pin_get(struct wpa_supplicant *wpa_s); int wpas_wps_ap_pin_set(struct wpa_supplicant *wpa_s, const char *pin, int timeout); int ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s, char *buf, size_t buflen); int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr, char *buf, size_t buflen); int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr, char *buf, size_t buflen); int ap_ctrl_iface_sta_deauthenticate(struct wpa_supplicant *wpa_s, const char *txtaddr); int ap_ctrl_iface_sta_disassociate(struct wpa_supplicant *wpa_s, const char *txtaddr); int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen, int verbose); void ap_tx_status(void *ctx, const u8 *addr, const u8 *buf, size_t len, int ack); void ap_eapol_tx_status(void *ctx, const u8 *dst, const u8 *data, size_t len, int ack); void ap_client_poll_ok(void *ctx, const u8 *addr); void ap_rx_from_unknown_sta(void *ctx, const u8 *addr, int wds); void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt); void ap_mgmt_tx_cb(void *ctx, const u8 *buf, size_t len, u16 stype, int ok); int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s); int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s, const u8 *addr); void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s); int ap_switch_channel(struct wpa_supplicant *wpa_s, struct csa_settings *settings); int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr); void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht, int offset, int width, int cf1, int cf2); struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s, int ndef); #ifdef CONFIG_AP struct wpabuf * wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef); #else /* CONFIG_AP */ static inline struct wpabuf * wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef) { return NULL; } #endif /* CONFIG_AP */ int wpas_ap_wps_nfc_report_handover(struct wpa_supplicant *wpa_s, const struct wpabuf *req, const struct wpabuf *sel); int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id, const struct wpabuf *pw, const u8 *pubkey_hash); #endif /* AP_H */ wpa_supplicant-2.2/wpa_supplicant/config_ssid.h0000664000175000017500000004323712343617166017721 0ustar jmjm/* * WPA Supplicant / Network configuration structures * Copyright (c) 2003-2013, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef CONFIG_SSID_H #define CONFIG_SSID_H #include "common/defs.h" #include "utils/list.h" #include "eap_peer/eap_config.h" #define MAX_SSID_LEN 32 #define DEFAULT_EAP_WORKAROUND ((unsigned int) -1) #define DEFAULT_EAPOL_FLAGS (EAPOL_FLAG_REQUIRE_KEY_UNICAST | \ EAPOL_FLAG_REQUIRE_KEY_BROADCAST) #define DEFAULT_PROTO (WPA_PROTO_WPA | WPA_PROTO_RSN) #define DEFAULT_KEY_MGMT (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X) #define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP) #define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | \ WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) #define DEFAULT_FRAGMENT_SIZE 1398 #define DEFAULT_BG_SCAN_PERIOD -1 #define DEFAULT_DISABLE_HT 0 #define DEFAULT_DISABLE_HT40 0 #define DEFAULT_DISABLE_SGI 0 #define DEFAULT_DISABLE_LDPC 0 #define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */ #define DEFAULT_AMPDU_FACTOR -1 /* no change */ #define DEFAULT_AMPDU_DENSITY -1 /* no change */ #define DEFAULT_USER_SELECTED_SIM 1 struct psk_list_entry { struct dl_list list; u8 addr[ETH_ALEN]; u8 psk[32]; u8 p2p; }; /** * struct wpa_ssid - Network configuration data * * This structure includes all the configuration variables for a network. This * data is included in the per-interface configuration data as an element of * the network list, struct wpa_config::ssid. Each network block in the * configuration is mapped to a struct wpa_ssid instance. */ struct wpa_ssid { /** * next - Next network in global list * * This pointer can be used to iterate over all networks. The head of * this list is stored in the ssid field of struct wpa_config. */ struct wpa_ssid *next; /** * pnext - Next network in per-priority list * * This pointer can be used to iterate over all networks in the same * priority class. The heads of these list are stored in the pssid * fields of struct wpa_config. */ struct wpa_ssid *pnext; /** * id - Unique id for the network * * This identifier is used as a unique identifier for each network * block when using the control interface. Each network is allocated an * id when it is being created, either when reading the configuration * file or when a new network is added through the control interface. */ int id; /** * priority - Priority group * * By default, all networks will get same priority group (0). If some * of the networks are more desirable, this field can be used to change * the order in which wpa_supplicant goes through the networks when * selecting a BSS. The priority groups will be iterated in decreasing * priority (i.e., the larger the priority value, the sooner the * network is matched against the scan results). Within each priority * group, networks will be selected based on security policy, signal * strength, etc. * * Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are * not using this priority to select the order for scanning. Instead, * they try the networks in the order that used in the configuration * file. */ int priority; /** * ssid - Service set identifier (network name) * * This is the SSID for the network. For wireless interfaces, this is * used to select which network will be used. If set to %NULL (or * ssid_len=0), any SSID can be used. For wired interfaces, this must * be set to %NULL. Note: SSID may contain any characters, even nul * (ASCII 0) and as such, this should not be assumed to be a nul * terminated string. ssid_len defines how many characters are valid * and the ssid field is not guaranteed to be nul terminated. */ u8 *ssid; /** * ssid_len - Length of the SSID */ size_t ssid_len; /** * bssid - BSSID * * If set, this network block is used only when associating with the AP * using the configured BSSID * * If this is a persistent P2P group (disabled == 2), this is the GO * Device Address. */ u8 bssid[ETH_ALEN]; /** * bssid_set - Whether BSSID is configured for this network */ int bssid_set; /** * go_p2p_dev_addr - GO's P2P Device Address or all zeros if not set */ u8 go_p2p_dev_addr[ETH_ALEN]; /** * psk - WPA pre-shared key (256 bits) */ u8 psk[32]; /** * psk_set - Whether PSK field is configured */ int psk_set; /** * passphrase - WPA ASCII passphrase * * If this is set, psk will be generated using the SSID and passphrase * configured for the network. ASCII passphrase must be between 8 and * 63 characters (inclusive). */ char *passphrase; /** * ext_psk - PSK/passphrase name in external storage * * If this is set, PSK/passphrase will be fetched from external storage * when requesting association with the network. */ char *ext_psk; /** * pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_* */ int pairwise_cipher; /** * group_cipher - Bitfield of allowed group ciphers, WPA_CIPHER_* */ int group_cipher; /** * key_mgmt - Bitfield of allowed key management protocols * * WPA_KEY_MGMT_* */ int key_mgmt; /** * bg_scan_period - Background scan period in seconds, 0 to disable, or * -1 to indicate no change to default driver configuration */ int bg_scan_period; /** * proto - Bitfield of allowed protocols, WPA_PROTO_* */ int proto; /** * auth_alg - Bitfield of allowed authentication algorithms * * WPA_AUTH_ALG_* */ int auth_alg; /** * scan_ssid - Scan this SSID with Probe Requests * * scan_ssid can be used to scan for APs using hidden SSIDs. * Note: Many drivers do not support this. ap_mode=2 can be used with * such drivers to use hidden SSIDs. */ int scan_ssid; #ifdef IEEE8021X_EAPOL #define EAPOL_FLAG_REQUIRE_KEY_UNICAST BIT(0) #define EAPOL_FLAG_REQUIRE_KEY_BROADCAST BIT(1) /** * eapol_flags - Bit field of IEEE 802.1X/EAPOL options (EAPOL_FLAG_*) */ int eapol_flags; /** * eap - EAP peer configuration for this network */ struct eap_peer_config eap; #endif /* IEEE8021X_EAPOL */ #define NUM_WEP_KEYS 4 #define MAX_WEP_KEY_LEN 16 /** * wep_key - WEP keys */ u8 wep_key[NUM_WEP_KEYS][MAX_WEP_KEY_LEN]; /** * wep_key_len - WEP key lengths */ size_t wep_key_len[NUM_WEP_KEYS]; /** * wep_tx_keyidx - Default key index for TX frames using WEP */ int wep_tx_keyidx; /** * proactive_key_caching - Enable proactive key caching * * This field can be used to enable proactive key caching which is also * known as opportunistic PMKSA caching for WPA2. This is disabled (0) * by default unless default value is changed with the global okc=1 * parameter. Enable by setting this to 1. * * Proactive key caching is used to make supplicant assume that the APs * are using the same PMK and generate PMKSA cache entries without * doing RSN pre-authentication. This requires support from the AP side * and is normally used with wireless switches that co-locate the * authenticator. * * Internally, special value -1 is used to indicate that the parameter * was not specified in the configuration (i.e., default behavior is * followed). */ int proactive_key_caching; /** * mixed_cell - Whether mixed cells are allowed * * This option can be used to configure whether so called mixed cells, * i.e., networks that use both plaintext and encryption in the same * SSID, are allowed. This is disabled (0) by default. Enable by * setting this to 1. */ int mixed_cell; #ifdef IEEE8021X_EAPOL /** * leap - Number of EAP methods using LEAP * * This field should be set to 1 if LEAP is enabled. This is used to * select IEEE 802.11 authentication algorithm. */ int leap; /** * non_leap - Number of EAP methods not using LEAP * * This field should be set to >0 if any EAP method other than LEAP is * enabled. This is used to select IEEE 802.11 authentication * algorithm. */ int non_leap; /** * eap_workaround - EAP workarounds enabled * * wpa_supplicant supports number of "EAP workarounds" to work around * interoperability issues with incorrectly behaving authentication * servers. This is recommended to be enabled by default because some * of the issues are present in large number of authentication servers. * * Strict EAP conformance mode can be configured by disabling * workarounds with eap_workaround = 0. */ unsigned int eap_workaround; #endif /* IEEE8021X_EAPOL */ /** * mode - IEEE 802.11 operation mode (Infrastucture/IBSS) * * 0 = infrastructure (Managed) mode, i.e., associate with an AP. * * 1 = IBSS (ad-hoc, peer-to-peer) * * 2 = AP (access point) * * 3 = P2P Group Owner (can be set in the configuration file) * * 4 = P2P Group Formation (used internally; not in configuration * files) * * Note: IBSS can only be used with key_mgmt NONE (plaintext and static * WEP) and WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE * (fixed group key TKIP/CCMP) is available for backwards compatibility, * but its use is deprecated. WPA-None requires following network block * options: proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or * CCMP, but not both), and psk must also be set (either directly or * using ASCII passphrase). */ enum wpas_mode { WPAS_MODE_INFRA = 0, WPAS_MODE_IBSS = 1, WPAS_MODE_AP = 2, WPAS_MODE_P2P_GO = 3, WPAS_MODE_P2P_GROUP_FORMATION = 4, } mode; /** * disabled - Whether this network is currently disabled * * 0 = this network can be used (default). * 1 = this network block is disabled (can be enabled through * ctrl_iface, e.g., with wpa_cli or wpa_gui). * 2 = this network block includes parameters for a persistent P2P * group (can be used with P2P ctrl_iface commands) */ int disabled; /** * disabled_for_connect - Whether this network was temporarily disabled * * This flag is used to reenable all the temporarily disabled networks * after either the success or failure of a WPS connection. */ int disabled_for_connect; /** * peerkey - Whether PeerKey handshake for direct links is allowed * * This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are * enabled. * * 0 = disabled (default) * 1 = enabled */ int peerkey; /** * id_str - Network identifier string for external scripts * * This value is passed to external ctrl_iface monitors in * WPA_EVENT_CONNECTED event and wpa_cli sets this as WPA_ID_STR * environment variable for action scripts. */ char *id_str; #ifdef CONFIG_IEEE80211W /** * ieee80211w - Whether management frame protection is enabled * * This value is used to configure policy for management frame * protection (IEEE 802.11w). 0 = disabled, 1 = optional, 2 = required. * This is disabled by default unless the default value has been changed * with the global pmf=1/2 parameter. * * Internally, special value 3 is used to indicate that the parameter * was not specified in the configuration (i.e., default behavior is * followed). */ enum mfp_options ieee80211w; #endif /* CONFIG_IEEE80211W */ /** * frequency - Channel frequency in megahertz (MHz) for IBSS * * This value is used to configure the initial channel for IBSS (adhoc) * networks, e.g., 2412 = IEEE 802.11b/g channel 1. It is ignored in * the infrastructure mode. In addition, this value is only used by the * station that creates the IBSS. If an IBSS network with the * configured SSID is already present, the frequency of the network * will be used instead of this configured value. */ int frequency; int ht40; int vht; /** * wpa_ptk_rekey - Maximum lifetime for PTK in seconds * * This value can be used to enforce rekeying of PTK to mitigate some * attacks against TKIP deficiencies. */ int wpa_ptk_rekey; /** * scan_freq - Array of frequencies to scan or %NULL for all * * This is an optional zero-terminated array of frequencies in * megahertz (MHz) to include in scan requests when searching for this * network. This can be used to speed up scanning when the network is * known to not use all possible channels. */ int *scan_freq; /** * bgscan - Background scan and roaming parameters or %NULL if none * * This is an optional set of parameters for background scanning and * roaming within a network (ESS) in following format: * : */ char *bgscan; /** * ignore_broadcast_ssid - Hide SSID in AP mode * * Send empty SSID in beacons and ignore probe request frames that do * not specify full SSID, i.e., require stations to know SSID. * default: disabled (0) * 1 = send empty (length=0) SSID in beacon and ignore probe request * for broadcast SSID * 2 = clear SSID (ASCII 0), but keep the original length (this may be * required with some clients that do not support empty SSID) and * ignore probe requests for broadcast SSID */ int ignore_broadcast_ssid; /** * freq_list - Array of allowed frequencies or %NULL for all * * This is an optional zero-terminated array of frequencies in * megahertz (MHz) to allow for selecting the BSS. If set, scan results * that do not match any of the specified frequencies are not * considered when selecting a BSS. */ int *freq_list; /** * p2p_client_list - List of P2P Clients in a persistent group (GO) * * This is a list of P2P Clients (P2P Device Address) that have joined * the persistent group. This is maintained on the GO for persistent * group entries (disabled == 2). */ u8 *p2p_client_list; /** * num_p2p_clients - Number of entries in p2p_client_list */ size_t num_p2p_clients; #ifndef P2P_MAX_STORED_CLIENTS #define P2P_MAX_STORED_CLIENTS 100 #endif /* P2P_MAX_STORED_CLIENTS */ /** * psk_list - Per-client PSKs (struct psk_list_entry) */ struct dl_list psk_list; /** * p2p_group - Network generated as a P2P group (used internally) */ int p2p_group; /** * p2p_persistent_group - Whether this is a persistent group */ int p2p_persistent_group; /** * temporary - Whether this network is temporary and not to be saved */ int temporary; /** * export_keys - Whether keys may be exported * * This attribute will be set when keys are determined through * WPS or similar so that they may be exported. */ int export_keys; #ifdef CONFIG_HT_OVERRIDES /** * disable_ht - Disable HT (IEEE 802.11n) for this network * * By default, use it if it is available, but this can be configured * to 1 to have it disabled. */ int disable_ht; /** * disable_ht40 - Disable HT40 for this network * * By default, use it if it is available, but this can be configured * to 1 to have it disabled. */ int disable_ht40; /** * disable_sgi - Disable SGI (Short Guard Interval) for this network * * By default, use it if it is available, but this can be configured * to 1 to have it disabled. */ int disable_sgi; /** * disable_ldpc - Disable LDPC for this network * * By default, use it if it is available, but this can be configured * to 1 to have it disabled. */ int disable_ldpc; /** * ht40_intolerant - Indicate 40 MHz intolerant for this network */ int ht40_intolerant; /** * disable_max_amsdu - Disable MAX A-MSDU * * A-MDSU will be 3839 bytes when disabled, or 7935 * when enabled (assuming it is otherwise supported) * -1 (default) means do not apply any settings to the kernel. */ int disable_max_amsdu; /** * ampdu_factor - Maximum A-MPDU Length Exponent * * Value: 0-3, see 7.3.2.56.3 in IEEE Std 802.11n-2009. */ int ampdu_factor; /** * ampdu_density - Minimum A-MPDU Start Spacing * * Value: 0-7, see 7.3.2.56.3 in IEEE Std 802.11n-2009. */ int ampdu_density; /** * ht_mcs - Allowed HT-MCS rates, in ASCII hex: ffff0000... * * By default (empty string): Use whatever the OS has configured. */ char *ht_mcs; #endif /* CONFIG_HT_OVERRIDES */ #ifdef CONFIG_VHT_OVERRIDES /** * disable_vht - Disable VHT (IEEE 802.11ac) for this network * * By default, use it if it is available, but this can be configured * to 1 to have it disabled. */ int disable_vht; /** * vht_capa - VHT capabilities to use */ unsigned int vht_capa; /** * vht_capa_mask - mask for VHT capabilities */ unsigned int vht_capa_mask; int vht_rx_mcs_nss_1, vht_rx_mcs_nss_2, vht_rx_mcs_nss_3, vht_rx_mcs_nss_4, vht_rx_mcs_nss_5, vht_rx_mcs_nss_6, vht_rx_mcs_nss_7, vht_rx_mcs_nss_8; int vht_tx_mcs_nss_1, vht_tx_mcs_nss_2, vht_tx_mcs_nss_3, vht_tx_mcs_nss_4, vht_tx_mcs_nss_5, vht_tx_mcs_nss_6, vht_tx_mcs_nss_7, vht_tx_mcs_nss_8; #endif /* CONFIG_VHT_OVERRIDES */ /** * ap_max_inactivity - Timeout in seconds to detect STA's inactivity * * This timeout value is used in AP mode to clean up inactive stations. * By default: 300 seconds. */ int ap_max_inactivity; /** * dtim_period - DTIM period in Beacon intervals * By default: 2 */ int dtim_period; /** * beacon_int - Beacon interval (default: 100 TU) */ int beacon_int; /** * auth_failures - Number of consecutive authentication failures */ unsigned int auth_failures; /** * disabled_until - Network block disabled until this time if non-zero */ struct os_reltime disabled_until; /** * parent_cred - Pointer to parent wpa_cred entry * * This pointer can be used to delete temporary networks when a wpa_cred * that was used to create them is removed. This pointer should not be * dereferences since it may not be updated in all cases. */ void *parent_cred; #ifdef CONFIG_MACSEC /** * macsec_policy - Determines the policy for MACsec secure session * * 0: MACsec not in use (default) * 1: MACsec enabled - Should secure, accept key server's advice to * determine whether to use a secure session or not. */ int macsec_policy; #endif /* CONFIG_MACSEC */ }; #endif /* CONFIG_SSID_H */ wpa_supplicant-2.2/wpa_supplicant/defconfig0000664000175000017500000004367212343617166017133 0ustar jmjm# Example wpa_supplicant build time configuration # # This file lists the configuration options that are used when building the # hostapd binary. All lines starting with # are ignored. Configuration option # lines must be commented out complete, if they are not to be included, i.e., # just setting VARIABLE=n is not disabling that variable. # # This file is included in Makefile, so variables like CFLAGS and LIBS can also # be modified from here. In most cases, these lines should use += in order not # to override previous values of the variables. # Uncomment following two lines and fix the paths if you have installed OpenSSL # or GnuTLS in non-default location #CFLAGS += -I/usr/local/openssl/include #LIBS += -L/usr/local/openssl/lib # Some Red Hat versions seem to include kerberos header files from OpenSSL, but # the kerberos files are not in the default include path. Following line can be # used to fix build issues on such systems (krb5.h not found). #CFLAGS += -I/usr/include/kerberos # Driver interface for generic Linux wireless extensions # Note: WEXT is deprecated in the current Linux kernel version and no new # functionality is added to it. nl80211-based interface is the new # replacement for WEXT and its use allows wpa_supplicant to properly control # the driver to improve existing functionality like roaming and to support new # functionality. CONFIG_DRIVER_WEXT=y # Driver interface for Linux drivers using the nl80211 kernel interface CONFIG_DRIVER_NL80211=y # driver_nl80211.c requires libnl. If you are compiling it yourself # you may need to point hostapd to your version of libnl. # #CFLAGS += -I$ #LIBS += -L$ # Use libnl v2.0 (or 3.0) libraries. #CONFIG_LIBNL20=y # Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored) #CONFIG_LIBNL32=y # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) #CONFIG_DRIVER_BSD=y #CFLAGS += -I/usr/local/include #LIBS += -L/usr/local/lib #LIBS_p += -L/usr/local/lib #LIBS_c += -L/usr/local/lib # Driver interface for Windows NDIS #CONFIG_DRIVER_NDIS=y #CFLAGS += -I/usr/include/w32api/ddk #LIBS += -L/usr/local/lib # For native build using mingw #CONFIG_NATIVE_WINDOWS=y # Additional directories for cross-compilation on Linux host for mingw target #CFLAGS += -I/opt/mingw/mingw32/include/ddk #LIBS += -L/opt/mingw/mingw32/lib #CC=mingw32-gcc # By default, driver_ndis uses WinPcap for low-level operations. This can be # replaced with the following option which replaces WinPcap calls with NDISUIO. # However, this requires that WZC is disabled (net stop wzcsvc) before starting # wpa_supplicant. # CONFIG_USE_NDISUIO=y # Driver interface for development testing #CONFIG_DRIVER_TEST=y # Driver interface for wired Ethernet drivers CONFIG_DRIVER_WIRED=y # Driver interface for the Broadcom RoboSwitch family #CONFIG_DRIVER_ROBOSWITCH=y # Driver interface for no driver (e.g., WPS ER only) #CONFIG_DRIVER_NONE=y # Solaris libraries #LIBS += -lsocket -ldlpi -lnsl #LIBS_c += -lsocket # Enable IEEE 802.1X Supplicant (automatically included if any EAP method is # included) CONFIG_IEEE8021X_EAPOL=y # EAP-MD5 CONFIG_EAP_MD5=y # EAP-MSCHAPv2 CONFIG_EAP_MSCHAPV2=y # EAP-TLS CONFIG_EAP_TLS=y # EAL-PEAP CONFIG_EAP_PEAP=y # EAP-TTLS CONFIG_EAP_TTLS=y # EAP-FAST # Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed # for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g., # with openssl-0.9.8x-tls-extensions.patch, to add the needed functions. #CONFIG_EAP_FAST=y # EAP-GTC CONFIG_EAP_GTC=y # EAP-OTP CONFIG_EAP_OTP=y # EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used) #CONFIG_EAP_SIM=y # EAP-PSK (experimental; this is _not_ needed for WPA-PSK) #CONFIG_EAP_PSK=y # EAP-pwd (secure authentication using only a password) #CONFIG_EAP_PWD=y # EAP-PAX #CONFIG_EAP_PAX=y # LEAP CONFIG_EAP_LEAP=y # EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used) #CONFIG_EAP_AKA=y # EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used). # This requires CONFIG_EAP_AKA to be enabled, too. #CONFIG_EAP_AKA_PRIME=y # Enable USIM simulator (Milenage) for EAP-AKA #CONFIG_USIM_SIMULATOR=y # EAP-SAKE #CONFIG_EAP_SAKE=y # EAP-GPSK #CONFIG_EAP_GPSK=y # Include support for optional SHA256 cipher suite in EAP-GPSK #CONFIG_EAP_GPSK_SHA256=y # EAP-TNC and related Trusted Network Connect support (experimental) #CONFIG_EAP_TNC=y # Wi-Fi Protected Setup (WPS) #CONFIG_WPS=y # Enable WPS external registrar functionality #CONFIG_WPS_ER=y # Disable credentials for an open network by default when acting as a WPS # registrar. #CONFIG_WPS_REG_DISABLE_OPEN=y # Enable WPS support with NFC config method #CONFIG_WPS_NFC=y # EAP-IKEv2 #CONFIG_EAP_IKEV2=y # EAP-EKE #CONFIG_EAP_EKE=y # PKCS#12 (PFX) support (used to read private key and certificate file from # a file that usually has extension .p12 or .pfx) CONFIG_PKCS12=y # Smartcard support (i.e., private key on a smartcard), e.g., with openssl # engine. CONFIG_SMARTCARD=y # PC/SC interface for smartcards (USIM, GSM SIM) # Enable this if EAP-SIM or EAP-AKA is included #CONFIG_PCSC=y # Support HT overrides (disable HT/HT40, mask MCS rates, etc.) #CONFIG_HT_OVERRIDES=y # Support VHT overrides (disable VHT, mask MCS rates, etc.) #CONFIG_VHT_OVERRIDES=y # Development testing #CONFIG_EAPOL_TEST=y # Select control interface backend for external programs, e.g, wpa_cli: # unix = UNIX domain sockets (default for Linux/*BSD) # udp = UDP sockets using localhost (127.0.0.1) # udp6 = UDP IPv6 sockets using localhost (::1) # named_pipe = Windows Named Pipe (default for Windows) # udp-remote = UDP sockets with remote access (only for tests systems/purpose) # udp6-remote = UDP IPv6 sockets with remote access (only for tests purpose) # y = use default (backwards compatibility) # If this option is commented out, control interface is not included in the # build. CONFIG_CTRL_IFACE=y # Include support for GNU Readline and History Libraries in wpa_cli. # When building a wpa_cli binary for distribution, please note that these # libraries are licensed under GPL and as such, BSD license may not apply for # the resulting binary. #CONFIG_READLINE=y # Include internal line edit mode in wpa_cli. This can be used as a replacement # for GNU Readline to provide limited command line editing and history support. #CONFIG_WPA_CLI_EDIT=y # Remove debugging code that is printing out debug message to stdout. # This can be used to reduce the size of the wpa_supplicant considerably # if debugging code is not needed. The size reduction can be around 35% # (e.g., 90 kB). #CONFIG_NO_STDOUT_DEBUG=y # Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save # 35-50 kB in code size. #CONFIG_NO_WPA=y # Remove IEEE 802.11i/WPA-Personal ASCII passphrase support # This option can be used to reduce code size by removing support for # converting ASCII passphrases into PSK. If this functionality is removed, the # PSK can only be configured as the 64-octet hexstring (e.g., from # wpa_passphrase). This saves about 0.5 kB in code size. #CONFIG_NO_WPA_PASSPHRASE=y # Disable scan result processing (ap_mode=1) to save code size by about 1 kB. # This can be used if ap_scan=1 mode is never enabled. #CONFIG_NO_SCAN_PROCESSING=y # Select configuration backend: # file = text file (e.g., wpa_supplicant.conf; note: the configuration file # path is given on command line, not here; this option is just used to # select the backend that allows configuration files to be used) # winreg = Windows registry (see win_example.reg for an example) CONFIG_BACKEND=file # Remove configuration write functionality (i.e., to allow the configuration # file to be updated based on runtime configuration changes). The runtime # configuration can still be changed, the changes are just not going to be # persistent over restarts. This option can be used to reduce code size by # about 3.5 kB. #CONFIG_NO_CONFIG_WRITE=y # Remove support for configuration blobs to reduce code size by about 1.5 kB. #CONFIG_NO_CONFIG_BLOBS=y # Select program entry point implementation: # main = UNIX/POSIX like main() function (default) # main_winsvc = Windows service (read parameters from registry) # main_none = Very basic example (development use only) #CONFIG_MAIN=main # Select wrapper for operating system and C library specific functions # unix = UNIX/POSIX like systems (default) # win32 = Windows systems # none = Empty template #CONFIG_OS=unix # Select event loop implementation # eloop = select() loop (default) # eloop_win = Windows events and WaitForMultipleObject() loop #CONFIG_ELOOP=eloop # Should we use poll instead of select? Select is used by default. #CONFIG_ELOOP_POLL=y # Should we use epoll instead of select? Select is used by default. #CONFIG_ELOOP_EPOLL=y # Select layer 2 packet implementation # linux = Linux packet socket (default) # pcap = libpcap/libdnet/WinPcap # freebsd = FreeBSD libpcap # winpcap = WinPcap with receive thread # ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y) # none = Empty template #CONFIG_L2_PACKET=linux # PeerKey handshake for Station to Station Link (IEEE 802.11e DLS) CONFIG_PEERKEY=y # IEEE 802.11w (management frame protection), also known as PMF # Driver support is also needed for IEEE 802.11w. #CONFIG_IEEE80211W=y # Select TLS implementation # openssl = OpenSSL (default) # gnutls = GnuTLS # internal = Internal TLSv1 implementation (experimental) # none = Empty template #CONFIG_TLS=openssl # TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1) # can be enabled to get a stronger construction of messages when block ciphers # are used. It should be noted that some existing TLS v1.0 -based # implementation may not be compatible with TLS v1.1 message (ClientHello is # sent prior to negotiating which version will be used) #CONFIG_TLSV11=y # TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2) # can be enabled to enable use of stronger crypto algorithms. It should be # noted that some existing TLS v1.0 -based implementation may not be compatible # with TLS v1.2 message (ClientHello is sent prior to negotiating which version # will be used) #CONFIG_TLSV12=y # If CONFIG_TLS=internal is used, additional library and include paths are # needed for LibTomMath. Alternatively, an integrated, minimal version of # LibTomMath can be used. See beginning of libtommath.c for details on benefits # and drawbacks of this option. #CONFIG_INTERNAL_LIBTOMMATH=y #ifndef CONFIG_INTERNAL_LIBTOMMATH #LTM_PATH=/usr/src/libtommath-0.39 #CFLAGS += -I$(LTM_PATH) #LIBS += -L$(LTM_PATH) #LIBS_p += -L$(LTM_PATH) #endif # At the cost of about 4 kB of additional binary size, the internal LibTomMath # can be configured to include faster routines for exptmod, sqr, and div to # speed up DH and RSA calculation considerably #CONFIG_INTERNAL_LIBTOMMATH_FAST=y # Include NDIS event processing through WMI into wpa_supplicant/wpasvc. # This is only for Windows builds and requires WMI-related header files and # WbemUuid.Lib from Platform SDK even when building with MinGW. #CONFIG_NDIS_EVENTS_INTEGRATED=y #PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib" # Add support for old DBus control interface # (fi.epitest.hostap.WPASupplicant) #CONFIG_CTRL_IFACE_DBUS=y # Add support for new DBus control interface # (fi.w1.hostap.wpa_supplicant1) #CONFIG_CTRL_IFACE_DBUS_NEW=y # Add introspection support for new DBus control interface #CONFIG_CTRL_IFACE_DBUS_INTRO=y # Add support for loading EAP methods dynamically as shared libraries. # When this option is enabled, each EAP method can be either included # statically (CONFIG_EAP_=y) or dynamically (CONFIG_EAP_=dyn). # Dynamic EAP methods are build as shared objects (eap_*.so) and they need to # be loaded in the beginning of the wpa_supplicant configuration file # (see load_dynamic_eap parameter in the example file) before being used in # the network blocks. # # Note that some shared parts of EAP methods are included in the main program # and in order to be able to use dynamic EAP methods using these parts, the # main program must have been build with the EAP method enabled (=y or =dyn). # This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries # unless at least one of them was included in the main build to force inclusion # of the shared code. Similarly, at least one of EAP-SIM/AKA must be included # in the main build to be able to load these methods dynamically. # # Please also note that using dynamic libraries will increase the total binary # size. Thus, it may not be the best option for targets that have limited # amount of memory/flash. #CONFIG_DYNAMIC_EAP_METHODS=y # IEEE Std 802.11r-2008 (Fast BSS Transition) #CONFIG_IEEE80211R=y # Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt) #CONFIG_DEBUG_FILE=y # Send debug messages to syslog instead of stdout #CONFIG_DEBUG_SYSLOG=y # Set syslog facility for debug messages #CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON # Add support for sending all debug messages (regardless of debug verbosity) # to the Linux kernel tracing facility. This helps debug the entire stack by # making it easy to record everything happening from the driver up into the # same file, e.g., using trace-cmd. #CONFIG_DEBUG_LINUX_TRACING=y # Add support for writing debug log to Android logcat instead of standard # output #CONFIG_ANDROID_LOG=y # Enable privilege separation (see README 'Privilege separation' for details) #CONFIG_PRIVSEP=y # Enable mitigation against certain attacks against TKIP by delaying Michael # MIC error reports by a random amount of time between 0 and 60 seconds #CONFIG_DELAYED_MIC_ERROR_REPORT=y # Enable tracing code for developer debugging # This tracks use of memory allocations and other registrations and reports # incorrect use with a backtrace of call (or allocation) location. #CONFIG_WPA_TRACE=y # For BSD, uncomment these. #LIBS += -lexecinfo #LIBS_p += -lexecinfo #LIBS_c += -lexecinfo # Use libbfd to get more details for developer debugging # This enables use of libbfd to get more detailed symbols for the backtraces # generated by CONFIG_WPA_TRACE=y. #CONFIG_WPA_TRACE_BFD=y # For BSD, uncomment these. #LIBS += -lbfd -liberty -lz #LIBS_p += -lbfd -liberty -lz #LIBS_c += -lbfd -liberty -lz # wpa_supplicant depends on strong random number generation being available # from the operating system. os_get_random() function is used to fetch random # data when needed, e.g., for key generation. On Linux and BSD systems, this # works by reading /dev/urandom. It should be noted that the OS entropy pool # needs to be properly initialized before wpa_supplicant is started. This is # important especially on embedded devices that do not have a hardware random # number generator and may by default start up with minimal entropy available # for random number generation. # # As a safety net, wpa_supplicant is by default trying to internally collect # additional entropy for generating random data to mix in with the data fetched # from the OS. This by itself is not considered to be very strong, but it may # help in cases where the system pool is not initialized properly. However, it # is very strongly recommended that the system pool is initialized with enough # entropy either by using hardware assisted random number generator or by # storing state over device reboots. # # wpa_supplicant can be configured to maintain its own entropy store over # restarts to enhance random number generation. This is not perfect, but it is # much more secure than using the same sequence of random numbers after every # reboot. This can be enabled with -e command line option. The # specified file needs to be readable and writable by wpa_supplicant. # # If the os_get_random() is known to provide strong random data (e.g., on # Linux/BSD, the board in question is known to have reliable source of random # data from /dev/urandom), the internal wpa_supplicant random pool can be # disabled. This will save some in binary size and CPU use. However, this # should only be considered for builds that are known to be used on devices # that meet the requirements described above. #CONFIG_NO_RANDOM_POOL=y # IEEE 802.11n (High Throughput) support (mainly for AP mode) #CONFIG_IEEE80211N=y # IEEE 802.11ac (Very High Throughput) support (mainly for AP mode) # (depends on CONFIG_IEEE80211N) #CONFIG_IEEE80211AC=y # Wireless Network Management (IEEE Std 802.11v-2011) # Note: This is experimental and not complete implementation. #CONFIG_WNM=y # Interworking (IEEE 802.11u) # This can be used to enable functionality to improve interworking with # external networks (GAS/ANQP to learn more about the networks and network # selection based on available credentials). #CONFIG_INTERWORKING=y # Hotspot 2.0 #CONFIG_HS20=y # Disable roaming in wpa_supplicant #CONFIG_NO_ROAMING=y # AP mode operations with wpa_supplicant # This can be used for controlling AP mode operations with wpa_supplicant. It # should be noted that this is mainly aimed at simple cases like # WPA2-Personal while more complex configurations like WPA2-Enterprise with an # external RADIUS server can be supported with hostapd. #CONFIG_AP=y # P2P (Wi-Fi Direct) # This can be used to enable P2P support in wpa_supplicant. See README-P2P for # more information on P2P operations. #CONFIG_P2P=y # Enable TDLS support #CONFIG_TDLS=y # Wi-Fi Direct # This can be used to enable Wi-Fi Direct extensions for P2P using an external # program to control the additional information exchanges in the messages. #CONFIG_WIFI_DISPLAY=y # Autoscan # This can be used to enable automatic scan support in wpa_supplicant. # See wpa_supplicant.conf for more information on autoscan usage. # # Enabling directly a module will enable autoscan support. # For exponential module: #CONFIG_AUTOSCAN_EXPONENTIAL=y # For periodic module: #CONFIG_AUTOSCAN_PERIODIC=y # Password (and passphrase, etc.) backend for external storage # These optional mechanisms can be used to add support for storing passwords # and other secrets in external (to wpa_supplicant) location. This allows, for # example, operating system specific key storage to be used # # External password backend for testing purposes (developer use) #CONFIG_EXT_PASSWORD_TEST=y wpa_supplicant-2.2/wpa_supplicant/ChangeLog0000664000175000017500000031407412343617166017033 0ustar jmjmChangeLog for wpa_supplicant 2014-06-04 - v2.2 * added DFS indicator to get_capability freq * added/fixed nl80211 functionality - BSSID/frequency hint for driver-based BSS selection - fix tearing down WDS STA interfaces - support vendor specific driver command (VENDOR []) - GO interface teardown optimization - allow beacon interval to be configured for IBSS - add SHA256-based AKM suites to CONNECT/ASSOCIATE commands * removed unused NFC_RX_HANDOVER_REQ and NFC_RX_HANDOVER_SEL control interface commands (the more generic NFC_REPORT_HANDOVER is now used) * fixed MSCHAP UTF-8 to UCS-2 conversion for three-byte encoding; this fixes password with include UTF-8 characters that use three-byte encoding EAP methods that use NtPasswordHash * fixed couple of sequencies where radio work items could get stuck, e.g., when rfkill blocking happens during scanning or when scan-for-auth workaround is used * P2P enhancements/fixes - enable enable U-APSD on GO automatically if the driver indicates support for this - fixed some service discovery cases with broadcast queries not being sent to all stations - fixed Probe Request frame triggering invitation to trigger only a single invitation instance even if multiple Probe Request frames are received - fixed a potential NULL pointer dereference crash when processing an invalid Invitation Request frame - add optional configuration file for the P2P_DEVICE parameters - optimize scan for GO during persistent group invocation - fix possible segmentation fault when PBC overlap is detected while using a separate P2P group interface - improve GO Negotiation robustness by allowing GO Negotiation Confirmation to be retransmitted - do use freed memory on device found event when P2P NFC * added phase1 network parameter options for disabling TLS v1.1 and v1.2 to allow workarounds with misbehaving AAA servers (tls_disable_tlsv1_1=1 and tls_disable_tlsv1_2=1) * added support for OCSP stapling to validate AAA server certificate during TLS exchange * Interworking/Hotspot 2.0 enhancements - prefer the last added network in Interworking connection to make the behavior more consistent with likely user expectation - roaming partner configuration (roaming_partner within a cred block) - support Hotspot 2.0 Release 2 * "hs20_anqp_get 8" to request OSU Providers list * "hs20_icon_request " to request icon files * "fetch_osu" and "cancel_osu_fetch" to start/stop full OSU provider search (all suitable APs in scan results) * OSEN network for online signup connection * min_{dl,ul}_bandwidth_{home,roaming} cred parameters * max_bss_load cred parameter * req_conn_capab cred parameter * sp_priority cred parameter * ocsp cred parameter * slow down automatic connection attempts on EAP failure to meet required behavior (no more than 10 retries within a 10-minute interval) * sample implementation of online signup client (both SPP and OMA-DM protocols) (hs20/client/*) - fixed GAS indication for additional comeback delay with status code 95 - extend ANQP_GET to accept Hotspot 2.0 subtypes ANQP_GET [,]... [,hs20:][...,hs20:] - add control interface events CRED-ADDED , CRED-MODIFIED , CRED-REMOVED - add "GET_CRED " command - enable FT for the connection automatically if the AP advertises support for this - fix a case where auto_interworking=1 could end up stopping scanning * fixed TDLS interoperability issues with supported operating class in some deployed stations * internal TLS implementation enhancements/fixes - add SHA256-based cipher suites - add DHE-RSA cipher suites - fix X.509 validation of PKCS#1 signature to check for extra data * fixed PTK derivation for CCMP-256 and GCMP-256 * added "reattach" command for fast reassociate-back-to-same-BSS * allow PMF to be enabled for AP mode operation with the ieee80211w parameter * added "get_capability tdls" command * added option to set config blobs through control interface with "SET blob " * D-Bus interface extensions/fixes - make p2p_no_group_iface configurable - declare ServiceDiscoveryRequest method properly - export peer's device address as a property - make reassociate command behave like the control interface one, i.e., to allow connection from disconnected state * added optional "freq=" parameter to SET pno * added optional "freq=" parameter to SELECT_NETWORK * fixed OBSS scan result processing for 20/40 MHz co-ex report * remove WPS 1.0 only support, i.e., WSC 2.0 support is now enabled whenever CONFIG_WPS=y is set * fixed regression in parsing of WNM Sleep Mode exit key data * fixed potential segmentation fault and memory leaks in WNM neighbor report processing * EAP-pwd fixes - fragmentation of PWD-Confirm-Resp - fix memory leak when fragmentation is used - fix possible segmentation fault on EAP method deinit if an invalid group is negotiated * added MACsec/IEEE Std 802.1X-2010 PAE implementation (currently available only with the macsec_qca driver wrapper) * fixed EAP-SIM counter-too-small message * added 'dup_network ' command; this can be used to clone the psk field without having toextract it from wpa_supplicant * fixed GSM authentication on USIM * added support for usin epoll in eloop (CONFIG_ELOOP_EPOLL=y) * fixed some concurrent virtual interface cases with dedicated P2P management interface to not catch events from removed interface (this could result in the management interface getting disabled) * fixed a memory leak in SAE random number generation * fixed off-by-one bounds checking in printf_encode() - this could result in some control interface ATTACH command cases terminating wpa_supplicant * fixed EAPOL-Key exchange when GCMP is used with SHA256-based AKM * various bug fixes 2014-02-04 - v2.1 * added support for simultaneous authentication of equals (SAE) for stronger password-based authentication with WPA2-Personal * improved P2P negotiation and group formation robustness - avoid unnecessary Dialog Token value changes during retries - avoid more concurrent scanning cases during full group formation sequence - do not use potentially obsolete scan result data from driver cache for peer discovery/updates - avoid undesired re-starting of GO negotiation based on Probe Request frames - increase GO Negotiation and Invitation timeouts to address busy environments and peers that take long time to react to messages, e.g., due to power saving - P2P Device interface type * improved P2P channel selection (use more peer information and allow more local options) * added support for optional per-device PSK assignment by P2P GO (wpa_cli p2p_set per_sta_psk <0/1>) * added P2P_REMOVE_CLIENT for removing a client from P2P groups (including persistent groups); this can be used to securely remove a client from a group if per-device PSKs are used * added more configuration flexibility for allowed P2P GO/client channels (p2p_no_go_freq list and p2p_add_cli_chan=0/1) * added nl80211 functionality - VHT configuration for nl80211 - MFP (IEEE 802.11w) information for nl80211 command API - support split wiphy dump - FT (IEEE 802.11r) with driver-based SME - use advertised number of supported concurrent channels - QoS Mapping configuration * improved TDLS negotiation robustness * added more TDLS peer parameters to be configured to the driver * optimized connection time by allowing recently received scan results to be used instead of having to run through a new scan * fixed ctrl_iface BSS command iteration with RANGE argument and no exact matches; also fixed argument parsing for some cases with multiple arguments * added 'SCAN TYPE=ONLY' ctrl_iface command to request manual scan without executing roaming/network re-selection on scan results * added Session-Id derivation for EAP peer methods * added fully automated regression testing with mac80211_hwsim * changed configuration parser to reject invalid integer values * allow AP/Enrollee to be specified with BSSID instead of UUID for WPS ER operations * disable network block temporarily on repeated connection failures * changed the default driver interface from wext to nl80211 if both are included in the build * remove duplicate networks if WPS provisioning is run multiple times * remove duplicate networks when Interworking network selection uses the same network * added global freq_list configuration to allow scan frequencies to be limited for all cases instead of just for a specific network block * added support for BSS Transition Management * added option to use "IFNAME= " prefix to use the global control interface connection to perform per-interface commands; similarly, allow global control interface to be used as a monitor interface to receive events from all interfaces * fixed OKC-based PMKSA cache entry clearing * fixed TKIP group key configuration with FT * added support for using OCSP stapling to validate server certificate (ocsp=1 as optional and ocsp=2 as mandatory) * added EAP-EKE peer * added peer restart detection for IBSS RSN * added domain_suffix_match (and domain_suffix_match2 for Phase 2 EAP-TLS) to specify additional constraint for the server certificate domain name * added support for external SIM/USIM processing in EAP-SIM, EAP-AKA, and EAP-AKA' (CTRL-REQ-SIM and CTRL-RSP-SIM commands over control interface) * added global bgscan configuration option as a default for all network blocks that do not specify their own bgscan parameters * added D-Bus methods for TDLS * added more control to scan requests - "SCAN freq=" can be used to specify which channels are scanned (comma-separated frequency ranges in MHz) - "SCAN passive=1" can be used to request a passive scan (no Probe Request frames are sent) - "SCAN use_id" can be used to request a scan id to be returned and included in event messages related to this specific scan operation - "SCAN only_new=1" can be used to request the driver/cfg80211 to report only BSS entries that have been updated during this scan round - these optional arguments to the SCAN command can be combined with each other * modified behavior on externally triggered scans - avoid concurrent operations requiring full control of the radio when an externally triggered scan is detected - do not use results for internal roaming decision * added a new cred block parameter 'temporary' to allow credential blocks to be stored separately even if wpa_supplicant configuration file is used to maintain other network information * added "radio work" framework to schedule exclusive radio operations for off-channel functionality - reduce issues with concurrent operations that try to control which channel is used - allow external programs to request exclusive radio control in a way that avoids conflicts with wpa_supplicant * added support for using Protected Dual of Public Action frames for GAS/ANQP exchanges when associated with PMF * added support for WPS+NFC updates and P2P+NFC - improved protocol for WPS - P2P group formation/join based on NFC connection handover - new IPv4 address assignment for P2P groups (ip_addr_* configuration parameters on the GO) to replace DHCP - option to fetch and report alternative carrier records for external NFC operations * various bug fixes 2013-01-12 - v2.0 * removed Qt3-based wpa_gui (obsoleted by wpa_qui-qt4) * removed unmaintained driver wrappers broadcom, iphone, osx, ralink, hostap, madwifi (hostap and madwifi remain available for hostapd; their wpa_supplicant functionality is obsoleted by wext) * improved debug logging (human readable event names, interface name included in more entries) * changed AP mode behavior to enable WPS only for open and WPA/WPA2-Personal configuration * improved P2P concurrency operations - better coordination of concurrent scan and P2P search operations - avoid concurrent remain-on-channel operation requests by canceling previous operations prior to starting a new one - reject operations that would require multi-channel concurrency if the driver does not support it - add parameter to select whether STA or P2P connection is preferred if the driver cannot support both at the same time - allow driver to indicate channel changes - added optional delay= parameter for p2p_find to avoid taking all radio resources - use 500 ms p2p_find search delay by default during concurrent operations - allow all channels in GO Negotiation if the driver supports multi-channel concurrency * added number of small changes to make it easier for static analyzers to understand the implementation * fixed number of small bugs (see git logs for more details) * nl80211: number of updates to use new cfg80211/nl80211 functionality - replace monitor interface with nl80211 commands for AP mode - additional information for driver-based AP SME - STA entry authorization in RSN IBSS * EAP-pwd: - fixed KDF for group 21 and zero-padding - added support for fragmentation - increased maximum number of hunting-and-pecking iterations * avoid excessive Probe Response retries for broadcast Probe Request frames (only with drivers using wpa_supplicant AP mode SME/MLME) * added "GET country" ctrl_iface command * do not save an invalid network block in wpa_supplicant.conf to avoid problems reading the file on next start * send STA connected/disconnected ctrl_iface events to both the P2P group and parent interfaces * added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y) * added "SET pno <1/0>" ctrl_iface command to start/stop preferred network offload with sched_scan driver command * merged in number of changes from Android repository for P2P, nl80211, and build parameters * changed P2P GO mode configuration to use driver capabilities to automatically enable HT operations when supported * added "wpa_cli status wps" command to fetch WPA2-Personal passhrase for WPS use cases in AP mode * EAP-AKA: keep pseudonym identity across EAP exchanges to match EAP-SIM behavior * improved reassociation behavior in cases where association is rejected or when an AP disconnects us to handle common load balancing mechanisms - try to avoid extra scans when the needed information is available * added optional "join" argument for p2p_prov_disc ctrl_iface command * added group ifname to P2P-PROV-DISC-* events * added P2P Device Address to AP-STA-DISCONNECTED event and use p2p_dev_addr parameter name with AP-STA-CONNECTED * added workarounds for WPS PBC overlap detection for some P2P use cases where deployed stations work incorrectly * optimize WPS connection speed by disconnecting prior to WPS scan and by using single channel scans when AP channel is known * PCSC and SIM/USIM improvements: - accept 0x67 (Wrong length) as a response to READ RECORD to fix issues with some USIM cards - try to read MNC length from SIM/USIM - build realm according to 3GPP TS 23.003 with identity from the SIM - allow T1 protocol to be enabled * added more WPS and P2P information available through D-Bus * improve P2P negotiation robustness - extra waits to get ACK frames through - longer timeouts for cases where deployed devices have been identified have issues meeting the specification requirements - more retries for some P2P frames - handle race conditions in GO Negotiation start by both devices - ignore unexpected GO Negotiation Response frame * added support for libnl 3.2 and newer * added P2P persistent group info to P2P_PEER data * maintain a list of P2P Clients for persistent group on GO * AP: increased initial group key handshake retransmit timeout to 500 ms * added optional dev_id parameter for p2p_find * added P2P-FIND-STOPPED ctrl_iface event * fixed issues in WPA/RSN element validation when roaming with ap_scan=1 and driver-based BSS selection * do not expire P2P peer entries while connected with the peer in a group * fixed WSC element inclusion in cases where P2P is disabled * AP: added a WPS workaround for mixed mode AP Settings with Windows 7 * EAP-SIM: fixed AT_COUNTER_TOO_SMALL use * EAP-SIM/AKA: append realm to pseudonym identity * EAP-SIM/AKA: store pseudonym identity in network configuration to allow it to persist over multiple EAP sessions and wpa_supplicant restarts * EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this breaks interoperability with older versions * added support for WFA Hotspot 2.0 - GAS/ANQP to fetch network information - credential configuration and automatic network selections based on credential match with ANQP information * limited PMKSA cache entries to be used only with the network context that was used to create them * improved PMKSA cache expiration to avoid unnecessary disconnections * adjusted bgscan_simple fast-scan backoff to avoid too frequent background scans * removed ctrl_iface event on P2P PD Response in join-group case * added option to fetch BSS table entry based on P2P Device Address ("BSS p2p_dev_addr=") * added BSS entry age to ctrl_iface BSS command output * added optional MASK=0xH option for ctrl_iface BSS command to select which fields are included in the response * added optional RANGE=ALL|N1-N2 option for ctrl_iface BSS command to fetch information about several BSSes in one call * simplified licensing terms by selecting the BSD license as the only alternative * added "P2P_SET disallow_freq " ctrl_iface command to disable channels from P2P use * added p2p_pref_chan configuration parameter to allow preferred P2P channels to be specified * added support for advertising immediate availability of a WPS credential for P2P use cases * optimized scan operations for P2P use cases (use single channel scan for a specific SSID when possible) * EAP-TTLS: fixed peer challenge generation for MSCHAPv2 * SME: do not use reassociation after explicit disconnection request (local or a notification from an AP) * added support for sending debug info to Linux tracing (-T on command line) * added support for using Deauthentication reason code 3 as an indication of P2P group termination * added wps_vendor_ext_m1 configuration parameter to allow vendor specific attributes to be added to WPS M1 * started using separate TLS library context for tunneled TLS (EAP-PEAP/TLS, EAP-TTLS/TLS, EAP-FAST/TLS) to support different CA certificate configuration between Phase 1 and Phase 2 * added optional "auto" parameter for p2p_connect to request automatic GO Negotiation vs. join-a-group selection * added disabled_scan_offload parameter to disable automatic scan offloading (sched_scan) * added optional persistent= parameter for p2p_connect to allow forcing of a specific SSID/passphrase for GO Negotiation * added support for OBSS scan requests and 20/40 BSS coexistence reports * reject PD Request for unknown group * removed scripts and notes related to Windows binary releases (which have not been used starting from 1.x) * added initial support for WNM operations - Keep-alive based on BSS max idle period - WNM-Sleep Mode - minimal BSS Transition Management processing * added autoscan module to control scanning behavior while not connected - autoscan_periodic and autoscan_exponential modules * added new WPS NFC ctrl_iface mechanism - added initial support NFC connection handover - removed obsoleted WPS_OOB command (including support for deprecated UFD config_method) * added optional framework for external password storage ("ext:") * wpa_cli: added optional support for controlling wpa_supplicant remotely over UDP (CONFIG_CTRL_IFACE=udp-remote) for testing purposes * wpa_cli: extended tab completion to more commands * changed SSID output to use printf-escaped strings instead of masking of non-ASCII characters - SSID can now be configured in the same format: ssid=P"abc\x00test" * removed default ACM=1 from AC_VO and AC_VI * added optional "ht40" argument for P2P ctrl_iface commands to allow 40 MHz channels to be requested on the 5 GHz band * added optional parameters for p2p_invite command to specify channel when reinvoking a persistent group as the GO * improved FIPS mode builds with OpenSSL - "make fips" with CONFIG_FIPS=y to build wpa_supplicant with the OpenSSL FIPS object module - replace low level OpenSSL AES API calls to use EVP - use OpenSSL keying material exporter when possible - do not export TLS keys in FIPS mode - remove MD5 from CONFIG_FIPS=y builds - use OpenSSL function for PKBDF2 passphrase-to-PSK - use OpenSSL HMAC implementation - mix RAND_bytes() output into random_get_bytes() to force OpenSSL DRBG to be used in FIPS mode - use OpenSSL CMAC implementation * added mechanism to disable TLS Session Ticket extension - a workaround for servers that do not support TLS extensions that was enabled by default in recent OpenSSL versions - tls_disable_session_ticket=1 - automatically disable TLS Session Ticket extension by default when using EAP-TLS/PEAP/TTLS (i.e., only use it with EAP-FAST) * changed VENDOR-TEST EAP method to use proper private enterprise number (this will not interoperate with older versions) * disable network block temporarily on authentication failures * improved WPS AP selection during WPS PIN iteration * added support for configuring GCMP cipher for IEEE 802.11ad * added support for Wi-Fi Display extensions - WFD_SUBELEMENT_SET ctrl_iface command to configure WFD subelements - SET wifi_display <0/1> to disable/enable WFD support - WFD service discovery - an external program is needed to manage the audio/video streaming and codecs * optimized scan result use for network selection - use the internal BSS table instead of raw scan results - allow unnecessary scans to be skipped if fresh information is available (e.g., after GAS/ANQP round for Interworking) * added support for 256-bit AES with internal TLS implementation * allow peer to propose channel in P2P invitation process for a persistent group * added disallow_aps parameter to allow BSSIDs/SSIDs to be disallowed from network selection * re-enable the networks disabled during WPS operations * allow P2P functionality to be disabled per interface (p2p_disabled=1) * added secondary device types into P2P_PEER output * added an option to disable use of a separate P2P group interface (p2p_no_group_iface=1) * fixed P2P Bonjour SD to match entries with both compressed and not compressed domain name format and support multiple Bonjour PTR matches for the same key * use deauthentication instead of disassociation for all disconnection operations; this removes the now unused disassociate() wpa_driver_ops callback * optimized PSK generation on P2P GO by caching results to avoid multiple PBKDF2 operations * added okc=1 global configuration parameter to allow OKC to be enabled by default for all network blocks * added a workaround for WPS PBC session overlap detection to avoid interop issues with deployed station implementations that do not remove active PBC indication from Probe Request frames properly * added basic support for 60 GHz band * extend EAPOL frames processing workaround for roaming cases (postpone processing of unexpected EAPOL frame until association event to handle reordered events) 2012-05-10 - v1.0 * bsd: Add support for setting HT values in IFM_MMASK. * Delay STA entry removal until Deauth/Disassoc TX status in AP mode. This allows the driver to use PS buffering of Deauthentication and Disassociation frames when the STA is in power save sleep. Only available with drivers that provide TX status events for Deauth/ Disassoc frames (nl80211). * Drop oldest unknown BSS table entries first. This makes it less likely to hit connection issues in environments with huge number of visible APs. * Add systemd support. * Add support for setting the syslog facility from the config file at build time. * atheros: Add support for IEEE 802.11w configuration. * AP mode: Allow enable HT20 if driver supports it, by setting the config parameter ieee80211n. * Allow AP mode to disconnect STAs based on low ACK condition (when the data connection is not working properly, e.g., due to the STA going outside the range of the AP). Disabled by default, enable by config option disassoc_low_ack. * nl80211: - Support GTK rekey offload. - Support PMKSA candidate events. This adds support for RSN pre-authentication with nl80211 interface and drivers that handle roaming internally. * dbus: - Add a DBus signal for EAP SM requests, emitted on the Interface object. - Export max scan ssids supported by the driver as MaxScanSSID. - Add signal Certification for information about server certification. - Add BSSExpireAge and BSSExpireCount interface properties and support set/get, which allows for setting BSS cache expiration age and expiration scan count. - Add ConfigFile to AddInterface properties. - Add Interface.Country property and support to get/set the value. - Add DBus property CurrentAuthMode. - P2P DBus API added. - Emit property changed events (for property BSSs) when adding/ removing BSSs. - Treat '' in SSIDs of Interface.Scan as a request for broadcast scan, instead of ignoring it. - Add DBus getter/setter for FastReauth. - Raise PropertiesChanged on org.freedesktop.DBus.Properties. * wpa_cli: - Send AP-STA-DISCONNECTED event when an AP disconnects a station due to inactivity. - Make second argument to set command optional. This can be used to indicate a zero length value. - Add signal_poll command. - Add bss_expire_age and bss_expire_count commands to set/get BSS cache expiration age and expiration scan count. - Add ability to set scan interval (the time in seconds wpa_s waits before requesting a new scan after failing to find a suitable network in scan results) using scan_interval command. - Add event CTRL-EVENT-ASSOC-REJECT for association rejected. - Add command get version, that returns wpa_supplicant version string. - Add command sta_autoconnect for disabling automatic reconnection on receiving disconnection event. - Setting bssid parameter to an empty string "" or any can now be used to clear the bssid_set flag in a network block, i.e., to remove bssid filtering. - Add tdls_testing command to add a special testing feature for changing TDLS behavior. Build param CONFIG_TDLS_TESTING must be enabled as well. - For interworking, add wpa_cli commands interworking_select, interworking_connect, anqp_get, fetch_anqp, and stop_fetch_anqp. - Many P2P commands were added. See README-P2P. - Many WPS/WPS ER commands - see WPS/WPS ER sections for details. - Allow set command to change global config parameters. - Add log_level command, which can be used to display the current debugging level and to change the log level during run time. - Add note command, which can be used to insert notes to the debug log. - Add internal line edit implementation. CONFIG_WPA_CLI_EDIT=y can now be used to build wpa_cli with internal implementation of line editing and history support. This can be used as a replacement for CONFIG_READLINE=y. * AP mode: Add max_num_sta config option, which can be used to limit the number of stations allowed to connect to the AP. * Add WPA_IGNORE_CONFIG_ERRORS build option to continue in case of bad config file. * wext: Increase scan timeout from 5 to 10 seconds. * Add blacklist command, allowing an external program to manage the BSS blacklist and display its current contents. * WPS: - Add wpa_cli wps_pin get command for generating random PINs. This can be used in a UI to generate a PIN without starting WPS (or P2P) operation. - Set RF bands based on driver capabilities, instead of hardcoding them. - Add mechanism for indicating non-standard WPS errors. - Add CONFIG_WPS_REG_DISABLE_OPEN=y option to disable open networks by default. - Add wps_ap_pin cli command for wpa_supplicant AP mode. - Add wps_check_pin cli command for processing PIN from user input. UIs can use this command to process a PIN entered by a user and to validate the checksum digit (if present). - Cancel WPS operation on PBC session overlap detection. - New wps_cancel command in wpa_cli will cancel a pending WPS operation. - wpa_cli action: Add WPS_EVENT_SUCCESS and WPS_EVENT_FAIL handlers. - Trigger WPS config update on Manufacturer, Model Name, Model Number, and Serial Number changes. - Fragment size is now configurable for EAP-WSC peer. Use wpa_cli set wps_fragment_size . - Disable AP PIN after 10 consecutive failures. Slow down attacks on failures up to 10. - Allow AP to start in Enrollee mode without AP PIN for probing, to be compatible with Windows 7. - Add Config Error into WPS-FAIL events to provide more info to the user on how to resolve the issue. - Label and Display config methods are not allowed to be enabled at the same time, since it is unclear which PIN to use if both methods are advertised. - When controlling multiple interfaces: - apply WPS commands to all interfaces configured to use WPS - apply WPS config changes to all interfaces that use WPS - when an attack is detected on any interface, disable AP PIN on all interfaces * WPS ER: - Add special AP Setup Locked mode to allow read only ER. ap_setup_locked=2 can now be used to enable a special mode where WPS ER can learn the current AP settings, but cannot change them. - Show SetSelectedRegistrar events as ctrl_iface events - Add wps_er_set_config to enroll a network based on a local network configuration block instead of having to (re-)learn the current AP settings with wps_er_learn. - Allow AP filtering based on IP address, add ctrl_iface event for learned AP settings, add wps_er_config command to configure an AP. * WPS 2.0: Add support for WPS 2.0 (CONFIG_WPS2) - Add build option CONFIG_WPS_EXTENSIBILITY_TESTING to enable tool for testing protocol extensibility. - Add build option CONFIG_WPS_STRICT to allow disabling of WPS workarounds. - Add support for AuthorizedMACs attribute. * TDLS: - Propogate TDLS related nl80211 capability flags from kernel and add them as driver capability flags. If the driver doesn't support capabilities, assume TDLS is supported internally. When TDLS is explicitly not supported, disable all user facing TDLS operations. - Allow TDLS to be disabled at runtime (mostly for testing). Use set tdls_disabled. - Honor AP TDLS settings that prohibit/allow TDLS. - Add a special testing feature for changing TDLS behavior. Use CONFIG_TDLS_TESTING build param to enable. Configure at runtime with tdls_testing cli command. - Add support for TDLS 802.11z. * wlantest: Add a tool wlantest for IEEE802.11 protocol testing. wlantest can be used to capture frames from a monitor interface for realtime capturing or from pcap files for offline analysis. * Interworking: Support added for 802.11u. Enable in .config with CONFIG_INTERWORKING. See wpa_supplicant.conf for config parameters for interworking. wpa_cli commands added to support this are interworking_select, interworking_connect, anqp_get, fetch_anqp, and stop_fetch_anqp. * Android: Add build and runtime support for Android wpa_supplicant. * bgscan learn: Add new bgscan that learns BSS information based on previous scans, and uses that information to dynamically generate the list of channels for background scans. * Add a new debug message level for excessive information. Use -ddd to enable. * TLS: Add support for tls_disable_time_checks=1 in client mode. * Internal TLS: - Add support for TLS v1.1 (RFC 4346). Enable with build parameter CONFIG_TLSV11. - Add domainComponent parser for X.509 names. * Linux: Add RFKill support by adding an interface state "disabled". * Reorder some IEs to get closer to IEEE 802.11 standard. Move WMM into end of Beacon, Probe Resp and (Re)Assoc Resp frames. Move HT IEs to be later in (Re)Assoc Resp. * Solaris: Add support for wired 802.1X client. * Wi-Fi Direct support. See README-P2P for more information. * Many bugfixes. 2010-04-18 - v0.7.2 * nl80211: fixed number of issues with roaming * avoid unnecessary roaming if multiple APs with similar signal strength are present in scan results * add TLS client events and server probing to ease design of automatic detection of EAP parameters * add option for server certificate matching (SHA256 hash of the certificate) instead of trusted CA certificate configuration * bsd: Cleaned up driver wrapper and added various low-level configuration options * wpa_gui-qt4: do not show too frequent WPS AP available events as tray messages * TNC: fixed issues with fragmentation * EAP-TNC: add Flags field into fragment acknowledgement (needed to interoperate with other implementations; may potentially breaks compatibility with older wpa_supplicant/hostapd versions) * wpa_cli: added option for using a separate process to receive event messages to reduce latency in showing these (CFLAGS += -DCONFIG_WPA_CLI_FORK=y in .config to enable this) * maximum BSS table size can now be configured (bss_max_count) * BSSes to be included in the BSS table can be filtered based on configured SSIDs to save memory (filter_ssids) * fix number of issues with IEEE 802.11r/FT; this version is not backwards compatible with old versions * nl80211: add support for IEEE 802.11r/FT protocol (both over-the-air and over-the-DS) * add freq_list network configuration parameter to allow the AP selection to filter out entries based on the operating channel * add signal strength change events for bgscan; this allows more dynamic changes to background scanning interval based on changes in the signal strength with the current AP; this improves roaming within ESS quite a bit, e.g., with bgscan="simple:30:-45:300" in the network configuration block to request background scans less frequently when signal strength remains good and to automatically trigger background scans whenever signal strength drops noticeably (this is currently only available with nl80211) * add BSSID and reason code (if available) to disconnect event messages * wpa_gui-qt4: more complete support for translating the GUI with linguist and add German translation * fix DH padding with internal crypto code (mainly, for WPS) * do not trigger initial scan automatically anymore if there are no enabled networks 2010-01-16 - v0.7.1 * cleaned up driver wrapper API (struct wpa_driver_ops); the new API is not fully backwards compatible, so out-of-tree driver wrappers will need modifications * cleaned up various module interfaces * merge hostapd and wpa_supplicant developers' documentation into a single document * nl80211: use explicit deauthentication to clear cfg80211 state to avoid issues when roaming between APs * dbus: major design changes in the new D-Bus API (fi.w1.wpa_supplicant1) * nl80211: added support for IBSS networks * added internal debugging mechanism with backtrace support and memory allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y) * added WPS ER unsubscription command to more cleanly unregister from receiving UPnP events when ER is terminated * cleaned up AP mode operations to avoid need for virtual driver_ops wrapper * added BSS table to maintain more complete scan result information over multiple scans (that may include only partial results) * wpa_gui-qt4: update Peers dialog information more dynamically while the dialog is kept open * fixed PKCS#12 use with OpenSSL 1.0.0 * driver_wext: Added cfg80211-specific optimization to avoid some unnecessary scans and to speed up association 2009-11-21 - v0.7.0 * increased wpa_cli ping interval to 5 seconds and made this configurable with a new command line options (-G) * fixed scan buffer processing with WEXT to handle up to 65535 byte result buffer (previously, limited to 32768 bytes) * allow multiple driver wrappers to be specified on command line (e.g., -Dnl80211,wext); the first one that is able to initialize the interface will be used * added support for multiple SSIDs per scan request to optimize scan_ssid=1 operations in ap_scan=1 mode (i.e., search for hidden SSIDs); this requires driver support and can currently be used only with nl80211 * added support for WPS USBA out-of-band mechanism with USB Flash Drives (UFD) (CONFIG_WPS_UFD=y) * driver_ndis: add PAE group address to the multicast address list to fix wired IEEE 802.1X authentication * fixed IEEE 802.11r key derivation function to match with the standard (note: this breaks interoperability with previous version) [Bug 303] * added better support for drivers that allow separate authentication and association commands (e.g., mac80211-based Linux drivers with nl80211; SME in wpa_supplicant); this allows over-the-air FT protocol to be used (IEEE 802.11r) * fixed SHA-256 based key derivation function to match with the standard when using CCMP (for IEEE 802.11r and IEEE 802.11w) (note: this breaks interoperability with previous version) [Bug 307] * use shared driver wrapper files with hostapd * added AP mode functionality (CONFIG_AP=y) with mode=2 in the network block; this can be used for open and WPA2-Personal networks (optionally, with WPS); this links in parts of hostapd functionality into wpa_supplicant * wpa_gui-qt4: added new Peers dialog to show information about peers (other devices, including APs and stations, etc. in the neighborhood) * added support for WPS External Registrar functionality (configure APs and enroll new devices); can be used with wpa_gui-qt4 Peers dialog and wpa_cli commands wps_er_start, wps_er_stop, wps_er_pin, wps_er_pbc, wps_er_learn (this can also be used with a new 'none' driver wrapper if no wireless device or IEEE 802.1X on wired is needed) * driver_nl80211: multiple updates to provide support for new Linux nl80211/mac80211 functionality * updated management frame protection to use IEEE Std 802.11w-2009 * fixed number of small WPS issues and added workarounds to interoperate with common deployed broken implementations * added support for NFC out-of-band mechanism with WPS * driver_ndis: fixed wired IEEE 802.1X authentication with PAE group address frames * added preliminary support for IEEE 802.11r RIC processing * added support for specifying subset of enabled frequencies to scan (scan_freq option in the network configuration block); this can speed up scanning process considerably if it is known that only a small subset of channels is actually used in the network (this is currently supported only with -Dnl80211) * added a workaround for race condition between receiving the association event and the following EAPOL-Key * added background scan and roaming infrastructure to allow network-specific optimizations to be used to improve roaming within an ESS (same SSID) * added new DBus interface (fi.w1.wpa_supplicant1) 2009-01-06 - v0.6.7 * added support for Wi-Fi Protected Setup (WPS) (wpa_supplicant can now be configured to act as a WPS Enrollee to enroll credentials for a network using PIN and PBC methods; in addition, wpa_supplicant can act as a wireless WPS Registrar to configure an AP); WPS support can be enabled by adding CONFIG_WPS=y into .config and setting the runtime configuration variables in wpa_supplicant.conf (see WPS section in the example configuration file); new wpa_cli commands wps_pin, wps_pbc, and wps_reg are used to manage WPS negotiation; see README-WPS for more details * added support for EAP-AKA' (draft-arkko-eap-aka-kdf) * added support for using driver_test over UDP socket * fixed PEAPv0 Cryptobinding interoperability issue with Windows Server 2008 NPS; optional cryptobinding is now enabled (again) by default * fixed PSK editing in wpa_gui * changed EAP-GPSK to use the IANA assigned EAP method type 51 * added a Windows installer that includes WinPcap and all the needed DLLs; in addition, it set up the registry automatically so that user will only need start wpa_gui to get prompted to start the wpasvc servide and add a new interface if needed through wpa_gui dialog * updated management frame protection to use IEEE 802.11w/D7.0 2008-11-23 - v0.6.6 * added Milenage SIM/USIM emulator for EAP-SIM/EAP-AKA (can be used to simulate test SIM/USIM card with a known private key; enable with CONFIG_SIM_SIMULATOR=y/CONFIG_USIM_SIMULATOR=y in .config and password="Ki:OPc"/password="Ki:OPc:SQN" in network configuration) * added a new network configuration option, wpa_ptk_rekey, that can be used to enforce frequent PTK rekeying, e.g., to mitigate some attacks against TKIP deficiencies * added an optional mitigation mechanism for certain attacks against TKIP by delaying Michael MIC error reports by a random amount of time between 0 and 60 seconds; this can be enabled with a build option CONFIG_DELAYED_MIC_ERROR_REPORT=y in .config * fixed EAP-AKA to use RES Length field in AT_RES as length in bits, not bytes * updated OpenSSL code for EAP-FAST to use an updated version of the session ticket overriding API that was included into the upstream OpenSSL 0.9.9 tree on 2008-11-15 (no additional OpenSSL patch is needed with that version anymore) * updated userspace MLME instructions to match with the current Linux mac80211 implementation; please also note that this can only be used with driver_nl80211.c (the old code from driver_wext.c was removed) * added support (Linux only) for RoboSwitch chipsets (often found in consumer grade routers); driver interface 'roboswitch' * fixed canceling of PMKSA caching when using drivers that generate RSN IE and refuse to drop PMKIDs that wpa_supplicant does not know about 2008-11-01 - v0.6.5 * added support for SHA-256 as X.509 certificate digest when using the internal X.509/TLSv1 implementation * updated management frame protection to use IEEE 802.11w/D6.0 * added support for using SHA256-based stronger key derivation for WPA2 (IEEE 802.11w) * fixed FT (IEEE 802.11r) authentication after a failed association to use correct FTIE * added support for configuring Phase 2 (inner/tunneled) authentication method with wpa_gui-qt4 2008-08-10 - v0.6.4 * added support for EAP Sequences in EAP-FAST Phase 2 * added support for using TNC with EAP-FAST * added driver_ps3 for the PS3 Linux wireless driver * added support for optional cryptobinding with PEAPv0 * fixed the OpenSSL patches (0.9.8g and 0.9.9) for EAP-FAST to allow fallback to full handshake if server rejects PAC-Opaque * added fragmentation support for EAP-TNC * added support for parsing PKCS #8 formatted private keys into the internal TLS implementation (both PKCS #1 RSA key and PKCS #8 encapsulated RSA key can now be used) * added option of using faster, but larger, routines in the internal LibTomMath (for internal TLS implementation) to speed up DH and RSA calculations (CONFIG_INTERNAL_LIBTOMMATH_FAST=y) * fixed race condition between disassociation event and group key handshake to avoid getting stuck in incorrect state [Bug 261] * fixed opportunistic key caching (proactive_key_caching) 2008-02-22 - v0.6.3 * removed 'nai' and 'eappsk' network configuration variables that were previously used for configuring user identity and key for EAP-PSK, EAP-PAX, EAP-SAKE, and EAP-GPSK. 'identity' field is now used as the replacement for 'nai' (if old configuration used a separate 'identity' value, that would now be configured as 'anonymous_identity'). 'password' field is now used as the replacement for 'eappsk' (it can also be set using hexstring to present random binary data) * removed '-w' command line parameter (wait for interface to be added, if needed); cleaner way of handling this functionality is to use an external mechanism (e.g., hotplug scripts) that start wpa_supplicant when an interface is added * updated FT support to use the latest draft, IEEE 802.11r/D9.0 * added ctrl_iface monitor event (CTRL-EVENT-SCAN-RESULTS) for indicating when new scan results become available * added new ctrl_iface command, BSS, to allow scan results to be fetched without hitting the message size limits (this command can be used to iterate through the scan results one BSS at the time) * fixed EAP-SIM not to include AT_NONCE_MT and AT_SELECTED_VERSION attributes in EAP-SIM Start/Response when using fast reauthentication * fixed EAPOL not to end up in infinite loop when processing dynamic WEP keys with IEEE 802.1X * fixed problems in getting NDIS events from WMI on Windows 2000 2008-01-01 - v0.6.2 * added support for Makefile builds to include debug-log-to-a-file functionality (CONFIG_DEBUG_FILE=y and -f on command line) * fixed EAP-SIM and EAP-AKA message parser to validate attribute lengths properly to avoid potential crash caused by invalid messages * added data structure for storing allocated buffers (struct wpabuf); this does not affect wpa_supplicant usage, but many of the APIs changed and various interfaces (e.g., EAP) is not compatible with old versions * added support for protecting EAP-AKA/Identity messages with AT_CHECKCODE (optional feature in RFC 4187) * added support for protected result indication with AT_RESULT_IND for EAP-SIM and EAP-AKA (phase1="result_ind=1") * added driver_wext workaround for race condition between scanning and association with drivers that take very long time to scan all channels (e.g., madwifi with dual-band cards); wpa_supplicant is now using a longer hardcoded timeout for the scan if the driver supports notifications for scan completion (SIOCGIWSCAN event); this helps, e.g., in cases where wpa_supplicant and madwifi driver ended up in loop where the driver did not even try to associate * stop EAPOL timer tick when no timers are in use in order to reduce power consumption (no need to wake up the process once per second) [Bug 237] * added support for privilege separation (run only minimal part of wpa_supplicant functionality as root and rest as unprivileged, non-root process); see 'Privilege separation' in README for details; this is disabled by default and can be enabled with CONFIG_PRIVSEP=y in .config * changed scan results data structure to include all information elements to make it easier to support new IEs; old get_scan_result() driver_ops is still supported for backwards compatibility (results are converted internally to the new format), but all drivers should start using the new get_scan_results2() to make them more likely to work with new features * Qt4 version of wpa_gui (wpa_gui-qt4 subdirectory) is now native Qt4 application, i.e., it does not require Qt3Support anymore; Windows binary of wpa_gui.exe is now from this directory and only requires QtCore4.dll and QtGui4.dll libraries * updated Windows binary build to use Qt 4.3.3 and made Qt DLLs available as a separate package to make wpa_gui installation easier: http://w1.fi/wpa_supplicant/qt4/wpa_gui-qt433-windows-dll.zip * added support for EAP-IKEv2 (draft-tschofenig-eap-ikev2-15.txt); only shared key/password authentication is supported in this version 2007-11-24 - v0.6.1 * added support for configuring password as NtPasswordHash (16-byte MD4 hash of password) in hash:<32 hex digits> format * added support for fallback from abbreviated TLS handshake to full handshake when using EAP-FAST (e.g., due to an expired PAC-Opaque) * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest draft (draft-ietf-emu-eap-gpsk-07.txt) * added support for drivers that take care of RSN 4-way handshake internally (WPA_DRIVER_FLAGS_4WAY_HANDSHAKE in get_capa flags and WPA_ALG_PMK in set_key) * added an experimental port for Mac OS X (CONFIG_DRIVER_OSX=y in .config); this version supports only ap_scan=2 mode and allow the driver to take care of the 4-way handshake * fixed a buffer overflow in parsing TSF from scan results when using driver_wext.c with a driver that includes the TSF (e.g., iwl4965) [Bug 232] * updated FT support to use the latest draft, IEEE 802.11r/D8.0 * fixed an integer overflow issue in the ASN.1 parser used by the (experimental) internal TLS implementation to avoid a potential buffer read overflow * fixed a race condition with -W option (wait for a control interface monitor before starting) that could have caused the first messages to be lost * added support for processing TNCC-TNCS-Messages to report recommendation (allow/none/isolate) when using TNC [Bug 243] 2007-05-28 - v0.6.0 * added network configuration parameter 'frequency' for setting initial channel for IBSS (adhoc) networks * added experimental IEEE 802.11r/D6.0 support * updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48 * updated EAP-PSK to use the IANA-allocated EAP type 47 * fixed EAP-PAX key derivation * fixed EAP-PSK bit ordering of the Flags field * fixed EAP-PEAP/TTLS/FAST to use the correct EAP identifier in tunnelled identity request (previously, the identifier from the outer method was used, not the tunnelled identifier which could be different) * added support for fragmentation of outer TLS packets during Phase 2 of EAP-PEAP/TTLS/FAST * fixed EAP-TTLS AVP parser processing for too short AVP lengths * added support for EAP-FAST authentication with inner methods that generate MSK (e.g., EAP-MSCHAPv2 that was previously only supported for PAC provisioning) * added support for authenticated EAP-FAST provisioning * added support for configuring maximum number of EAP-FAST PACs to store in a PAC list (fast_max_pac_list_len= in phase1 string) * added support for storing EAP-FAST PACs in binary format (fast_pac_format=binary in phase1 string) * fixed dbus ctrl_iface to validate message interface before dispatching to avoid a possible segfault [Bug 190] * fixed PeerKey key derivation to use the correct PRF label * updated Windows binary build to link against OpenSSL 0.9.8d and added support for EAP-FAST * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest draft (draft-ietf-emu-eap-gpsk-04.txt) * fixed EAP-AKA Notification processing to allow Notification to be processed after AKA Challenge response has been sent * updated to use IEEE 802.11w/D2.0 for management frame protection (still experimental) * fixed EAP-TTLS implementation not to crash on use of freed memory if TLS library initialization fails * added support for EAP-TNC (Trusted Network Connect) (this version implements the EAP-TNC method and EAP-TTLS changes needed to run two methods in sequence (IF-T) and the IF-IMC and IF-TNCCS interfaces from TNCC) 2006-11-24 - v0.5.6 * added experimental, integrated TLSv1 client implementation with the needed X.509/ASN.1/RSA/bignum processing (this can be enabled by setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in .config); this can be useful, e.g., if the target system does not have a suitable TLS library and a minimal code size is required (total size of this internal TLS/crypto code is bit under 50 kB on x86 and the crypto code is shared by rest of the supplicant so some of it was already required; TLSv1/X.509/ASN.1/RSA added about 25 kB) * removed STAKey handshake since PeerKey handshake has replaced it in IEEE 802.11ma and there are no known deployments of STAKey * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest draft (draft-ietf-emu-eap-gpsk-01.txt) * added preliminary implementation of IEEE 802.11w/D1.0 (management frame protection) (Note: this requires driver support to work properly.) (Note2: IEEE 802.11w is an unapproved draft and subject to change.) * fixed Windows named pipes ctrl_iface to not stop listening for commands if client program opens a named pipe and closes it immediately without sending a command * fixed USIM PIN status determination for the case that PIN is not needed (this allows EAP-AKA to be used with USIM cards that do not use PIN) * added support for reading 3G USIM AID from EF_DIR to allow EAP-AKA to be used with cards that do not support file selection based on partial AID * added support for matching the subjectAltName of the authentication server certificate against multiple name components (e.g., altsubject_match="DNS:server.example.com;DNS:server2.example.com") * fixed EAP-SIM/AKA key derivation for re-authentication case (only affects IEEE 802.1X with dynamic WEP keys) * changed ctrl_iface network configuration 'get' operations to not return password/key material; if these fields are requested, "*" will be returned if the password/key is set, but the value of the parameter is not exposed 2006-08-27 - v0.5.5 * added support for building Windows version with UNICODE defined (wide-char functions) * driver_ndis: fixed static WEP configuration to avoid race condition issues with some NDIS drivers between association and setting WEP keys * driver_ndis: added validation for IELength value in scan results to avoid crashes when using buggy NDIS drivers [Bug 165] * fixed Release|Win32 target in the Visual Studio project files (previously, only Debug|Win32 target was set properly) * changed control interface API call wpa_ctrl_pending() to allow it to return -1 on error (e.g., connection lost); control interface clients will need to make sure that they verify that the value is indeed >0 when determining whether there are pending messages * added an alternative control interface backend for Windows targets: Named Pipe (CONFIG_CTRL_IFACE=named_pipe); this is now the default control interface mechanism for Windows builds (previously, UDP to localhost was used) * changed ctrl_interface configuration for UNIX domain sockets: - deprecated ctrl_interface_group variable (it may be removed in future versions) - allow both directory and group be configured with ctrl_interface in following format: DIR=/var/run/wpa_supplicant GROUP=wheel - ctrl_interface=/var/run/wpa_supplicant is still supported for the case when group is not changed * added support for controlling more than one interface per process in Windows version * added a workaround for a case where the AP is using unknown address (e.g., MAC address of the wired interface) as the source address for EAPOL-Key frames; previously, that source address was used as the destination for EAPOL-Key frames and in key derivation; now, BSSID is used even if the source address does not match with it (this resolves an interoperability issue with Thomson SpeedTouch 580) * added a workaround for UDP-based control interface (which was used in Windows builds before this release) to prevent packets with forged addresses from being accepted as local control requests * removed ndis_events.cpp and possibility of using external ndis_events.exe; C version (ndis_events.c) is fully functional and there is no desire to maintain two separate versions of this implementation * ndis_events: Changed NDIS event notification design to use WMI to learn the adapter description through Win32_PnPEntity class; this should fix some cases where the adapter name was not recognized correctly (e.g., with some USB WLAN adapters, e.g., Ralink RT2500 USB) [Bug 113] * fixed selection of the first network in ap_scan=2 mode; previously, wpa_supplicant could get stuck in SCANNING state when only the first network for enabled (e.g., after 'wpa_cli select_network 0') * winsvc: added support for configuring ctrl_interface parameters in registry (ctrl_interface string value in HKLM\SOFTWARE\wpa_supplicant\interfaces\0000 key); this new value is required to enable control interface (previously, this was hardcoded to be enabled) * allow wpa_gui subdirectory to be built with both Qt3 and Qt4 * converted wpa_gui-qt4 subdirectory to use Qt4 specific project format 2006-06-20 - v0.5.4 * fixed build with CONFIG_STAKEY=y [Bug 143] * added support for doing MLME (IEEE 802.11 management frame processing) in wpa_supplicant when using Devicescape IEEE 802.11 stack (wireless-dev.git tree) * added a new network block configuration option, fragment_size, to configure the maximum EAP fragment size * driver_ndis: Disable WZC automatically for the selected interface to avoid conflicts with two programs trying to control the radio; WZC will be re-enabled (if it was enabled originally) when wpa_supplicant is terminated * added an experimental TLSv1 client implementation (CONFIG_TLS=internal) that can be used instead of an external TLS library, e.g., to reduce total size requirement on systems that do not include any TLS library by default (this is not yet complete; basic functionality is there, but certificate validation is not yet included) * added PeerKey handshake implementation for IEEE 802.11e direct link setup (DLS) to replace STAKey handshake * fixed WPA PSK update through ctrl_iface for the case where the old PSK was derived from an ASCII passphrase and the new PSK is set as a raw PSK (hex string) * added new configuration option for identifying which network block was used (id_str in wpa_supplicant.conf; included on WPA_EVENT_CONNECT monitor event and as WPA_ID_STR environmental variable in wpa_cli action scripts; in addition WPA_ID variable is set to the current unique identifier that wpa_supplicant assigned automatically for the network and that can be used with GET_NETWORK/SET_NETWORK ctrl_iface commands) * wpa_cli action script is now called only when the connect/disconnect status changes or when associating with a different network * fixed configuration parser not to remove CCMP from group cipher list if WPA-None (adhoc) is used (pairwise=NONE in that case) * fixed integrated NDIS events processing not to hang the process due to a missed change in eloop_win.c API in v0.5.3 [Bug 155] * added support for EAP Generalized Pre-Shared Key (EAP-GPSK, draft-clancy-emu-eap-shared-secret-00.txt) * added Microsoft Visual Studio 2005 solution and project files for build wpa_supplicant for Windows (see vs2005 subdirectory) * eloop_win: fixed unregistration of Windows events * l2_packet_winpcap: fixed a deadlock in deinitializing l2_packet at the end of RSN pre-authentication and added unregistration of a Windows event to avoid getting eloop_win stuck with an invalid handle * driver_ndis: added support for selecting AP based on BSSID * added new environmental variable for wpa_cli action scripts: WPA_CTRL_DIR is the current control interface directory * driver_ndis: added support for using NDISUIO instead of WinPcap for OID set/query operations (CONFIG_USE_NDISUIO=y in .config); with new l2_packet_ndis (CONFIG_L2_PACKET=ndis), this can be used to build wpa_supplicant without requiring WinPcap; note that using NDISUIO requires that WZC is disabled (net stop wzcsvc) since NDISUIO allows only one application to open the device * changed NDIS driver naming to only include device GUID, e.g., {7EE3EFE5-C165-472F-986D-F6FBEDFE8C8D}, instead of including WinPcap specific \Device\NPF_ prefix before the GUID; the prefix is still allowed for backwards compatibility, but it is not required anymore when specifying the interface * driver_ndis: re-initialize driver interface is the adapter is removed and re-inserted [Bug 159] * driver_madwifi: fixed TKIP and CCMP sequence number configuration on big endian hosts [Bug 146] 2006-04-27 - v0.5.3 * fixed EAP-GTC response to include correct user identity when run as phase 2 method of EAP-FAST (i.e., EAP-FAST did not work in v0.5.2) * driver_ndis: Fixed encryption mode configuration for unencrypted networks (some NDIS drivers ignored this, but others, e.g., Broadcom, refused to associate with open networks) [Bug 106] * driver_ndis: use BSSID OID polling to detect when IBSS network is formed even when ndis_events code is included since some NDIS drivers do not generate media connect events in IBSS mode * config_winreg: allow global ctrl_interface parameter to be configured in Windows registry * config_winreg: added support for saving configuration data into Windows registry * added support for controlling network device operational state (dormant/up) for Linux 2.6.17 to improve DHCP processing (see http://www.flamewarmaster.de/software/dhcpclient/ for a DHCP client that can use this information) * driver_wext: added support for WE-21 change to SSID configuration * driver_wext: fixed privacy configuration for static WEP keys mode [Bug 140] * added an optional driver_ops callback for MLME-SETPROTECTION.request primitive * added support for EAP-SAKE (no EAP method number allocated yet, so this is using the same experimental type 255 as EAP-PSK) * added support for dynamically loading EAP methods (.so files) instead of requiring them to be statically linked in; this is disabled by default (see CONFIG_DYNAMIC_EAP_METHODS in defconfig for information on how to use this) 2006-03-19 - v0.5.2 * do not try to use USIM APDUs when initializing PC/SC for SIM card access for a network that has not enabled EAP-AKA * fixed EAP phase 2 Nak for EAP-{PEAP,TTLS,FAST} (this was broken in v0.5.1 due to the new support for expanded EAP types) * added support for generating EAP Expanded Nak * try to fetch scan results once before requesting new scan when starting up in ap_scan=1 mode (this can speed up initial association a lot with, e.g., madwifi-ng driver) * added support for receiving EAPOL frames from a Linux bridge interface (-bbr0 on command line) * fixed EAPOL re-authentication for sessions that used PMKSA caching * changed EAP method registration to use a dynamic list of methods instead of a static list generated at build time * fixed PMKSA cache deinitialization not to use freed memory when removing PMKSA entries * fixed a memory leak in EAP-TTLS re-authentication * reject WPA/WPA2 message 3/4 if it does not include any valid WPA/RSN IE * driver_wext: added fallback to use SIOCSIWENCODE for setting auth_alg if the driver does not support SIOCSIWAUTH 2006-01-29 - v0.5.1 * driver_test: added better support for multiple APs and STAs by using a directory with sockets that include MAC address for each device in the name (driver_param=test_dir=/tmp/test) * added support for EAP expanded type (vendor specific EAP methods) * added AP_SCAN command into ctrl_iface so that ap_scan configuration option can be changed if needed * wpa_cli/wpa_gui: skip non-socket files in control directory when using UNIX domain sockets; this avoids selecting an incorrect interface (e.g., a PID file could be in this directory, even though use of this directory for something else than socket files is not recommended) * fixed TLS library deinitialization after RSN pre-authentication not to disable TLS library for normal authentication * driver_wext: Remove null-termination from SSID length if the driver used it; some Linux drivers do this and they were causing problems in wpa_supplicant not finding matching configuration block. This change would break a case where the SSID actually ends in '\0', but that is not likely to happen in real use. * fixed PMKSA cache processing not to trigger deauthentication if the current PMKSA cache entry is replaced with a valid new entry * fixed PC/SC initialization for ap_scan != 1 modes (this fixes EAP-SIM and EAP-AKA with real SIM/USIM card when using ap_scan=0 or ap_scan=2) 2005-12-18 - v0.5.0 (beginning of 0.5.x development releases) * added experimental STAKey handshake implementation for IEEE 802.11e direct link setup (DLS); note: this is disabled by default in both build and runtime configuration (can be enabled with CONFIG_STAKEY=y and stakey=1) * fixed EAP-SIM and EAP-AKA pseudonym and fast re-authentication to decrypt AT_ENCR_DATA attributes correctly * fixed EAP-AKA to allow resynchronization within the same session * made code closer to ANSI C89 standard to make it easier to port to other C libraries and compilers * started moving operating system or C library specific functions into wrapper functions defined in os.h and implemented in os_*.c to make code more portable * wpa_supplicant can now be built with Microsoft Visual C++ (e.g., with the freely available Toolkit 2003 version or Visual C++ 2005 Express Edition and Platform SDK); see nmake.mak for an example makefile for nmake * added support for using Windows registry for command line parameters (CONFIG_MAIN=main_winsvc) and configuration data (CONFIG_BACKEND=winreg); see win_example.reg for an example registry contents; this version can be run both as a Windows service and as a normal application; 'wpasvc.exe app' to start as applicant, 'wpasvc.exe reg ' to register a service, 'net start wpasvc' to start the service, 'wpasvc.exe unreg' to unregister a service * made it possible to link ndis_events.exe functionality into wpa_supplicant.exe by defining CONFIG_NDIS_EVENTS_INTEGRATED * added better support for multiple control interface backends (CONFIG_CTRL_IFACE option); currently, 'unix' and 'udp' are supported * fixed PC/SC code to use correct length for GSM AUTH command buffer and to not use pioRecvPci with SCardTransmit() calls; these were not causing visible problems with pcsc-lite, but Windows Winscard.dll refused the previously used parameters; this fixes EAP-SIM and EAP-AKA authentication using SIM/USIM card under Windows * added new event loop implementation for Windows using WaitForMultipleObject() instead of select() in order to allow waiting for non-socket objects; this can be selected with CONFIG_ELOOP=eloop_win in .config * added support for selecting l2_packet implementation in .config (CONFIG_L2_PACKET; following options are available now: linux, pcap, winpcap, freebsd, none) * added new l2_packet implementation for WinPcap (CONFIG_L2_PACKET=winpcap) that uses a separate receive thread to reduce latency in EAPOL receive processing from about 100 ms to about 3 ms * added support for EAP-FAST key derivation using other ciphers than RC4-128-SHA for authentication and AES128-SHA for provisioning * added support for configuring CA certificate as DER file and as a configuration blob * fixed private key configuration as configuration blob and added support for using PKCS#12 as a blob * tls_gnutls: added support for using PKCS#12 files; added support for session resumption * added support for loading trusted CA certificates from Windows certificate store: ca_cert="cert_store://", where is likely CA (Intermediate CA certificates) or ROOT (root certificates) * added C version of ndis_events.cpp and made it possible to build this with MinGW so that CONFIG_NDIS_EVENTS_INTEGRATED can be used more easily on cross-compilation builds * added wpasvc.exe into Windows binary release; this is an alternative version of wpa_supplicant.exe with configuration backend using Windows registry and with the entry point designed to run as a Windows service * integrated ndis_events.exe functionality into wpa_supplicant.exe and wpasvc.exe and removed this additional tool from the Windows binary release since it is not needed anymore * load winscard.dll functions dynamically when building with MinGW since MinGW does not yet include winscard library 2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases) * l2_packet_pcap: fixed wired IEEE 802.1X authentication with libpcap and WinPcap to receive frames sent to PAE group address * disable EAP state machine when IEEE 802.1X authentication is not used in order to get rid of bogus "EAP failed" messages * fixed OpenSSL error reporting to go through all pending errors to avoid confusing reports of old errors being reported at later point during handshake * fixed configuration file updating to not write empty variables (e.g., proto or key_mgmt) that the file parser would not accept * fixed ADD_NETWORK ctrl_iface command to use the same default values for variables as empty network definitions read from config file would get * fixed EAP state machine to not discard EAP-Failure messages in many cases (e.g., during TLS handshake) * fixed a infinite loop in private key reading if the configured file cannot be parsed successfully * driver_madwifi: added support for madwifi-ng * wpa_gui: do not display password/PSK field contents * wpa_gui: added CA certificate configuration * driver_ndis: fixed scan request in ap_scan=2 mode not to change SSID * driver_ndis: include Beacon IEs in AssocInfo in order to notice if the new AP is using different WPA/RSN IE * use longer timeout for IEEE 802.11 association to avoid problems with drivers that may take more than five second to associate 2005-10-27 - v0.4.6 * allow fallback to WPA, if mixed WPA+WPA2 networks have mismatch in RSN IE, but WPA IE would match with wpa_supplicant configuration * added support for named configuration blobs in order to avoid having to use file system for external files (e.g., certificates); variables can be set to "blob://" instead of file path to use a named blob; supported fields: pac_file, client_cert, private_key * fixed RSN pre-authentication (it was broken in the clean up of WPA state machine interface in v0.4.5) * driver_madwifi: set IEEE80211_KEY_GROUP flag for group keys to make sure the driver configures broadcast decryption correctly * added ca_path (and ca_path2) configuration variables that can be used to configure OpenSSL CA path, e.g., /etc/ssl/certs, for using the system-wide trusted CA list * added support for starting wpa_supplicant without a configuration file (-C argument must be used to set ctrl_interface parameter for this case; in addition, -p argument can be used to provide driver_param; these new arguments can also be used with a configuration to override the values from the configuration) * added global control interface that can be optionally used for adding and removing network interfaces dynamically (-g command line argument for both wpa_supplicant and wpa_cli) without having to restart wpa_supplicant process * wpa_gui: - try to save configuration whenever something is modified - added WEP key configuration - added possibility to edit the current network configuration * driver_ndis: fixed driver polling not to increase frequency on each received EAPOL frame due to incorrectly cancelled timeout * added simple configuration file examples (in examples subdirectory) * fixed driver_wext.c to filter wireless events based on ifindex to avoid interfaces receiving events from other interfaces * delay sending initial EAPOL-Start couple of seconds to speed up authentication for the most common case of Authenticator starting EAP authentication immediately after association 2005-09-25 - v0.4.5 * added a workaround for clearing keys with ndiswrapper to allow roaming from WPA enabled AP to plaintext one * added docbook documentation (doc/docbook) that can be used to generate, e.g., man pages * l2_packet_linux: use socket type SOCK_DGRAM instead of SOCK_RAW for PF_PACKET in order to prepare for network devices that do not use Ethernet headers (e.g., network stack with native IEEE 802.11 frames) * use receipt of EAPOL-Key frame as a lower layer success indication for EAP state machine to allow recovery from dropped EAP-Success frame * cleaned up internal EAPOL frame processing by not including link layer (Ethernet) header during WPA and EAPOL/EAP processing; this header is added only when transmitted the frame; this makes it easier to use wpa_supplicant on link layers that use different header than Ethernet * updated EAP-PSK to use draft 9 by default since this can now be tested with hostapd; removed support for draft 3, including server_nai configuration option from network blocks * driver_wired: add PAE address to the multicast address list in order to be able to receive EAPOL frames with drivers that do not include these multicast addresses by default * driver_wext: add support for WE-19 * added support for multiple configuration backends (CONFIG_BACKEND option); currently, only 'file' is supported (i.e., the format used in wpa_supplicant.conf) * added support for updating configuration ('wpa_cli save_config'); this is disabled by default and can be enabled with global update_config=1 variable in wpa_supplicant.conf; this allows wpa_cli and wpa_gui to store the configuration changes in a permanent store * added GET_NETWORK ctrl_iface command (e.g., 'wpa_cli get_network 0 ssid') 2005-08-21 - v0.4.4 * replaced OpenSSL patch for EAP-FAST support (openssl-tls-extensions.patch) with a more generic and correct patch (the new patch is not compatible with the previous one, so the OpenSSL library will need to be patched with the new patch in order to be able to build wpa_supplicant with EAP-FAST support) * added support for using Windows certificate store (through CryptoAPI) for client certificate and private key operations (EAP-TLS) (see wpa_supplicant.conf for more information on how to configure this with private_key) * ported wpa_gui to Windows * added Qt4 version of wpa_gui (wpa_gui-qt4 directory); this can be built with the open source version of the Qt4 for Windows * allow non-WPA modes (e.g., IEEE 802.1X with dynamic WEP) to be used with drivers that do not support WPA * ndis_events: fixed Windows 2000 support * added support for enabling/disabling networks from the list of all configured networks ('wpa_cli enable_network ' and 'wpa_cli disable_network ') * added support for adding and removing network from the current configuration ('wpa_cli add_network' and 'wpa_cli remove_network '); added networks are disabled by default and they can be enabled with enable_network command once the configuration is done for the new network; note: configuration file is not yet updated, so these new networks are lost when wpa_supplicant is restarted * added support for setting network configuration parameters through the control interface, for example: wpa_cli set_network 0 ssid "\"my network\"" * fixed parsing of strings that include both " and # within double quoted area (e.g., "start"#end") * added EAP workaround for PEAP session resumption: allow outer, i.e., not tunneled, EAP-Success to terminate session since; this can be disabled with eap_workaround=0 (this was allowed for PEAPv1 before, but now it is also allowed for PEAPv0 since at least one RADIUS authentication server seems to be doing this for PEAPv0, too) * wpa_gui: added preliminary support for adding new networks to the wpa_supplicant configuration (double click on the scan results to open network configuration) 2005-06-26 - v0.4.3 * removed interface for external EAPOL/EAP supplicant (e.g., Xsupplicant), (CONFIG_XSUPPLICANT_IFACE) since it is not required anymore and is unlikely to be used by anyone * driver_ndis: fixed WinPcap 3.0 support * fixed build with CONFIG_DNET_PCAP=y on Linux * l2_packet: moved different implementations into separate files (l2_packet_*.c) 2005-06-12 - v0.4.2 * driver_ipw: updated driver structures to match with ipw2200-1.0.4 (note: ipw2100-1.1.0 is likely to require an update to work with this) * added support for using ap_scan=2 mode with multiple network blocks; wpa_supplicant will go through the networks one by one until the driver reports a successful association; this uses the same order for networks as scan_ssid=1 scans, i.e., the priority field is ignored and the network block order in the file is used instead * fixed a potential issue in RSN pre-authentication ending up using freed memory if pre-authentication times out * added support for matching alternative subject name extensions of the authentication server certificate; new configuration variables altsubject_match and altsubject_match2 * driver_ndis: added support for IEEE 802.1X authentication with wired NDIS drivers * added support for querying private key password (EAP-TLS) through the control interface (wpa_cli/wpa_gui) if one is not included in the configuration file * driver_broadcom: fixed couple of memory leaks in scan result processing * EAP-PAX is now registered as EAP type 46 * fixed EAP-PAX MAC calculation * fixed EAP-PAX CK and ICK key derivation * added support for using password with EAP-PAX (as an alternative to entering key with eappsk); SHA-1 hash of the password will be used as the key in this case * added support for arbitrary driver interface parameters through the configuration file with a new driver_param field; this adds a new driver_ops function set_param() * added possibility to override l2_packet module with driver interface API (new send_eapol handler); this can be used to implement driver specific TX/RX functions for EAPOL frames * fixed ctrl_interface_group processing for the case where gid is entered as a number, not group name * driver_test: added support for testing hostapd with wpa_supplicant by using test driver interface without any kernel drivers or network cards 2005-05-22 - v0.4.1 * driver_madwifi: fixed WPA/WPA2 mode configuration to allow EAPOL packets to be encrypted; this was apparently broken by the changed ioctl order in v0.4.0 * driver_madwifi: added preliminary support for compiling against 'BSD' branch of madwifi CVS tree * added support for EAP-MSCHAPv2 password retries within the same EAP authentication session * added support for password changes with EAP-MSCHAPv2 (used when the password has expired) * added support for reading additional certificates from PKCS#12 files and adding them to the certificate chain * fixed association with IEEE 802.1X (no WPA) when dynamic WEP keys were used * fixed a possible double free in EAP-TTLS fast-reauthentication when identity or password is entered through control interface * display EAP Notification messages to user through control interface with "CTRL-EVENT-EAP-NOTIFICATION" prefix * added GUI version of wpa_cli, wpa_gui; this is not build automatically with 'make'; use 'make wpa_gui' to build (this requires Qt development tools) * added 'disconnect' command to control interface for setting wpa_supplicant in state where it will not associate before 'reassociate' command has been used * added support for selecting a network from the list of all configured networks ('wpa_cli select_network '; this disabled all other networks; to re-enable, 'wpa_cli select_network any') * added support for getting scan results through control interface * added EAP workaround for PEAPv1 session resumption: allow outer, i.e., not tunneled, EAP-Success to terminate session since; this can be disabled with eap_workaround=0 2005-04-25 - v0.4.0 (beginning of 0.4.x development releases) * added a new build time option, CONFIG_NO_STDOUT_DEBUG, that can be used to reduce the size of the wpa_supplicant considerably if debugging code is not needed * fixed EAPOL-Key validation to drop packets with invalid Key Data Length; such frames could have crashed wpa_supplicant due to buffer overflow * added support for wired authentication (IEEE 802.1X on wired Ethernet); driver interface 'wired' * obsoleted set_wpa() handler in the driver interface API (it can be replaced by moving enable/disable functionality into init()/deinit()) (calls to set_wpa() are still present for backwards compatibility, but they may be removed in the future) * driver_madwifi: fixed association in plaintext mode * modified the EAP workaround that accepts EAP-Success with incorrect Identifier to be even less strict about verification in order to interoperate with some authentication servers * added support for sending TLS alerts * added support for 'any' SSID wildcard; if ssid is not configured or is set to an empty string, any SSID will be accepted for non-WPA AP * added support for asking PIN (for SIM) from frontends (e.g., wpa_cli); if a PIN is needed, but not included in the configuration file, a control interface request is sent and EAP processing is delayed until the PIN is available * added support for using external devices (e.g., a smartcard) for private key operations in EAP-TLS (CONFIG_SMARTCARD=y in .config); new wpa_supplicant.conf variables: - global: opensc_engine_path, pkcs11_engine_path, pkcs11_module_path - network: engine, engine_id, key_id * added experimental support for EAP-PAX * added monitor mode for wpa_cli (-a) that allows external commands (e.g., shell scripts) to be run based on wpa_supplicant events, e.g., when authentication has been completed and data connection is ready; other related wpa_cli arguments: -B (run in background), -P (write PID file); wpa_supplicant has a new command line argument (-W) that can be used to make it wait until a control interface command is received in order to avoid missing events * added support for opportunistic WPA2 PMKSA key caching (disabled by default, can be enabled with proactive_key_caching=1) * fixed RSN IE in 4-Way Handshake message 2/4 for the case where Authenticator rejects PMKSA caching attempt and the driver is not using assoc_info events * added -P argument for wpa_supplicant to write the current process id into a file 2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases) * added new phase1 option parameter, include_tls_length=1, to force wpa_supplicant to add TLS Message Length field to all TLS messages even if the packet is not fragmented; this may be needed with some authentication servers * fixed WPA/RSN IE verification in message 3 of 4-Way Handshake when using drivers that take care of AP selection (e.g., when using ap_scan=2) * fixed reprocessing of pending request after ctrl_iface requests for identity/password/otp * fixed ctrl_iface requests for identity/password/otp in Phase 2 of EAP-PEAP and EAP-TTLS * all drivers using driver_wext: set interface up and select Managed mode when starting wpa_supplicant; set interface down when exiting * renamed driver_ipw2100.c to driver_ipw.c since it now supports both ipw2100 and ipw2200; please note that this also changed the configuration variable in .config to CONFIG_DRIVER_IPW 2005-01-24 - v0.3.6 * fixed a busy loop introduced in v0.3.5 for scan result processing when no matching AP is found 2005-01-23 - v0.3.5 * added a workaround for an interoperability issue with a Cisco AP when using WPA2-PSK * fixed non-WPA IEEE 802.1X to use the same authentication timeout as WPA with IEEE 802.1X (i.e., timeout 10 -> 70 sec to allow retransmission of dropped frames) * fixed issues with 64-bit CPUs and SHA1 cleanup in previous version (e.g., segfault when processing EAPOL-Key frames) * fixed EAP workaround and fast reauthentication configuration for RSN pre-authentication; previously these were disabled and pre-authentication would fail if the used authentication server requires EAP workarounds * added support for blacklisting APs that fail or timeout authentication in ap_scan=1 mode so that all APs are tried in cases where the ones with strongest signal level are failing authentication * fixed CA certificate loading after a failed EAP-TLS/PEAP/TTLS authentication attempt * allow EAP-PEAP/TTLS fast reauthentication only if Phase 2 succeeded in the previous authentication (previously, only Phase 1 success was verified) 2005-01-09 - v0.3.4 * added preliminary support for IBSS (ad-hoc) mode configuration (mode=1 in network block); this included a new key_mgmt mode WPA-NONE, i.e., TKIP or CCMP with a fixed key (based on psk) and no key management; see wpa_supplicant.conf for more details and an example on how to configure this (note: this is currently implemented only for driver_hostapd.c, but the changes should be trivial to add in associate() handler for other drivers, too (assuming the driver supports WPA-None) * added preliminary port for native Windows (i.e., no cygwin) using mingw 2005-01-02 - v0.3.3 * added optional support for GNU Readline and History Libraries for wpa_cli (CONFIG_READLINE) * cleaned up EAP state machine <-> method interface and number of small problems with error case processing not terminating on EAP-Failure but waiting for timeout * added couple of workarounds for interoperability issues with a Cisco AP when using WPA2 * added support for EAP-FAST (draft-cam-winget-eap-fast-00.txt); Note: This requires a patch for openssl to add support for TLS extensions and number of workarounds for operations without certificates. Proof of concept type of experimental patch is included in openssl-tls-extensions.patch. 2004-12-19 - v0.3.2 * fixed private key loading for cases where passphrase is not set * fixed Windows/cygwin L2 packet handler freeing; previous version could cause a segfault when RSN pre-authentication was completed * added support for PMKSA caching with drivers that generate RSN IEs (e.g., NDIS); currently, this is only implemented in driver_ndis.c, but similar code can be easily added to driver_ndiswrapper.c once ndiswrapper gets full support for RSN PMKSA caching * improved recovery from PMKID mismatches by requesting full EAP authentication in case of failed PMKSA caching attempt * driver_ndis: added support for NDIS NdisMIncidateStatus() events (this requires that ndis_events is ran while wpa_supplicant is running) * driver_ndis: use ADD_WEP/REMOVE_WEP when configuring WEP keys * added support for driver interfaces to replace the interface name based on driver/OS specific mapping, e.g., in case of driver_ndis, this allows the beginning of the adapter description to be used as the interface name * added support for CR+LF (Windows-style) line ends in configuration file * driver_ndis: enable radio before starting scanning, disable radio when exiting * modified association event handler to set portEnabled = FALSE before clearing port Valid in order to reset EAP state machine and avoid problems with new authentication getting ignored because of state machines ending up in AUTHENTICATED/SUCCESS state based on old information * added support for driver events to add PMKID candidates in order to allow drivers to give priority to most likely roaming candidates * driver_hostap: moved PrivacyInvoked configuration to associate() function so that this will not be set for plaintext connections * added KEY_MGMT_802_1X_NO_WPA as a new key_mgmt type so that driver interface can distinguish plaintext and IEEE 802.1X (no WPA) authentication * fixed static WEP key configuration to use broadcast/default type for all keys (previously, the default TX key was configured as pairwise/ unicast key) * driver_ndis: added legacy WPA capability detection for non-WPA2 drivers * added support for setting static WEP keys for IEEE 802.1X without dynamic WEP keying (eapol_flags=0) 2004-12-12 - v0.3.1 * added support for reading PKCS#12 (PFX) files (as a replacement for PEM/DER) to get certificate and private key (CONFIG_PKCS12) * fixed compilation with CONFIG_PCSC=y * added new ap_scan mode, ap_scan=2, for drivers that take care of association, but need to be configured with security policy and SSID, e.g., ndiswrapper and NDIS driver; this mode should allow such drivers to work with hidden SSIDs and optimized roaming; when ap_scan=2 is used, only the first network block in the configuration file is used and this configuration should have explicit security policy (i.e., only one option in the lists) for key_mgmt, pairwise, group, proto variables * added experimental port of wpa_supplicant for Windows - driver_ndis.c driver interface (NDIS OIDs) - currently, this requires cygwin and WinPcap - small utility, win_if_list, can be used to get interface name * control interface can now be removed at build time; add CONFIG_CTRL_IFACE=y to .config to maintain old functionality * optional Xsupplicant interface can now be removed at build time; (CONFIG_XSUPPLICANT_IFACE=y in .config to bring it back) * added auth_alg to driver interface associate() parameters to make it easier for drivers to configure authentication algorithm as part of the association 2004-12-05 - v0.3.0 (beginning of 0.3.x development releases) * driver_broadcom: added new driver interface for Broadcom wl.o driver (a generic driver for Broadcom IEEE 802.11a/g cards) * wpa_cli: fixed parsing of -p command line argument * PEAPv1: fixed tunneled EAP-Success reply handling to reply with TLS ACK, not tunneled EAP-Success (of which only the first byte was actually send due to a bug in previous code); this seems to interoperate with most RADIUS servers that implements PEAPv1 * PEAPv1: added support for terminating PEAP authentication on tunneled EAP-Success message; this can be configured by adding peap_outer_success=0 on phase1 parameters in wpa_supplicant.conf (some RADIUS servers require this whereas others require a tunneled reply * PEAPv1: changed phase1 option peaplabel to use default to 0, i.e., to the old label for key derivation; previously, the default was 1, but it looks like most existing PEAPv1 implementations use the old label which is thus more suitable default option * added support for EAP-PSK (draft-bersani-eap-psk-03.txt) * fixed parsing of wep_tx_keyidx * added support for configuring list of allowed Phase 2 EAP types (for both EAP-PEAP and EAP-TTLS) instead of only one type * added support for configuring IEEE 802.11 authentication algorithm (auth_alg; mainly for using Shared Key authentication with static WEP keys) * added support for EAP-AKA (with UMTS SIM) * fixed couple of errors in PCSC handling that could have caused random-looking errors for EAP-SIM * added support for EAP-SIM pseudonyms and fast re-authentication * added support for EAP-TLS/PEAP/TTLS fast re-authentication (TLS session resumption) * added support for EAP-SIM with two challanges (phase1="sim_min_num_chal=3" can be used to require three challenges) * added support for configuring DH/DSA parameters for an ephemeral DH key exchange (EAP-TLS/PEAP/TTLS) using new configuration parameters dh_file and dh_file2 (phase 2); this adds support for using DSA keys and optional DH key exchange to achieve forward secracy with RSA keys * added support for matching subject of the authentication server certificate with a substring when using EAP-TLS/PEAP/TTLS; new configuration variables subject_match and subject_match2 * changed SSID configuration in driver_wext.c (used by many driver interfaces) to use ssid_len+1 as the length for SSID since some Linux drivers expect this * fixed couple of unaligned reads in scan result parsing to fix WPA connection on some platforms (e.g., ARM) * added driver interface for Intel ipw2100 driver * added support for LEAP with WPA * added support for larger scan results report (old limit was 4 kB of data, i.e., about 35 or so APs) when using Linux wireless extensions v17 or newer * fixed a bug in PMKSA cache processing: skip sending of EAPOL-Start only if there is a PMKSA cache entry for the current AP * fixed error handling for case where reading of scan results fails: must schedule a new scan or wpa_supplicant will remain waiting forever * changed debug output to remove shared password/key material by default; all key information can be included with -K command line argument to match the previous behavior * added support for timestamping debug log messages (disabled by default, can be enabled with -t command line argument) * set pairwise/group cipher suite for non-WPA IEEE 802.1X to WEP-104 if keys are not configured to be used; this fixes IEEE 802.1X mode with drivers that use this information to configure whether Privacy bit can be in Beacon frames (e.g., ndiswrapper) * avoid clearing driver keys if no keys have been configured since last key clear request; this seems to improve reliability of group key handshake for ndiswrapper & NDIS driver which seems to be suffering of some kind of timing issue when the keys are cleared again after association * changed driver interface API: - WPA_SUPPLICANT_DRIVER_VERSION define can be used to determine which version is being used (now, this is set to 2; previously, it was not defined) - pass pointer to private data structure to all calls - the new API is not backwards compatible; all in-tree driver interfaces has been converted to the new API * added support for controlling multiple interfaces (radios) per wpa_supplicant process; each interface needs to be listed on the command line (-c, -i, -D arguments) with -N as a separator (-cwpa1.conf -iwlan0 -Dhostap -N -cwpa2.conf -iath0 -Dmadwifi) * added a workaround for EAP servers that incorrectly use same Id for sequential EAP packets * changed libpcap/libdnet configuration to use .config variable, CONFIG_DNET_PCAP, instead of requiring Makefile modification * improved downgrade attack detection in IE verification of msg 3/4: verify both WPA and RSN IEs, if present, not only the selected one; reject the AP if an RSN IE is found in msg 3/4, but not in Beacon or Probe Response frame, and RSN is enabled in wpa_supplicant configuration * fixed WPA msg 3/4 processing to allow Key Data field contain other IEs than just one WPA IE * added support for FreeBSD and driver interface for the BSD net80211 layer (CONFIG_DRIVER_BSD=y in .config); please note that some of the required kernel mods have not yet been committed * made EAP workarounds configurable; enabled by default, can be disabled with network block option eap_workaround=0 2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases) * resolved couple of interoperability issues with EAP-PEAPv1 and Phase 2 (inner EAP) fragment reassembly * driver_madwifi: fixed WEP key configuration for IEEE 802.1X when the AP is using non-zero key index for the unicast key and key index zero for the broadcast key * driver_hostap: fixed IEEE 802.1X WEP key updates and re-authentication by allowing unencrypted EAPOL frames when not using WPA * added a new driver interface, 'wext', which uses only standard, driver independent functionality in Linux wireless extensions; currently, this can be used only for non-WPA IEEE 802.1X mode, but eventually, this is to be extended to support full WPA/WPA2 once Linux wireless extensions get support for this * added support for mode in which the driver is responsible for AP scanning and selection; this is disabled by default and can be enabled with global ap_scan=0 variable in wpa_supplicant.conf; this mode can be used, e.g., with generic 'wext' driver interface to use wpa_supplicant as IEEE 802.1X Supplicant with any Linux driver supporting wireless extensions. * driver_madwifi: fixed WPA2 configuration and scan_ssid=1 (e.g., operation with an AP that does not include SSID in the Beacon frames) * added support for new EAP authentication methods: EAP-TTLS/EAP-OTP, EAP-PEAPv0/OTP, EAP-PEAPv1/OTP, EAP-OTP * added support for asking one-time-passwords from frontends (e.g., wpa_cli); this 'otp' command works otherwise like 'password' command, but the password is used only once and the frontend will be asked for a new password whenever a request from authenticator requires a password; this can be used with both EAP-OTP and EAP-GTC * changed wpa_cli to automatically re-establish connection so that it does not need to be re-started when wpa_supplicant is terminated and started again * improved user data (identity/password/otp) requests through frontends: process pending EAPOL packets after getting new information so that full authentication does not need to be restarted; in addition, send pending requests again whenever a new frontend is attached * changed control frontends to use a new directory for socket files to make it easier for wpa_cli to automatically select between interfaces and to provide access control for the control interface; wpa_supplicant.conf: ctrl_interface is now a path (/var/run/wpa_supplicant is the recommended path) and ctrl_interface_group can be used to select which group gets access to the control interface; wpa_cli: by default, try to connect to the first interface available in /var/run/wpa_supplicant; this path can be overriden with -p option and an interface can be selected with -i option (i.e., in most common cases, wpa_cli does not need to get any arguments) * added support for LEAP * added driver interface for Linux ndiswrapper * added priority option for network blocks in the configuration file; this allows networks to be grouped based on priority (the scan results are searched for matches with network blocks in this order) 2004-06-20 - v0.2.3 * sort scan results to improve AP selection * fixed control interface socket removal for some error cases * improved scan requesting and authentication timeout * small improvements/bug fixes for EAP-MSCHAPv2, EAP-PEAP, and TLS processing * PEAP version can now be forced with phase1="peapver=" (mostly for testing; by default, the highest version supported by both the Supplicant and Authentication Server is selected automatically) * added support for madwifi driver (Atheros ar521x) * added a workaround for cases where AP sets Install Tx/Rx bit for WPA Group Key messages when pairwise keys are used (without this, the Group Key would be used for Tx and the AP would drop frames from the station) * added GSM SIM/USIM interface for GSM authentication algorithm for EAP-SIM; this requires pcsc-lite * added support for ATMEL AT76C5XXx driver * fixed IEEE 802.1X WEP key derivation in the case where Authenticator does not include key data in the EAPOL-Key frame (i.e., part of EAP keying material is used as data encryption key) * added support for using plaintext and static WEP networks (key_mgmt=NONE) 2004-05-31 - v0.2.2 * added support for new EAP authentication methods: EAP-TTLS/EAP-MD5-Challenge EAP-TTLS/EAP-GTC EAP-TTLS/EAP-MSCHAPv2 EAP-TTLS/EAP-TLS EAP-TTLS/MSCHAPv2 EAP-TTLS/MSCHAP EAP-TTLS/PAP EAP-TTLS/CHAP EAP-PEAP/TLS EAP-PEAP/GTC EAP-PEAP/MD5-Challenge EAP-GTC EAP-SIM (not yet complete; needs GSM/SIM authentication interface) * added support for anonymous identity (to be used when identity is sent in plaintext; real identity will be used within TLS protected tunnel (e.g., with EAP-TTLS) * added event messages from wpa_supplicant to frontends, e.g., wpa_cli * added support for requesting identity and password information using control interface; in other words, the password for EAP-PEAP or EAP-TTLS does not need to be included in the configuration file since a frontand (e.g., wpa_cli) can ask it from the user * improved RSN pre-authentication to use a candidate list and process all candidates from each scan; not only one per scan * fixed RSN IE and WPA IE capabilities field parsing * ignore Tx bit in GTK IE when Pairwise keys are used * avoid making new scan requests during IEEE 802.1X negotiation * use openssl/libcrypto for MD5 and SHA-1 when compiling wpa_supplicant with TLS support (this replaces the included implementation with library code to save about 8 kB since the library code is needed anyway for TLS) * fixed WPA-PSK only mode when compiled without IEEE 802.1X support (i.e., without CONFIG_IEEE8021X_EAPOL=y in .config) 2004-05-06 - v0.2.1 * added support for internal IEEE 802.1X (actually, IEEE 802.1aa/D6.1) Supplicant - EAPOL state machines for Supplicant [IEEE 802.1aa/D6.1] - EAP peer state machine [draft-ietf-eap-statemachine-02.pdf] - EAP-MD5 (cannot be used with WPA-RADIUS) [draft-ietf-eap-rfc2284bis-09.txt] - EAP-TLS [RFC 2716] - EAP-MSCHAPv2 (currently used only with EAP-PEAP) - EAP-PEAP/MSCHAPv2 [draft-josefsson-pppext-eap-tls-eap-07.txt] [draft-kamath-pppext-eap-mschapv2-00.txt] (PEAP version 0, 1, and parts of 2; only 0 and 1 are enabled by default; tested with FreeRADIUS, Microsoft IAS, and Funk Odyssey) - new configuration file options: eap, identity, password, ca_cert, client_cert, privatekey, private_key_passwd - Xsupplicant is not required anymore, but it can be used by disabling the internal IEEE 802.1X Supplicant with -e command line option - this code is not included in the default build; Makefile need to be edited for this (uncomment lines for selected functionality) - EAP-TLS and EAP-PEAP require openssl libraries * use module prefix in debug messages (WPA, EAP, EAP-TLS, ..) * added support for non-WPA IEEE 802.1X mode with dynamic WEP keys (i.e., complete IEEE 802.1X/EAP authentication and use IEEE 802.1X EAPOL-Key frames instead of WPA key handshakes) * added support for IEEE 802.11i/RSN (WPA2) - improved PTK Key Handshake - PMKSA caching, pre-authentication * fixed wpa_supplicant to ignore possible extra data after WPA EAPOL-Key packets (this fixes 'Invalid EAPOL-Key MIC when using TPTK' error from message 3 of 4-Way Handshake in case the AP includes extra data after the EAPOL-Key) * added interface for external programs (frontends) to control wpa_supplicant - CLI example (wpa_cli) with interactive mode and command line mode - replaced SIGUSR1 status/statistics with the new control interface * made some feature compile time configurable - .config file for make - driver interfaces (hostap, hermes, ..) - EAPOL/EAP functions 2004-02-15 - v0.2.0 * Initial version of wpa_supplicant wpa_supplicant-2.2/wpa_supplicant/dbus/0000775000175000017500000000000012343617166016205 5ustar jmjmwpa_supplicant-2.2/wpa_supplicant/dbus/dbus_new_introspect.c0000664000175000017500000001717212343617166022441 0ustar jmjm/* * wpa_supplicant - D-Bus introspection * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * Copyright (c) 2009, Witold Sowa * Copyright (c) 2010, 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/list.h" #include "utils/wpabuf.h" #include "dbus_common_i.h" #include "dbus_new_helpers.h" struct interfaces { struct dl_list list; char *dbus_interface; struct wpabuf *xml; }; static struct interfaces * add_interface(struct dl_list *list, const char *dbus_interface) { struct interfaces *iface; dl_list_for_each(iface, list, struct interfaces, list) { if (os_strcmp(iface->dbus_interface, dbus_interface) == 0) return iface; /* already in the list */ } iface = os_zalloc(sizeof(struct interfaces)); if (!iface) return NULL; iface->xml = wpabuf_alloc(6000); if (iface->xml == NULL) { os_free(iface); return NULL; } wpabuf_printf(iface->xml, "", dbus_interface); dl_list_add_tail(list, &iface->list); iface->dbus_interface = os_strdup(dbus_interface); return iface; } static void add_arg(struct wpabuf *xml, const char *name, const char *type, const char *direction) { wpabuf_printf(xml, ""); } static void add_entry(struct wpabuf *xml, const char *type, const char *name, const struct wpa_dbus_argument *args, int include_dir) { const struct wpa_dbus_argument *arg; if (args == NULL || args->name == NULL) { wpabuf_printf(xml, "<%s name=\"%s\"/>", type, name); return; } wpabuf_printf(xml, "<%s name=\"%s\">", type, name); for (arg = args; arg && arg->name; arg++) { add_arg(xml, arg->name, arg->type, include_dir ? (arg->dir == ARG_IN ? "in" : "out") : NULL); } wpabuf_printf(xml, "", type); } static void add_property(struct wpabuf *xml, const struct wpa_dbus_property_desc *dsc) { wpabuf_printf(xml, "", dsc->dbus_property, dsc->type, dsc->getter ? "read" : "", dsc->setter ? "write" : ""); } static void extract_interfaces_methods( struct dl_list *list, const struct wpa_dbus_method_desc *methods) { const struct wpa_dbus_method_desc *dsc; struct interfaces *iface; for (dsc = methods; dsc && dsc->dbus_method; dsc++) { iface = add_interface(list, dsc->dbus_interface); if (iface) add_entry(iface->xml, "method", dsc->dbus_method, dsc->args, 1); } } static void extract_interfaces_signals( struct dl_list *list, const struct wpa_dbus_signal_desc *signals) { const struct wpa_dbus_signal_desc *dsc; struct interfaces *iface; for (dsc = signals; dsc && dsc->dbus_signal; dsc++) { iface = add_interface(list, dsc->dbus_interface); if (iface) add_entry(iface->xml, "signal", dsc->dbus_signal, dsc->args, 0); } } static void extract_interfaces_properties( struct dl_list *list, const struct wpa_dbus_property_desc *properties) { const struct wpa_dbus_property_desc *dsc; struct interfaces *iface; for (dsc = properties; dsc && dsc->dbus_property; dsc++) { iface = add_interface(list, dsc->dbus_interface); if (iface) add_property(iface->xml, dsc); } } /** * extract_interfaces - Extract interfaces from methods, signals and props * @list: Interface list to be filled * @obj_dsc: Description of object from which interfaces will be extracted * * Iterates over all methods, signals, and properties registered with an * object and collects all declared DBus interfaces and create interfaces' * node in XML root node for each. Returned list elements contain interface * name and XML node of corresponding interface. */ static void extract_interfaces(struct dl_list *list, struct wpa_dbus_object_desc *obj_dsc) { extract_interfaces_methods(list, obj_dsc->methods); extract_interfaces_signals(list, obj_dsc->signals); extract_interfaces_properties(list, obj_dsc->properties); } static void add_interfaces(struct dl_list *list, struct wpabuf *xml) { struct interfaces *iface, *n; dl_list_for_each_safe(iface, n, list, struct interfaces, list) { if (wpabuf_len(iface->xml) + 20 < wpabuf_tailroom(xml)) { wpabuf_put_buf(xml, iface->xml); wpabuf_put_str(xml, ""); } else { wpa_printf(MSG_DEBUG, "dbus: Not enough room for " "add_interfaces inspect data: tailroom %u, " "add %u", (unsigned int) wpabuf_tailroom(xml), (unsigned int) wpabuf_len(iface->xml)); } dl_list_del(&iface->list); wpabuf_free(iface->xml); os_free(iface->dbus_interface); os_free(iface); } } static void add_child_nodes(struct wpabuf *xml, DBusConnection *con, const char *path) { char **children; int i; /* add child nodes to introspection tree */ dbus_connection_list_registered(con, path, &children); for (i = 0; children[i]; i++) wpabuf_printf(xml, "", children[i]); dbus_free_string_array(children); } static void add_introspectable_interface(struct wpabuf *xml) { wpabuf_printf(xml, "" "" "" "" "", WPA_DBUS_INTROSPECTION_INTERFACE, WPA_DBUS_INTROSPECTION_METHOD); } static void add_properties_interface(struct wpabuf *xml) { wpabuf_printf(xml, "", WPA_DBUS_PROPERTIES_INTERFACE); wpabuf_printf(xml, "", WPA_DBUS_PROPERTIES_GET); add_arg(xml, "interface", "s", "in"); add_arg(xml, "propname", "s", "in"); add_arg(xml, "value", "v", "out"); wpabuf_put_str(xml, ""); wpabuf_printf(xml, "", WPA_DBUS_PROPERTIES_GETALL); add_arg(xml, "interface", "s", "in"); add_arg(xml, "props", "a{sv}", "out"); wpabuf_put_str(xml, ""); wpabuf_printf(xml, "", WPA_DBUS_PROPERTIES_SET); add_arg(xml, "interface", "s", "in"); add_arg(xml, "propname", "s", "in"); add_arg(xml, "value", "v", "in"); wpabuf_put_str(xml, ""); wpabuf_put_str(xml, ""); } static void add_wpas_interfaces(struct wpabuf *xml, struct wpa_dbus_object_desc *obj_dsc) { struct dl_list ifaces; dl_list_init(&ifaces); extract_interfaces(&ifaces, obj_dsc); add_interfaces(&ifaces, xml); } /** * wpa_dbus_introspect - Responds for Introspect calls on object * @message: Message with Introspect call * @obj_dsc: Object description on which Introspect was called * Returns: Message with introspection result XML string as only argument * * Iterates over all methods, signals and properties registered with * object and generates introspection data for the object as XML string. */ DBusMessage * wpa_dbus_introspect(DBusMessage *message, struct wpa_dbus_object_desc *obj_dsc) { DBusMessage *reply; struct wpabuf *xml; xml = wpabuf_alloc(10000); if (xml == NULL) return NULL; wpabuf_put_str(xml, "\n"); wpabuf_put_str(xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE); wpabuf_put_str(xml, ""); add_introspectable_interface(xml); add_properties_interface(xml); add_wpas_interfaces(xml, obj_dsc); add_child_nodes(xml, obj_dsc->connection, dbus_message_get_path(message)); wpabuf_put_str(xml, "\n"); reply = dbus_message_new_method_return(message); if (reply) { const char *intro_str = wpabuf_head(xml); dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str, DBUS_TYPE_INVALID); } wpabuf_free(xml); return reply; } wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_old_handlers.c0000664000175000017500000012047412343617166022034 0ustar jmjm/* * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include #include "common.h" #include "eap_peer/eap_methods.h" #include "common/ieee802_11_defs.h" #include "eapol_supp/eapol_supp_sm.h" #include "rsn_supp/wpa.h" #include "../config.h" #include "../wpa_supplicant_i.h" #include "../driver_i.h" #include "../notify.h" #include "../wpas_glue.h" #include "../bss.h" #include "../scan.h" #include "dbus_old.h" #include "dbus_old_handlers.h" #include "dbus_dict_helpers.h" /** * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message * @message: Pointer to incoming dbus message this error refers to * Returns: a dbus error message * * Convenience function to create and return an invalid options error */ DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message, const char *arg) { DBusMessage *reply; reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS, "Did not receive correct message " "arguments."); if (arg != NULL) dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID); return reply; } /** * wpas_dbus_new_success_reply - Return a new success reply message * @message: Pointer to incoming dbus message this reply refers to * Returns: a dbus message containing a single UINT32 that indicates * success (ie, a value of 1) * * Convenience function to create and return a success reply message */ DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message) { DBusMessage *reply; unsigned int success = 1; reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success, DBUS_TYPE_INVALID); return reply; } /** * wpas_dbus_global_add_interface - Request registration of a network interface * @message: Pointer to incoming dbus message * @global: %wpa_supplicant global data structure * Returns: The object path of the new interface object, * or a dbus error message with more information * * Handler function for "addInterface" method call. Handles requests * by dbus clients to register a network interface that wpa_supplicant * will manage. */ DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message, struct wpa_global *global) { char *ifname = NULL; char *driver = NULL; char *driver_param = NULL; char *confname = NULL; char *bridge_ifname = NULL; DBusMessage *reply = NULL; DBusMessageIter iter; dbus_message_iter_init(message, &iter); /* First argument: interface name (DBUS_TYPE_STRING) * Required; must be non-zero length */ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) goto error; dbus_message_iter_get_basic(&iter, &ifname); if (!os_strlen(ifname)) goto error; /* Second argument: dict of options */ if (dbus_message_iter_next(&iter)) { DBusMessageIter iter_dict; struct wpa_dbus_dict_entry entry; if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto error; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; if (!strcmp(entry.key, "driver") && (entry.type == DBUS_TYPE_STRING)) { driver = os_strdup(entry.str_value); wpa_dbus_dict_entry_clear(&entry); if (driver == NULL) goto error; } else if (!strcmp(entry.key, "driver-params") && (entry.type == DBUS_TYPE_STRING)) { driver_param = os_strdup(entry.str_value); wpa_dbus_dict_entry_clear(&entry); if (driver_param == NULL) goto error; } else if (!strcmp(entry.key, "config-file") && (entry.type == DBUS_TYPE_STRING)) { confname = os_strdup(entry.str_value); wpa_dbus_dict_entry_clear(&entry); if (confname == NULL) goto error; } else if (!strcmp(entry.key, "bridge-ifname") && (entry.type == DBUS_TYPE_STRING)) { bridge_ifname = os_strdup(entry.str_value); wpa_dbus_dict_entry_clear(&entry); if (bridge_ifname == NULL) goto error; } else { wpa_dbus_dict_entry_clear(&entry); goto error; } } } /* * Try to get the wpa_supplicant record for this iface, return * an error if we already control it. */ if (wpa_supplicant_get_iface(global, ifname) != NULL) { reply = dbus_message_new_error(message, WPAS_ERROR_EXISTS_ERROR, "wpa_supplicant already " "controls this interface."); } else { struct wpa_supplicant *wpa_s; struct wpa_interface iface; os_memset(&iface, 0, sizeof(iface)); iface.ifname = ifname; iface.driver = driver; iface.driver_param = driver_param; iface.confname = confname; iface.bridge_ifname = bridge_ifname; /* Otherwise, have wpa_supplicant attach to it. */ if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) { const char *path = wpa_s->dbus_path; reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); } else { reply = dbus_message_new_error(message, WPAS_ERROR_ADD_ERROR, "wpa_supplicant " "couldn't grab this " "interface."); } } out: os_free(driver); os_free(driver_param); os_free(confname); os_free(bridge_ifname); return reply; error: reply = wpas_dbus_new_invalid_opts_error(message, NULL); goto out; } /** * wpas_dbus_global_remove_interface - Request deregistration of an interface * @message: Pointer to incoming dbus message * @global: wpa_supplicant global data structure * Returns: a dbus message containing a UINT32 indicating success (1) or * failure (0), or returns a dbus error message with more information * * Handler function for "removeInterface" method call. Handles requests * by dbus clients to deregister a network interface that wpa_supplicant * currently manages. */ DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message, struct wpa_global *global) { struct wpa_supplicant *wpa_s; char *path; DBusMessage *reply = NULL; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { reply = wpas_dbus_new_invalid_opts_error(message, NULL); goto out; } wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path); if (wpa_s == NULL) { reply = wpas_dbus_new_invalid_iface_error(message); goto out; } if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) { reply = wpas_dbus_new_success_reply(message); } else { reply = dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR, "wpa_supplicant couldn't " "remove this interface."); } out: return reply; } /** * wpas_dbus_global_get_interface - Get the object path for an interface name * @message: Pointer to incoming dbus message * @global: %wpa_supplicant global data structure * Returns: The object path of the interface object, * or a dbus error message with more information * * Handler function for "getInterface" method call. Handles requests * by dbus clients for the object path of an specific network interface. */ DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message, struct wpa_global *global) { DBusMessage *reply = NULL; const char *ifname; const char *path; struct wpa_supplicant *wpa_s; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname, DBUS_TYPE_INVALID)) { reply = wpas_dbus_new_invalid_opts_error(message, NULL); goto out; } wpa_s = wpa_supplicant_get_iface(global, ifname); if (wpa_s == NULL) { reply = wpas_dbus_new_invalid_iface_error(message); goto out; } path = wpa_s->dbus_path; reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); out: return reply; } /** * wpas_dbus_global_set_debugparams- Set the debug params * @message: Pointer to incoming dbus message * @global: %wpa_supplicant global data structure * Returns: a dbus message containing a UINT32 indicating success (1) or * failure (0), or returns a dbus error message with more information * * Handler function for "setDebugParams" method call. Handles requests * by dbus clients for the object path of an specific network interface. */ DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message, struct wpa_global *global) { DBusMessage *reply = NULL; int debug_level; dbus_bool_t debug_timestamp; dbus_bool_t debug_show_keys; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &debug_level, DBUS_TYPE_BOOLEAN, &debug_timestamp, DBUS_TYPE_BOOLEAN, &debug_show_keys, DBUS_TYPE_INVALID)) { return wpas_dbus_new_invalid_opts_error(message, NULL); } if (wpa_supplicant_set_debug_params(global, debug_level, debug_timestamp ? 1 : 0, debug_show_keys ? 1 : 0)) { return wpas_dbus_new_invalid_opts_error(message, NULL); } reply = wpas_dbus_new_success_reply(message); return reply; } /** * wpas_dbus_iface_scan - Request a wireless scan on an interface * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: a dbus message containing a UINT32 indicating success (1) or * failure (0) * * Handler function for "scan" method call of a network device. Requests * that wpa_supplicant perform a wireless scan as soon as possible * on a particular wireless interface. */ DBusMessage * wpas_dbus_iface_scan(DBusMessage *message, struct wpa_supplicant *wpa_s) { wpa_s->scan_req = MANUAL_SCAN_REQ; wpa_supplicant_req_scan(wpa_s, 0, 0); return wpas_dbus_new_success_reply(message); } /** * wpas_dbus_iface_scan_results - Get the results of a recent scan request * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: a dbus message containing a dbus array of objects paths, or returns * a dbus error message if not scan results could be found * * Handler function for "scanResults" method call of a network device. Returns * a dbus message containing the object paths of wireless networks found. */ DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; DBusMessageIter iter; DBusMessageIter sub_iter; struct wpa_bss *bss; /* Create and initialize the return message */ reply = dbus_message_new_method_return(message); dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH_AS_STRING, &sub_iter); /* Loop through scan results and append each result's object path */ dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { char path_buf[WPAS_DBUS_OBJECT_PATH_MAX]; char *path = path_buf; /* Construct the object path for this network. Note that ':' * is not a valid character in dbus object paths. */ os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_BSSIDS_PART "/" WPAS_DBUS_BSSID_FORMAT, wpa_s->dbus_path, MAC2STR(bss->bssid)); dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_OBJECT_PATH, &path); } dbus_message_iter_close_container(&iter, &sub_iter); return reply; } /** * wpas_dbus_bssid_properties - Return the properties of a scanned network * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * @res: wpa_supplicant scan result for which to get properties * Returns: a dbus message containing the properties for the requested network * * Handler function for "properties" method call of a scanned network. * Returns a dbus message containing the the properties. */ DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message, struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { DBusMessage *reply; DBusMessageIter iter, iter_dict; const u8 *ie; /* Dump the properties into a dbus message */ reply = dbus_message_new_method_return(message); dbus_message_iter_init_append(reply, &iter); if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) goto error; if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid", (const char *) bss->bssid, ETH_ALEN)) goto error; ie = wpa_bss_get_ie(bss, WLAN_EID_SSID); if (ie) { if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid", (const char *) (ie + 2), ie[1])) goto error; } ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); if (ie) { if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie", (const char *) ie, ie[1] + 2)) goto error; } ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); if (ie) { if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie", (const char *) ie, ie[1] + 2)) goto error; } ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE); if (ie) { if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie", (const char *) ie, ie[1] + 2)) goto error; } if (bss->freq) { if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency", bss->freq)) goto error; } if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities", bss->caps)) goto error; if (!(bss->flags & WPA_BSS_QUAL_INVALID) && !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual)) goto error; if (!(bss->flags & WPA_BSS_NOISE_INVALID) && !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise)) goto error; if (!(bss->flags & WPA_BSS_LEVEL_INVALID) && !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level)) goto error; if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate", wpa_bss_get_max_rate(bss) * 500000)) goto error; if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) goto error; return reply; error: if (reply) dbus_message_unref(reply); return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR, "an internal error occurred returning " "BSSID properties."); } /** * wpas_dbus_iface_capabilities - Return interface capabilities * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A dbus message containing a dict of strings * * Handler function for "capabilities" method call of an interface. */ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; struct wpa_driver_capa capa; int res; DBusMessageIter iter, iter_dict; char **eap_methods; size_t num_items; dbus_bool_t strict = FALSE; DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_BOOLEAN, &strict, DBUS_TYPE_INVALID)) strict = FALSE; reply = dbus_message_new_method_return(message); dbus_message_iter_init_append(reply, &iter); if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) goto error; /* EAP methods */ eap_methods = eap_get_names_as_string_array(&num_items); if (eap_methods) { dbus_bool_t success = FALSE; size_t i = 0; success = wpa_dbus_dict_append_string_array( &iter_dict, "eap", (const char **) eap_methods, num_items); /* free returned method array */ while (eap_methods[i]) os_free(eap_methods[i++]); os_free(eap_methods); if (!success) goto error; } res = wpa_drv_get_capa(wpa_s, &capa); /***** pairwise cipher */ if (res < 0) { if (!strict) { const char *args[] = {"CCMP", "TKIP", "NONE"}; if (!wpa_dbus_dict_append_string_array( &iter_dict, "pairwise", args, ARRAY_SIZE(args))) goto error; } } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise", &iter_dict_entry, &iter_dict_val, &iter_array)) goto error; if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "CCMP")) goto error; } if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "TKIP")) goto error; } if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "NONE")) goto error; } if (!wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) goto error; } /***** group cipher */ if (res < 0) { if (!strict) { const char *args[] = { "CCMP", "TKIP", "WEP104", "WEP40" }; if (!wpa_dbus_dict_append_string_array( &iter_dict, "group", args, ARRAY_SIZE(args))) goto error; } } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group", &iter_dict_entry, &iter_dict_val, &iter_array)) goto error; if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "CCMP")) goto error; } if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "TKIP")) goto error; } if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "WEP104")) goto error; } if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "WEP40")) goto error; } if (!wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) goto error; } /***** key management */ if (res < 0) { if (!strict) { const char *args[] = { "WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE", "NONE" }; if (!wpa_dbus_dict_append_string_array( &iter_dict, "key_mgmt", args, ARRAY_SIZE(args))) goto error; } } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt", &iter_dict_entry, &iter_dict_val, &iter_array)) goto error; if (!wpa_dbus_dict_string_array_add_element(&iter_array, "NONE")) goto error; if (!wpa_dbus_dict_string_array_add_element(&iter_array, "IEEE8021X")) goto error; if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "WPA-EAP")) goto error; } if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "WPA-PSK")) goto error; } if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "WPA-NONE")) goto error; } if (!wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) goto error; } /***** WPA protocol */ if (res < 0) { if (!strict) { const char *args[] = { "RSN", "WPA" }; if (!wpa_dbus_dict_append_string_array( &iter_dict, "proto", args, ARRAY_SIZE(args))) goto error; } } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto", &iter_dict_entry, &iter_dict_val, &iter_array)) goto error; if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "RSN")) goto error; } if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "WPA")) goto error; } if (!wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) goto error; } /***** auth alg */ if (res < 0) { if (!strict) { const char *args[] = { "OPEN", "SHARED", "LEAP" }; if (!wpa_dbus_dict_append_string_array( &iter_dict, "auth_alg", args, ARRAY_SIZE(args))) goto error; } } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg", &iter_dict_entry, &iter_dict_val, &iter_array)) goto error; if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "OPEN")) goto error; } if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "SHARED")) goto error; } if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "LEAP")) goto error; } if (!wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) goto error; } if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) goto error; return reply; error: if (reply) dbus_message_unref(reply); return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR, "an internal error occurred returning " "interface capabilities."); } /** * wpas_dbus_iface_add_network - Add a new configured network * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A dbus message containing the object path of the new network * * Handler function for "addNetwork" method call of a network interface. */ DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; struct wpa_ssid *ssid; char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; ssid = wpa_config_add_network(wpa_s->conf); if (ssid == NULL) { reply = dbus_message_new_error(message, WPAS_ERROR_ADD_NETWORK_ERROR, "wpa_supplicant could not add " "a network on this interface."); goto out; } wpas_notify_network_added(wpa_s, ssid); ssid->disabled = 1; wpa_config_set_network_defaults(ssid); /* Construct the object path for this network. */ os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NETWORKS_PART "/%d", wpa_s->dbus_path, ssid->id); reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); out: return reply; } /** * wpas_dbus_iface_remove_network - Remove a configured network * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A dbus message containing a UINT32 indicating success (1) or * failure (0) * * Handler function for "removeNetwork" method call of a network interface. */ DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; const char *op; char *iface = NULL, *net_id = NULL; int id; struct wpa_ssid *ssid; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, DBUS_TYPE_INVALID)) { reply = wpas_dbus_new_invalid_opts_error(message, NULL); goto out; } /* Extract the network ID */ iface = wpas_dbus_decompose_object_path(op, &net_id, NULL); if (iface == NULL) { reply = wpas_dbus_new_invalid_network_error(message); goto out; } /* Ensure the network is actually a child of this interface */ if (os_strcmp(iface, wpa_s->dbus_path) != 0) { reply = wpas_dbus_new_invalid_network_error(message); goto out; } id = strtoul(net_id, NULL, 10); ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { reply = wpas_dbus_new_invalid_network_error(message); goto out; } wpas_notify_network_removed(wpa_s, ssid); if (wpa_config_remove_network(wpa_s->conf, id) < 0) { reply = dbus_message_new_error(message, WPAS_ERROR_REMOVE_NETWORK_ERROR, "error removing the specified " "on this interface."); goto out; } if (ssid == wpa_s->current_ssid) wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); reply = wpas_dbus_new_success_reply(message); out: os_free(iface); os_free(net_id); return reply; } static const char *dont_quote[] = { "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap", "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path", "bssid", NULL }; static dbus_bool_t should_quote_opt(const char *key) { int i = 0; while (dont_quote[i] != NULL) { if (strcmp(key, dont_quote[i]) == 0) return FALSE; i++; } return TRUE; } /** * wpas_dbus_iface_set_network - Set options for a configured network * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * @ssid: wpa_ssid structure for a configured network * Returns: a dbus message containing a UINT32 indicating success (1) or * failure (0) * * Handler function for "set" method call of a configured network. */ DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { DBusMessage *reply = NULL; struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; DBusMessageIter iter, iter_dict; dbus_message_iter_init(message, &iter); if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) { reply = wpas_dbus_new_invalid_opts_error(message, NULL); goto out; } while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { char *value = NULL; size_t size = 50; int ret; if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { reply = wpas_dbus_new_invalid_opts_error(message, NULL); goto out; } /* Type conversions, since wpa_supplicant wants strings */ if (entry.type == DBUS_TYPE_ARRAY && entry.array_type == DBUS_TYPE_BYTE) { if (entry.array_len <= 0) goto error; size = entry.array_len * 2 + 1; value = os_zalloc(size); if (value == NULL) goto error; ret = wpa_snprintf_hex(value, size, (u8 *) entry.bytearray_value, entry.array_len); if (ret <= 0) goto error; } else if (entry.type == DBUS_TYPE_STRING) { if (should_quote_opt(entry.key)) { size = os_strlen(entry.str_value); /* Zero-length option check */ if (size <= 0) goto error; size += 3; /* For quotes and terminator */ value = os_zalloc(size); if (value == NULL) goto error; ret = os_snprintf(value, size, "\"%s\"", entry.str_value); if (ret < 0 || (size_t) ret != (size - 1)) goto error; } else { value = os_strdup(entry.str_value); if (value == NULL) goto error; } } else if (entry.type == DBUS_TYPE_UINT32) { value = os_zalloc(size); if (value == NULL) goto error; ret = os_snprintf(value, size, "%u", entry.uint32_value); if (ret <= 0) goto error; } else if (entry.type == DBUS_TYPE_INT32) { value = os_zalloc(size); if (value == NULL) goto error; ret = os_snprintf(value, size, "%d", entry.int32_value); if (ret <= 0) goto error; } else goto error; if (wpa_config_set(ssid, entry.key, value, 0) < 0) goto error; if ((os_strcmp(entry.key, "psk") == 0 && value[0] == '"' && ssid->ssid_len) || (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) wpa_config_update_psk(ssid); else if (os_strcmp(entry.key, "priority") == 0) wpa_config_update_prio_list(wpa_s->conf); os_free(value); wpa_dbus_dict_entry_clear(&entry); continue; error: os_free(value); reply = wpas_dbus_new_invalid_opts_error(message, entry.key); wpa_dbus_dict_entry_clear(&entry); break; } if (!reply) reply = wpas_dbus_new_success_reply(message); out: return reply; } /** * wpas_dbus_iface_enable_network - Mark a configured network as enabled * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * @ssid: wpa_ssid structure for a configured network * Returns: A dbus message containing a UINT32 indicating success (1) or * failure (0) * * Handler function for "enable" method call of a configured network. */ DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message, struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { wpa_supplicant_enable_network(wpa_s, ssid); return wpas_dbus_new_success_reply(message); } /** * wpas_dbus_iface_disable_network - Mark a configured network as disabled * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * @ssid: wpa_ssid structure for a configured network * Returns: A dbus message containing a UINT32 indicating success (1) or * failure (0) * * Handler function for "disable" method call of a configured network. */ DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message, struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { wpa_supplicant_disable_network(wpa_s, ssid); return wpas_dbus_new_success_reply(message); } /** * wpas_dbus_iface_select_network - Attempt association with a configured network * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A dbus message containing a UINT32 indicating success (1) or * failure (0) * * Handler function for "selectNetwork" method call of network interface. */ DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; const char *op; struct wpa_ssid *ssid; char *iface_obj_path = NULL; char *network = NULL; if (os_strlen(dbus_message_get_signature(message)) == 0) { /* Any network */ ssid = NULL; } else { int nid; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, DBUS_TYPE_INVALID)) { reply = wpas_dbus_new_invalid_opts_error(message, NULL); goto out; } /* Extract the network number */ iface_obj_path = wpas_dbus_decompose_object_path(op, &network, NULL); if (iface_obj_path == NULL) { reply = wpas_dbus_new_invalid_iface_error(message); goto out; } /* Ensure the object path really points to this interface */ if (os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) { reply = wpas_dbus_new_invalid_network_error(message); goto out; } nid = strtoul(network, NULL, 10); if (errno == EINVAL) { reply = wpas_dbus_new_invalid_network_error(message); goto out; } ssid = wpa_config_get_network(wpa_s->conf, nid); if (ssid == NULL) { reply = wpas_dbus_new_invalid_network_error(message); goto out; } } /* Finally, associate with the network */ wpa_supplicant_select_network(wpa_s, ssid); reply = wpas_dbus_new_success_reply(message); out: os_free(iface_obj_path); os_free(network); return reply; } /** * wpas_dbus_iface_disconnect - Terminate the current connection * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A dbus message containing a UINT32 indicating success (1) or * failure (0) * * Handler function for "disconnect" method call of network interface. */ DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message, struct wpa_supplicant *wpa_s) { wpa_s->disconnected = 1; wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); return wpas_dbus_new_success_reply(message); } /** * wpas_dbus_iface_set_ap_scan - Control roaming mode * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A dbus message containing a UINT32 indicating success (1) or * failure (0) * * Handler function for "setAPScan" method call. */ DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; dbus_uint32_t ap_scan = 1; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan, DBUS_TYPE_INVALID)) { reply = wpas_dbus_new_invalid_opts_error(message, NULL); goto out; } if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) { reply = wpas_dbus_new_invalid_opts_error(message, NULL); goto out; } reply = wpas_dbus_new_success_reply(message); out: return reply; } /** * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A dbus message containing a UINT32 indicating success (1) or * failure (0) * * Handler function for "setSmartcardModules" method call. */ DBusMessage * wpas_dbus_iface_set_smartcard_modules( DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessageIter iter, iter_dict; char *opensc_engine_path = NULL; char *pkcs11_engine_path = NULL; char *pkcs11_module_path = NULL; struct wpa_dbus_dict_entry entry; if (!dbus_message_iter_init(message, &iter)) goto error; if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto error; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; if (!strcmp(entry.key, "opensc_engine_path") && (entry.type == DBUS_TYPE_STRING)) { opensc_engine_path = os_strdup(entry.str_value); if (opensc_engine_path == NULL) goto error; } else if (!strcmp(entry.key, "pkcs11_engine_path") && (entry.type == DBUS_TYPE_STRING)) { pkcs11_engine_path = os_strdup(entry.str_value); if (pkcs11_engine_path == NULL) goto error; } else if (!strcmp(entry.key, "pkcs11_module_path") && (entry.type == DBUS_TYPE_STRING)) { pkcs11_module_path = os_strdup(entry.str_value); if (pkcs11_module_path == NULL) goto error; } else { wpa_dbus_dict_entry_clear(&entry); goto error; } wpa_dbus_dict_entry_clear(&entry); } os_free(wpa_s->conf->opensc_engine_path); wpa_s->conf->opensc_engine_path = opensc_engine_path; os_free(wpa_s->conf->pkcs11_engine_path); wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path; os_free(wpa_s->conf->pkcs11_module_path); wpa_s->conf->pkcs11_module_path = pkcs11_module_path; wpa_sm_set_eapol(wpa_s->wpa, NULL); eapol_sm_deinit(wpa_s->eapol); wpa_s->eapol = NULL; wpa_supplicant_init_eapol(wpa_s); wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol); return wpas_dbus_new_success_reply(message); error: os_free(opensc_engine_path); os_free(pkcs11_engine_path); os_free(pkcs11_module_path); return wpas_dbus_new_invalid_opts_error(message, NULL); } /** * wpas_dbus_iface_get_state - Get interface state * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A dbus message containing a STRING representing the current * interface state * * Handler function for "state" method call. */ DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; const char *str_state; reply = dbus_message_new_method_return(message); if (reply != NULL) { str_state = wpa_supplicant_state_txt(wpa_s->wpa_state); dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state, DBUS_TYPE_INVALID); } return reply; } /** * wpas_dbus_iface_get_scanning - Get interface scanning state * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A dbus message containing whether the interface is scanning * * Handler function for "scanning" method call. */ DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; reply = dbus_message_new_method_return(message); if (reply != NULL) { dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning, DBUS_TYPE_INVALID); } else { wpa_printf(MSG_ERROR, "dbus: Not enough memory to return " "scanning state"); } return reply; } #ifndef CONFIG_NO_CONFIG_BLOBS /** * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates) * @message: Pointer to incoming dbus message * @wpa_s: %wpa_supplicant data structure * Returns: A dbus message containing a UINT32 indicating success (1) or * failure (0) * * Asks wpa_supplicant to internally store a one or more binary blobs. */ DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; DBusMessageIter iter, iter_dict; dbus_message_iter_init(message, &iter); if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) return wpas_dbus_new_invalid_opts_error(message, NULL); while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { struct wpa_config_blob *blob; if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { reply = wpas_dbus_new_invalid_opts_error(message, NULL); break; } if (entry.type != DBUS_TYPE_ARRAY || entry.array_type != DBUS_TYPE_BYTE) { reply = wpas_dbus_new_invalid_opts_error( message, "Byte array expected."); break; } if ((entry.array_len <= 0) || (entry.array_len > 65536) || !strlen(entry.key)) { reply = wpas_dbus_new_invalid_opts_error( message, "Invalid array size."); break; } blob = os_zalloc(sizeof(*blob)); if (blob == NULL) { reply = dbus_message_new_error( message, WPAS_ERROR_ADD_ERROR, "Not enough memory to add blob."); break; } blob->data = os_zalloc(entry.array_len); if (blob->data == NULL) { reply = dbus_message_new_error( message, WPAS_ERROR_ADD_ERROR, "Not enough memory to add blob data."); os_free(blob); break; } blob->name = os_strdup(entry.key); blob->len = entry.array_len; os_memcpy(blob->data, (u8 *) entry.bytearray_value, entry.array_len); if (blob->name == NULL || blob->data == NULL) { wpa_config_free_blob(blob); reply = dbus_message_new_error( message, WPAS_ERROR_ADD_ERROR, "Error adding blob."); break; } /* Success */ if (!wpa_config_remove_blob(wpa_s->conf, blob->name)) wpas_notify_blob_removed(wpa_s, blob->name); wpa_config_set_blob(wpa_s->conf, blob); wpas_notify_blob_added(wpa_s, blob->name); wpa_dbus_dict_entry_clear(&entry); } wpa_dbus_dict_entry_clear(&entry); return reply ? reply : wpas_dbus_new_success_reply(message); } /** * wpas_dbus_iface_remove_blob - Remove named binary blobs * @message: Pointer to incoming dbus message * @wpa_s: %wpa_supplicant data structure * Returns: A dbus message containing a UINT32 indicating success (1) or * failure (0) * * Asks wpa_supplicant to remove one or more previously stored binary blobs. */ DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessageIter iter, array; char *err_msg = NULL; dbus_message_iter_init(message, &iter); if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) || (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING)) return wpas_dbus_new_invalid_opts_error(message, NULL); dbus_message_iter_recurse(&iter, &array); while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) { const char *name; dbus_message_iter_get_basic(&array, &name); if (!os_strlen(name)) err_msg = "Invalid blob name."; if (wpa_config_remove_blob(wpa_s->conf, name) != 0) err_msg = "Error removing blob."; else wpas_notify_blob_removed(wpa_s, name); dbus_message_iter_next(&array); } if (err_msg) return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR, err_msg); return wpas_dbus_new_success_reply(message); } #endif /* CONFIG_NO_CONFIG_BLOBS */ /** * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries * @message: Pointer to incoming dbus message * @wpa_s: %wpa_supplicant data structure * Returns: a dbus message containing a UINT32 indicating success (1) or * failure (0), or returns a dbus error message with more information * * Handler function for "flush" method call. Handles requests for an * interface with an optional "age" parameter that specifies the minimum * age of a BSS to be flushed. */ DBusMessage * wpas_dbus_iface_flush(DBusMessage *message, struct wpa_supplicant *wpa_s) { int flush_age = 0; if (os_strlen(dbus_message_get_signature(message)) != 0 && !dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &flush_age, DBUS_TYPE_INVALID)) { return wpas_dbus_new_invalid_opts_error(message, NULL); } if (flush_age == 0) wpa_bss_flush(wpa_s); else wpa_bss_flush_by_age(wpa_s, flush_age); return wpas_dbus_new_success_reply(message); } wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_new_helpers.c0000664000175000017500000007544412343617166021717 0ustar jmjm/* * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * Copyright (c) 2009, Witold Sowa * * 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 "dbus_common.h" #include "dbus_common_i.h" #include "dbus_new.h" #include "dbus_new_helpers.h" #include "dbus_dict_helpers.h" static dbus_bool_t fill_dict_with_properties( DBusMessageIter *dict_iter, const struct wpa_dbus_property_desc *props, const char *interface, void *user_data, DBusError *error) { DBusMessageIter entry_iter; const struct wpa_dbus_property_desc *dsc; for (dsc = props; dsc && dsc->dbus_property; dsc++) { /* Only return properties for the requested D-Bus interface */ if (os_strncmp(dsc->dbus_interface, interface, WPAS_DBUS_INTERFACE_MAX) != 0) continue; /* Skip write-only properties */ if (dsc->getter == NULL) continue; if (!dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry_iter)) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } if (!dbus_message_iter_append_basic(&entry_iter, DBUS_TYPE_STRING, &dsc->dbus_property)) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } /* An error getting a property fails the request entirely */ if (!dsc->getter(&entry_iter, error, user_data)) return FALSE; dbus_message_iter_close_container(dict_iter, &entry_iter); } return TRUE; } /** * get_all_properties - Responds for GetAll properties calls on object * @message: Message with GetAll call * @interface: interface name which properties will be returned * @property_dsc: list of object's properties * Returns: Message with dict of variants as argument with properties values * * Iterates over all properties registered with object and execute getters * of those, which are readable and which interface matches interface * specified as argument. Returned message contains one dict argument * with properties names as keys and theirs values as values. */ static DBusMessage * get_all_properties(DBusMessage *message, char *interface, struct wpa_dbus_object_desc *obj_dsc) { DBusMessage *reply; DBusMessageIter iter, dict_iter; DBusError error; reply = dbus_message_new_method_return(message); if (reply == NULL) { wpa_printf(MSG_ERROR, "%s: out of memory creating dbus reply", __func__); return NULL; } dbus_message_iter_init_append(reply, &iter); if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) { wpa_printf(MSG_ERROR, "%s: out of memory creating reply", __func__); dbus_message_unref(reply); reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, "out of memory"); return reply; } dbus_error_init(&error); if (!fill_dict_with_properties(&dict_iter, obj_dsc->properties, interface, obj_dsc->user_data, &error)) { dbus_message_unref(reply); reply = wpas_dbus_reply_new_from_error(message, &error, DBUS_ERROR_INVALID_ARGS, "No readable properties" " in this interface"); dbus_error_free(&error); return reply; } wpa_dbus_dict_close_write(&iter, &dict_iter); return reply; } static int is_signature_correct(DBusMessage *message, const struct wpa_dbus_method_desc *method_dsc) { /* According to DBus documentation max length of signature is 255 */ #define MAX_SIG_LEN 256 char registered_sig[MAX_SIG_LEN], *pos; const char *sig = dbus_message_get_signature(message); int ret; const struct wpa_dbus_argument *arg; pos = registered_sig; *pos = '\0'; for (arg = method_dsc->args; arg && arg->name; arg++) { if (arg->dir == ARG_IN) { size_t blen = registered_sig + MAX_SIG_LEN - pos; ret = os_snprintf(pos, blen, "%s", arg->type); if (ret < 0 || (size_t) ret >= blen) return 0; pos += ret; } } return !os_strncmp(registered_sig, sig, MAX_SIG_LEN); } static DBusMessage * properties_get_all(DBusMessage *message, char *interface, struct wpa_dbus_object_desc *obj_dsc) { if (os_strcmp(dbus_message_get_signature(message), "s") != 0) return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, NULL); return get_all_properties(message, interface, obj_dsc); } static DBusMessage * properties_get(DBusMessage *message, const struct wpa_dbus_property_desc *dsc, void *user_data) { DBusMessage *reply; DBusMessageIter iter; DBusError error; if (os_strcmp(dbus_message_get_signature(message), "ss")) { return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, NULL); } if (dsc->getter == NULL) { return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "Property is write-only"); } reply = dbus_message_new_method_return(message); dbus_message_iter_init_append(reply, &iter); dbus_error_init(&error); if (dsc->getter(&iter, &error, user_data) == FALSE) { dbus_message_unref(reply); reply = wpas_dbus_reply_new_from_error( message, &error, DBUS_ERROR_FAILED, "Failed to read property"); dbus_error_free(&error); } return reply; } static DBusMessage * properties_set(DBusMessage *message, const struct wpa_dbus_property_desc *dsc, void *user_data) { DBusMessage *reply; DBusMessageIter iter; DBusError error; if (os_strcmp(dbus_message_get_signature(message), "ssv")) { return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, NULL); } if (dsc->setter == NULL) { return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "Property is read-only"); } dbus_message_iter_init(message, &iter); /* Skip the interface name and the property name */ dbus_message_iter_next(&iter); dbus_message_iter_next(&iter); /* Iter will now point to the property's new value */ dbus_error_init(&error); if (dsc->setter(&iter, &error, user_data) == TRUE) { /* Success */ reply = dbus_message_new_method_return(message); } else { reply = wpas_dbus_reply_new_from_error( message, &error, DBUS_ERROR_FAILED, "Failed to set property"); dbus_error_free(&error); } return reply; } static DBusMessage * properties_get_or_set(DBusMessage *message, DBusMessageIter *iter, char *interface, struct wpa_dbus_object_desc *obj_dsc) { const struct wpa_dbus_property_desc *property_dsc; char *property; const char *method; method = dbus_message_get_member(message); property_dsc = obj_dsc->properties; /* Second argument: property name (DBUS_TYPE_STRING) */ if (!dbus_message_iter_next(iter) || dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) { return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, NULL); } dbus_message_iter_get_basic(iter, &property); while (property_dsc && property_dsc->dbus_property) { /* compare property names and * interfaces */ if (!os_strncmp(property_dsc->dbus_property, property, WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) && !os_strncmp(property_dsc->dbus_interface, interface, WPAS_DBUS_INTERFACE_MAX)) break; property_dsc++; } if (property_dsc == NULL || property_dsc->dbus_property == NULL) { wpa_printf(MSG_DEBUG, "no property handler for %s.%s on %s", interface, property, dbus_message_get_path(message)); return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "No such property"); } if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method, WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0) return properties_get(message, property_dsc, obj_dsc->user_data); return properties_set(message, property_dsc, obj_dsc->user_data); } static DBusMessage * properties_handler(DBusMessage *message, struct wpa_dbus_object_desc *obj_dsc) { DBusMessageIter iter; char *interface; const char *method; method = dbus_message_get_member(message); dbus_message_iter_init(message, &iter); if (!os_strncmp(WPA_DBUS_PROPERTIES_GET, method, WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) || !os_strncmp(WPA_DBUS_PROPERTIES_SET, method, WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) || !os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method, WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) { /* First argument: interface name (DBUS_TYPE_STRING) */ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) { return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, NULL); } dbus_message_iter_get_basic(&iter, &interface); if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method, WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) { /* GetAll */ return properties_get_all(message, interface, obj_dsc); } /* Get or Set */ return properties_get_or_set(message, &iter, interface, obj_dsc); } return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD, NULL); } static DBusMessage * msg_method_handler(DBusMessage *message, struct wpa_dbus_object_desc *obj_dsc) { const struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods; const char *method; const char *msg_interface; method = dbus_message_get_member(message); msg_interface = dbus_message_get_interface(message); /* try match call to any registered method */ while (method_dsc && method_dsc->dbus_method) { /* compare method names and interfaces */ if (!os_strncmp(method_dsc->dbus_method, method, WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) && !os_strncmp(method_dsc->dbus_interface, msg_interface, WPAS_DBUS_INTERFACE_MAX)) break; method_dsc++; } if (method_dsc == NULL || method_dsc->dbus_method == NULL) { wpa_printf(MSG_DEBUG, "no method handler for %s.%s on %s", msg_interface, method, dbus_message_get_path(message)); return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD, NULL); } if (!is_signature_correct(message, method_dsc)) { return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, NULL); } return method_dsc->method_handler(message, obj_dsc->user_data); } /** * message_handler - Handles incoming DBus messages * @connection: DBus connection on which message was received * @message: Received message * @user_data: pointer to description of object to which message was sent * Returns: Returns information whether message was handled or not * * Reads message interface and method name, then checks if they matches one * of the special cases i.e. introspection call or properties get/getall/set * methods and handles it. Else it iterates over registered methods list * and tries to match method's name and interface to those read from message * If appropriate method was found its handler function is called and * response is sent. Otherwise, the DBUS_ERROR_UNKNOWN_METHOD error message * will be sent. */ static DBusHandlerResult message_handler(DBusConnection *connection, DBusMessage *message, void *user_data) { struct wpa_dbus_object_desc *obj_dsc = user_data; const char *method; const char *path; const char *msg_interface; DBusMessage *reply; /* get method, interface and path the message is addressed to */ method = dbus_message_get_member(message); path = dbus_message_get_path(message); msg_interface = dbus_message_get_interface(message); if (!method || !path || !msg_interface) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)", msg_interface, method, path); /* if message is introspection method call */ if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method, WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) && !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE, msg_interface, WPAS_DBUS_INTERFACE_MAX)) { #ifdef CONFIG_CTRL_IFACE_DBUS_INTRO reply = wpa_dbus_introspect(message, obj_dsc); #else /* CONFIG_CTRL_IFACE_DBUS_INTRO */ reply = dbus_message_new_error( message, DBUS_ERROR_UNKNOWN_METHOD, "wpa_supplicant was compiled without " "introspection support."); #endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */ } else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface, WPAS_DBUS_INTERFACE_MAX)) { /* if message is properties method call */ reply = properties_handler(message, obj_dsc); } else { reply = msg_method_handler(message, obj_dsc); } /* If handler succeed returning NULL, reply empty message */ if (!reply) reply = dbus_message_new_method_return(message); if (reply) { if (!dbus_message_get_no_reply(message)) dbus_connection_send(connection, reply, NULL); dbus_message_unref(reply); } wpa_dbus_flush_all_changed_properties(connection); return DBUS_HANDLER_RESULT_HANDLED; } /** * free_dbus_object_desc - Frees object description data structure * @connection: DBus connection * @obj_dsc: Object description to free * * Frees each of properties, methods and signals description lists and * the object description structure itself. */ void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc) { if (!obj_dsc) return; /* free handler's argument */ if (obj_dsc->user_data_free_func) obj_dsc->user_data_free_func(obj_dsc->user_data); os_free(obj_dsc->path); os_free(obj_dsc->prop_changed_flags); os_free(obj_dsc); } static void free_dbus_object_desc_cb(DBusConnection *connection, void *obj_dsc) { free_dbus_object_desc(obj_dsc); } /** * wpa_dbus_ctrl_iface_init - Initialize dbus control interface * @application_data: Pointer to application specific data structure * @dbus_path: DBus path to interface object * @dbus_service: DBus service name to register with * @messageHandler: a pointer to function which will handle dbus messages * coming on interface * Returns: 0 on success, -1 on failure * * Initialize the dbus control interface and start receiving commands from * external programs over the bus. */ int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface, char *dbus_path, char *dbus_service, struct wpa_dbus_object_desc *obj_desc) { DBusError error; int ret = -1; DBusObjectPathVTable wpa_vtable = { &free_dbus_object_desc_cb, &message_handler, NULL, NULL, NULL, NULL }; obj_desc->connection = iface->con; obj_desc->path = os_strdup(dbus_path); /* Register the message handler for the global dbus interface */ if (!dbus_connection_register_object_path(iface->con, dbus_path, &wpa_vtable, obj_desc)) { wpa_printf(MSG_ERROR, "dbus: Could not set up message " "handler"); return -1; } /* Register our service with the message bus */ dbus_error_init(&error); switch (dbus_bus_request_name(iface->con, dbus_service, 0, &error)) { case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: ret = 0; break; case DBUS_REQUEST_NAME_REPLY_EXISTS: case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: wpa_printf(MSG_ERROR, "dbus: Could not request service name: " "already registered"); break; default: wpa_printf(MSG_ERROR, "dbus: Could not request service name: " "%s %s", error.name, error.message); break; } dbus_error_free(&error); if (ret != 0) return -1; wpa_printf(MSG_DEBUG, "Providing DBus service '%s'.", dbus_service); return 0; } /** * wpa_dbus_register_object_per_iface - Register a new object with dbus * @ctrl_iface: pointer to dbus private data * @path: DBus path to object * @ifname: interface name * @obj_desc: description of object's methods, signals and properties * Returns: 0 on success, -1 on error * * Registers a new interface with dbus and assigns it a dbus object path. */ int wpa_dbus_register_object_per_iface( struct wpas_dbus_priv *ctrl_iface, const char *path, const char *ifname, struct wpa_dbus_object_desc *obj_desc) { DBusConnection *con; DBusError error; DBusObjectPathVTable vtable = { &free_dbus_object_desc_cb, &message_handler, NULL, NULL, NULL, NULL }; /* Do nothing if the control interface is not turned on */ if (ctrl_iface == NULL) return 0; con = ctrl_iface->con; obj_desc->connection = con; obj_desc->path = os_strdup(path); dbus_error_init(&error); /* Register the message handler for the interface functions */ if (!dbus_connection_try_register_object_path(con, path, &vtable, obj_desc, &error)) { if (!os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE)) { wpa_printf(MSG_DEBUG, "dbus: %s", error.message); } else { wpa_printf(MSG_ERROR, "dbus: Could not set up message " "handler for interface %s object %s", ifname, path); wpa_printf(MSG_ERROR, "dbus error: %s", error.name); wpa_printf(MSG_ERROR, "dbus: %s", error.message); } dbus_error_free(&error); return -1; } dbus_error_free(&error); return 0; } static void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx); /** * wpa_dbus_unregister_object_per_iface - Unregisters DBus object * @ctrl_iface: Pointer to dbus private data * @path: DBus path to object which will be unregistered * Returns: Zero on success and -1 on failure * * Unregisters DBus object given by its path */ int wpa_dbus_unregister_object_per_iface( struct wpas_dbus_priv *ctrl_iface, const char *path) { DBusConnection *con = ctrl_iface->con; struct wpa_dbus_object_desc *obj_desc = NULL; dbus_connection_get_object_path_data(con, path, (void **) &obj_desc); if (!obj_desc) { wpa_printf(MSG_ERROR, "dbus: %s: Could not obtain object's " "private data: %s", __func__, path); return 0; } eloop_cancel_timeout(flush_object_timeout_handler, con, obj_desc); if (!dbus_connection_unregister_object_path(con, path)) return -1; return 0; } static dbus_bool_t put_changed_properties( const struct wpa_dbus_object_desc *obj_dsc, const char *interface, DBusMessageIter *dict_iter, int clear_changed) { DBusMessageIter entry_iter; const struct wpa_dbus_property_desc *dsc; int i; DBusError error; for (dsc = obj_dsc->properties, i = 0; dsc && dsc->dbus_property; dsc++, i++) { if (obj_dsc->prop_changed_flags == NULL || !obj_dsc->prop_changed_flags[i]) continue; if (os_strcmp(dsc->dbus_interface, interface) != 0) continue; if (clear_changed) obj_dsc->prop_changed_flags[i] = 0; if (!dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry_iter)) return FALSE; if (!dbus_message_iter_append_basic(&entry_iter, DBUS_TYPE_STRING, &dsc->dbus_property)) return FALSE; dbus_error_init(&error); if (!dsc->getter(&entry_iter, &error, obj_dsc->user_data)) { if (dbus_error_is_set (&error)) { wpa_printf(MSG_ERROR, "dbus: %s: Cannot get " "new value of property %s: (%s) %s", __func__, dsc->dbus_property, error.name, error.message); } else { wpa_printf(MSG_ERROR, "dbus: %s: Cannot get " "new value of property %s", __func__, dsc->dbus_property); } dbus_error_free(&error); return FALSE; } if (!dbus_message_iter_close_container(dict_iter, &entry_iter)) return FALSE; } return TRUE; } static void do_send_prop_changed_signal( DBusConnection *con, const char *path, const char *interface, const struct wpa_dbus_object_desc *obj_dsc) { DBusMessage *msg; DBusMessageIter signal_iter, dict_iter; msg = dbus_message_new_signal(path, DBUS_INTERFACE_PROPERTIES, "PropertiesChanged"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &signal_iter); if (!dbus_message_iter_append_basic(&signal_iter, DBUS_TYPE_STRING, &interface)) goto err; /* Changed properties dict */ if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)) goto err; if (!put_changed_properties(obj_dsc, interface, &dict_iter, 0)) goto err; if (!dbus_message_iter_close_container(&signal_iter, &dict_iter)) goto err; /* Invalidated properties array (empty) */ if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY, "s", &dict_iter)) goto err; if (!dbus_message_iter_close_container(&signal_iter, &dict_iter)) goto err; dbus_connection_send(con, msg, NULL); out: dbus_message_unref(msg); return; err: wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal", __func__); goto out; } static void do_send_deprecated_prop_changed_signal( DBusConnection *con, const char *path, const char *interface, const struct wpa_dbus_object_desc *obj_dsc) { DBusMessage *msg; DBusMessageIter signal_iter, dict_iter; msg = dbus_message_new_signal(path, interface, "PropertiesChanged"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &signal_iter); if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)) goto err; if (!put_changed_properties(obj_dsc, interface, &dict_iter, 1)) goto err; if (!dbus_message_iter_close_container(&signal_iter, &dict_iter)) goto err; dbus_connection_send(con, msg, NULL); out: dbus_message_unref(msg); return; err: wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal", __func__); goto out; } static void send_prop_changed_signal( DBusConnection *con, const char *path, const char *interface, const struct wpa_dbus_object_desc *obj_dsc) { /* * First, send property change notification on the standardized * org.freedesktop.DBus.Properties interface. This call will not * clear the property change bits, so that they are preserved for * the call that follows. */ do_send_prop_changed_signal(con, path, interface, obj_dsc); /* * Now send PropertiesChanged on our own interface for backwards * compatibility. This is deprecated and will be removed in a future * release. */ do_send_deprecated_prop_changed_signal(con, path, interface, obj_dsc); /* Property change bits have now been cleared. */ } static void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx) { DBusConnection *con = eloop_ctx; struct wpa_dbus_object_desc *obj_desc = timeout_ctx; wpa_printf(MSG_DEBUG, "dbus: %s: Timeout - sending changed properties " "of object %s", __func__, obj_desc->path); wpa_dbus_flush_object_changed_properties(con, obj_desc->path); } static void recursive_flush_changed_properties(DBusConnection *con, const char *path) { char **objects = NULL; char subobj_path[WPAS_DBUS_OBJECT_PATH_MAX]; int i; wpa_dbus_flush_object_changed_properties(con, path); if (!dbus_connection_list_registered(con, path, &objects)) goto out; for (i = 0; objects[i]; i++) { os_snprintf(subobj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/%s", path, objects[i]); recursive_flush_changed_properties(con, subobj_path); } out: dbus_free_string_array(objects); } /** * wpa_dbus_flush_all_changed_properties - Send all PropertiesChanged signals * @con: DBus connection * * Traverses through all registered objects and sends PropertiesChanged for * each properties. */ void wpa_dbus_flush_all_changed_properties(DBusConnection *con) { recursive_flush_changed_properties(con, WPAS_DBUS_NEW_PATH); } /** * wpa_dbus_flush_object_changed_properties - Send PropertiesChanged for object * @con: DBus connection * @path: path to a DBus object for which PropertiesChanged will be sent. * * Iterates over all properties registered with object and for each interface * containing properties marked as changed, sends a PropertiesChanged signal * containing names and new values of properties that have changed. * * You need to call this function after wpa_dbus_mark_property_changed() * if you want to send PropertiesChanged signal immediately (i.e., without * waiting timeout to expire). PropertiesChanged signal for an object is sent * automatically short time after first marking property as changed. All * PropertiesChanged signals are sent automatically after responding on DBus * message, so if you marked a property changed as a result of DBus call * (e.g., param setter), you usually do not need to call this function. */ void wpa_dbus_flush_object_changed_properties(DBusConnection *con, const char *path) { struct wpa_dbus_object_desc *obj_desc = NULL; const struct wpa_dbus_property_desc *dsc; int i; dbus_connection_get_object_path_data(con, path, (void **) &obj_desc); if (!obj_desc) return; eloop_cancel_timeout(flush_object_timeout_handler, con, obj_desc); for (dsc = obj_desc->properties, i = 0; dsc && dsc->dbus_property; dsc++, i++) { if (obj_desc->prop_changed_flags == NULL || !obj_desc->prop_changed_flags[i]) continue; send_prop_changed_signal(con, path, dsc->dbus_interface, obj_desc); } } #define WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT 5000 /** * wpa_dbus_mark_property_changed - Mark a property as changed and * @iface: dbus priv struct * @path: path to DBus object which property has changed * @interface: interface containing changed property * @property: property name which has changed * * Iterates over all properties registered with an object and marks the one * given in parameters as changed. All parameters registered for an object * within a single interface will be aggregated together and sent in one * PropertiesChanged signal when function * wpa_dbus_flush_object_changed_properties() is called. */ void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface, const char *path, const char *interface, const char *property) { struct wpa_dbus_object_desc *obj_desc = NULL; const struct wpa_dbus_property_desc *dsc; int i = 0; if (iface == NULL) return; dbus_connection_get_object_path_data(iface->con, path, (void **) &obj_desc); if (!obj_desc) { wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: " "could not obtain object's private data: %s", path); return; } for (dsc = obj_desc->properties; dsc && dsc->dbus_property; dsc++, i++) if (os_strcmp(property, dsc->dbus_property) == 0 && os_strcmp(interface, dsc->dbus_interface) == 0) { if (obj_desc->prop_changed_flags) obj_desc->prop_changed_flags[i] = 1; break; } if (!dsc || !dsc->dbus_property) { wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: " "no property %s in object %s", property, path); return; } if (!eloop_is_timeout_registered(flush_object_timeout_handler, iface->con, obj_desc->path)) { eloop_register_timeout(0, WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT, flush_object_timeout_handler, iface->con, obj_desc); } } /** * wpa_dbus_get_object_properties - Put object's properties into dictionary * @iface: dbus priv struct * @path: path to DBus object which properties will be obtained * @interface: interface name which properties will be obtained * @iter: DBus message iter at which to append property dictionary. * * Iterates over all properties registered with object and execute getters * of those, which are readable and which interface matches interface * specified as argument. Obtained properties values are stored in * dict_iter dictionary. */ dbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface, const char *path, const char *interface, DBusMessageIter *iter) { struct wpa_dbus_object_desc *obj_desc = NULL; DBusMessageIter dict_iter; DBusError error; dbus_connection_get_object_path_data(iface->con, path, (void **) &obj_desc); if (!obj_desc) { wpa_printf(MSG_ERROR, "dbus: %s: could not obtain object's " "private data: %s", __func__, path); return FALSE; } if (!wpa_dbus_dict_open_write(iter, &dict_iter)) { wpa_printf(MSG_ERROR, "dbus: %s: failed to open message dict", __func__); return FALSE; } dbus_error_init(&error); if (!fill_dict_with_properties(&dict_iter, obj_desc->properties, interface, obj_desc->user_data, &error)) { wpa_printf(MSG_ERROR, "dbus: %s: failed to get object" " properties: (%s) %s", __func__, dbus_error_is_set(&error) ? error.name : "none", dbus_error_is_set(&error) ? error.message : "none"); dbus_error_free(&error); return FALSE; } return wpa_dbus_dict_close_write(iter, &dict_iter); } /** * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts * @path: The dbus object path * @p2p_persistent_group: indicates whether to parse the path as a P2P * persistent group object * @network: (out) the configured network this object path refers to, if any * @bssid: (out) the scanned bssid this object path refers to, if any * Returns: The object path of the network interface this path refers to * * For a given object path, decomposes the object path into object id, network, * and BSSID parts, if those parts exist. */ char *wpas_dbus_new_decompose_object_path(const char *path, int p2p_persistent_group, char **network, char **bssid) { const unsigned int dev_path_prefix_len = os_strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/"); char *obj_path_only; char *next_sep; /* Be a bit paranoid about path */ if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/", dev_path_prefix_len)) return NULL; /* Ensure there's something at the end of the path */ if ((path + dev_path_prefix_len)[0] == '\0') return NULL; obj_path_only = os_strdup(path); if (obj_path_only == NULL) return NULL; next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/'); if (next_sep != NULL) { const char *net_part = os_strstr( next_sep, p2p_persistent_group ? WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/" : WPAS_DBUS_NEW_NETWORKS_PART "/"); const char *bssid_part = os_strstr( next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/"); if (network && net_part) { /* Deal with a request for a configured network */ const char *net_name = net_part + os_strlen(p2p_persistent_group ? WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/" : WPAS_DBUS_NEW_NETWORKS_PART "/"); *network = NULL; if (os_strlen(net_name)) *network = os_strdup(net_name); } else if (bssid && bssid_part) { /* Deal with a request for a scanned BSSID */ const char *bssid_name = bssid_part + os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/"); if (os_strlen(bssid_name)) *bssid = os_strdup(bssid_name); else *bssid = NULL; } /* Cut off interface object path before "/" */ *next_sep = '\0'; } return obj_path_only; } /** * wpas_dbus_reply_new_from_error - Create a new D-Bus error message from a * dbus error structure * @message: The original request message for which the error is a reply * @error: The error containing a name and a descriptive error cause * @fallback_name: A generic error name if @error was not set * @fallback_string: A generic error string if @error was not set * Returns: A new D-Bus error message * * Given a DBusMessage structure, creates a new D-Bus error message using * the error name and string contained in that structure. */ DBusMessage * wpas_dbus_reply_new_from_error(DBusMessage *message, DBusError *error, const char *fallback_name, const char *fallback_string) { if (error && error->name && error->message) { return dbus_message_new_error(message, error->name, error->message); } if (fallback_name && fallback_string) { return dbus_message_new_error(message, fallback_name, fallback_string); } return NULL; } wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_old.c0000664000175000017500000005440712343617166020156 0ustar jmjm/* * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include #include "common.h" #include "eloop.h" #include "wps/wps.h" #include "../config.h" #include "../wpa_supplicant_i.h" #include "../bss.h" #include "dbus_old.h" #include "dbus_old_handlers.h" #include "dbus_common_i.h" /** * wpas_dbus_decompose_object_path - Decompose an interface object path into parts * @path: The dbus object path * @network: (out) the configured network this object path refers to, if any * @bssid: (out) the scanned bssid this object path refers to, if any * Returns: The object path of the network interface this path refers to * * For a given object path, decomposes the object path into object id, network, * and BSSID parts, if those parts exist. */ char * wpas_dbus_decompose_object_path(const char *path, char **network, char **bssid) { const unsigned int dev_path_prefix_len = strlen(WPAS_DBUS_PATH_INTERFACES "/"); char *obj_path_only; char *next_sep; /* Be a bit paranoid about path */ if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/", dev_path_prefix_len)) return NULL; /* Ensure there's something at the end of the path */ if ((path + dev_path_prefix_len)[0] == '\0') return NULL; obj_path_only = os_strdup(path); if (obj_path_only == NULL) return NULL; next_sep = strchr(obj_path_only + dev_path_prefix_len, '/'); if (next_sep != NULL) { const char *net_part = strstr(next_sep, WPAS_DBUS_NETWORKS_PART "/"); const char *bssid_part = strstr(next_sep, WPAS_DBUS_BSSIDS_PART "/"); if (network && net_part) { /* Deal with a request for a configured network */ const char *net_name = net_part + strlen(WPAS_DBUS_NETWORKS_PART "/"); *network = NULL; if (strlen(net_name)) *network = os_strdup(net_name); } else if (bssid && bssid_part) { /* Deal with a request for a scanned BSSID */ const char *bssid_name = bssid_part + strlen(WPAS_DBUS_BSSIDS_PART "/"); if (strlen(bssid_name)) *bssid = os_strdup(bssid_name); else *bssid = NULL; } /* Cut off interface object path before "/" */ *next_sep = '\0'; } return obj_path_only; } /** * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message * @message: Pointer to incoming dbus message this error refers to * Returns: A dbus error message * * Convenience function to create and return an invalid interface error */ DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message) { return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE, "wpa_supplicant knows nothing about " "this interface."); } /** * wpas_dbus_new_invalid_network_error - Return a new invalid network error message * @message: Pointer to incoming dbus message this error refers to * Returns: a dbus error message * * Convenience function to create and return an invalid network error */ DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message) { return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK, "The requested network does not exist."); } /** * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message * @message: Pointer to incoming dbus message this error refers to * Returns: a dbus error message * * Convenience function to create and return an invalid bssid error */ static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message) { return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID, "The BSSID requested was invalid."); } /** * wpas_dispatch_network_method - dispatch messages for configured networks * @message: the incoming dbus message * @wpa_s: a network interface's data * @network_id: id of the configured network we're interested in * Returns: a reply dbus message, or a dbus error message * * This function dispatches all incoming dbus messages for configured networks. */ static DBusMessage * wpas_dispatch_network_method(DBusMessage *message, struct wpa_supplicant *wpa_s, int network_id) { DBusMessage *reply = NULL; const char *method = dbus_message_get_member(message); struct wpa_ssid *ssid; ssid = wpa_config_get_network(wpa_s->conf, network_id); if (ssid == NULL) return wpas_dbus_new_invalid_network_error(message); if (!strcmp(method, "set")) reply = wpas_dbus_iface_set_network(message, wpa_s, ssid); else if (!strcmp(method, "enable")) reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid); else if (!strcmp(method, "disable")) reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid); return reply; } /** * wpas_dispatch_bssid_method - dispatch messages for scanned networks * @message: the incoming dbus message * @wpa_s: a network interface's data * @bssid: bssid of the scanned network we're interested in * Returns: a reply dbus message, or a dbus error message * * This function dispatches all incoming dbus messages for scanned networks. */ static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message, struct wpa_supplicant *wpa_s, const char *bssid_txt) { u8 bssid[ETH_ALEN]; struct wpa_bss *bss; if (hexstr2bin(bssid_txt, bssid, ETH_ALEN) < 0) return wpas_dbus_new_invalid_bssid_error(message); bss = wpa_bss_get_bssid(wpa_s, bssid); if (bss == NULL) return wpas_dbus_new_invalid_bssid_error(message); /* Dispatch the method call against the scanned bssid */ if (os_strcmp(dbus_message_get_member(message), "properties") == 0) return wpas_dbus_bssid_properties(message, wpa_s, bss); return NULL; } /** * wpas_iface_message_handler - Dispatch messages for interfaces or networks * @connection: Connection to the system message bus * @message: An incoming dbus message * @user_data: A pointer to a dbus control interface data structure * Returns: Whether or not the message was handled * * This function dispatches all incoming dbus messages for network interfaces, * or objects owned by them, such as scanned BSSIDs and configured networks. */ static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection, DBusMessage *message, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *method = dbus_message_get_member(message); const char *path = dbus_message_get_path(message); const char *msg_interface = dbus_message_get_interface(message); char *iface_obj_path = NULL; char *network = NULL; char *bssid = NULL; DBusMessage *reply = NULL; /* Caller must specify a message interface */ if (!msg_interface) goto out; iface_obj_path = wpas_dbus_decompose_object_path(path, &network, &bssid); if (iface_obj_path == NULL) { reply = wpas_dbus_new_invalid_iface_error(message); goto out; } /* Make sure the message's object path actually refers to the * wpa_supplicant structure it's supposed to (which is wpa_s) */ if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global, iface_obj_path) != wpa_s) { reply = wpas_dbus_new_invalid_iface_error(message); goto out; } if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) { /* A method for one of this interface's configured networks */ int nid = strtoul(network, NULL, 10); if (errno != EINVAL) reply = wpas_dispatch_network_method(message, wpa_s, nid); else reply = wpas_dbus_new_invalid_network_error(message); } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) { /* A method for one of this interface's scanned BSSIDs */ reply = wpas_dispatch_bssid_method(message, wpa_s, bssid); } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) { /* A method for an interface only. */ if (!strcmp(method, "scan")) reply = wpas_dbus_iface_scan(message, wpa_s); else if (!strcmp(method, "scanResults")) reply = wpas_dbus_iface_scan_results(message, wpa_s); else if (!strcmp(method, "addNetwork")) reply = wpas_dbus_iface_add_network(message, wpa_s); else if (!strcmp(method, "removeNetwork")) reply = wpas_dbus_iface_remove_network(message, wpa_s); else if (!strcmp(method, "selectNetwork")) reply = wpas_dbus_iface_select_network(message, wpa_s); else if (!strcmp(method, "capabilities")) reply = wpas_dbus_iface_capabilities(message, wpa_s); else if (!strcmp(method, "disconnect")) reply = wpas_dbus_iface_disconnect(message, wpa_s); else if (!strcmp(method, "setAPScan")) reply = wpas_dbus_iface_set_ap_scan(message, wpa_s); else if (!strcmp(method, "setSmartcardModules")) reply = wpas_dbus_iface_set_smartcard_modules(message, wpa_s); else if (!strcmp(method, "state")) reply = wpas_dbus_iface_get_state(message, wpa_s); else if (!strcmp(method, "scanning")) reply = wpas_dbus_iface_get_scanning(message, wpa_s); #ifndef CONFIG_NO_CONFIG_BLOBS else if (!strcmp(method, "setBlobs")) reply = wpas_dbus_iface_set_blobs(message, wpa_s); else if (!strcmp(method, "removeBlobs")) reply = wpas_dbus_iface_remove_blobs(message, wpa_s); #endif /* CONFIG_NO_CONFIG_BLOBS */ #ifdef CONFIG_WPS else if (!os_strcmp(method, "wpsPbc")) reply = wpas_dbus_iface_wps_pbc(message, wpa_s); else if (!os_strcmp(method, "wpsPin")) reply = wpas_dbus_iface_wps_pin(message, wpa_s); else if (!os_strcmp(method, "wpsReg")) reply = wpas_dbus_iface_wps_reg(message, wpa_s); #endif /* CONFIG_WPS */ else if (!os_strcmp(method, "flush")) reply = wpas_dbus_iface_flush(message, wpa_s); } /* If the message was handled, send back the reply */ if (reply) { if (!dbus_message_get_no_reply(message)) dbus_connection_send(connection, reply, NULL); dbus_message_unref(reply); } out: os_free(iface_obj_path); os_free(network); os_free(bssid); return reply ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } /** * wpas_message_handler - dispatch incoming dbus messages * @connection: connection to the system message bus * @message: an incoming dbus message * @user_data: a pointer to a dbus control interface data structure * Returns: whether or not the message was handled * * This function dispatches all incoming dbus messages to the correct * handlers, depending on what the message's target object path is, * and what the method call is. */ static DBusHandlerResult wpas_message_handler(DBusConnection *connection, DBusMessage *message, void *user_data) { struct wpas_dbus_priv *ctrl_iface = user_data; const char *method; const char *path; const char *msg_interface; DBusMessage *reply = NULL; method = dbus_message_get_member(message); path = dbus_message_get_path(message); msg_interface = dbus_message_get_interface(message); if (!method || !path || !ctrl_iface || !msg_interface) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; /* Validate the method interface */ if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; if (!strcmp(path, WPAS_DBUS_PATH)) { /* dispatch methods against our global dbus interface here */ if (!strcmp(method, "addInterface")) { reply = wpas_dbus_global_add_interface( message, ctrl_iface->global); } else if (!strcmp(method, "removeInterface")) { reply = wpas_dbus_global_remove_interface( message, ctrl_iface->global); } else if (!strcmp(method, "getInterface")) { reply = wpas_dbus_global_get_interface( message, ctrl_iface->global); } else if (!strcmp(method, "setDebugParams")) { reply = wpas_dbus_global_set_debugparams( message, ctrl_iface->global); } } /* If the message was handled, send back the reply */ if (reply) { if (!dbus_message_get_no_reply(message)) dbus_connection_send(connection, reply, NULL); dbus_message_unref(reply); } return reply ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } /** * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal * @wpa_s: %wpa_supplicant network interface data * Returns: 0 on success, -1 on failure * * Notify listeners that this interface has updated scan results. */ void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) { struct wpas_dbus_priv *iface = wpa_s->global->dbus; DBusMessage *_signal; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; _signal = dbus_message_new_signal(wpa_s->dbus_path, WPAS_DBUS_IFACE_INTERFACE, "ScanResultsAvailable"); if (_signal == NULL) { wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan " "results signal"); return; } dbus_connection_send(iface->con, _signal, NULL); dbus_message_unref(_signal); } /** * wpa_supplicant_dbus_notify_state_change - Send a state change signal * @wpa_s: %wpa_supplicant network interface data * @new_state: new state wpa_supplicant is entering * @old_state: old state wpa_supplicant is leaving * Returns: 0 on success, -1 on failure * * Notify listeners that wpa_supplicant has changed state */ void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, enum wpa_states new_state, enum wpa_states old_state) { struct wpas_dbus_priv *iface; DBusMessage *_signal = NULL; const char *new_state_str, *old_state_str; if (wpa_s->dbus_path == NULL) return; /* Skip signal since D-Bus setup is not yet ready */ /* Do nothing if the control interface is not turned on */ if (wpa_s->global == NULL) return; iface = wpa_s->global->dbus; if (iface == NULL) return; /* Only send signal if state really changed */ if (new_state == old_state) return; _signal = dbus_message_new_signal(wpa_s->dbus_path, WPAS_DBUS_IFACE_INTERFACE, "StateChange"); if (_signal == NULL) { wpa_printf(MSG_ERROR, "dbus: wpa_supplicant_dbus_notify_state_change: " "could not create dbus signal; likely out of " "memory"); return; } new_state_str = wpa_supplicant_state_txt(new_state); old_state_str = wpa_supplicant_state_txt(old_state); if (new_state_str == NULL || old_state_str == NULL) { wpa_printf(MSG_ERROR, "dbus: wpa_supplicant_dbus_notify_state_change: " "Could not convert state strings"); goto out; } if (!dbus_message_append_args(_signal, DBUS_TYPE_STRING, &new_state_str, DBUS_TYPE_STRING, &old_state_str, DBUS_TYPE_INVALID)) { wpa_printf(MSG_ERROR, "dbus: wpa_supplicant_dbus_notify_state_change: " "Not enough memory to construct state change " "signal"); goto out; } dbus_connection_send(iface->con, _signal, NULL); out: dbus_message_unref(_signal); } /** * wpa_supplicant_dbus_notify_scanning - send scanning status * @wpa_s: %wpa_supplicant network interface data * Returns: 0 on success, -1 on failure * * Notify listeners of interface scanning state changes */ void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s) { struct wpas_dbus_priv *iface = wpa_s->global->dbus; DBusMessage *_signal; dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; _signal = dbus_message_new_signal(wpa_s->dbus_path, WPAS_DBUS_IFACE_INTERFACE, "Scanning"); if (_signal == NULL) { wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan " "results signal"); return; } if (dbus_message_append_args(_signal, DBUS_TYPE_BOOLEAN, &scanning, DBUS_TYPE_INVALID)) { dbus_connection_send(iface->con, _signal, NULL); } else { wpa_printf(MSG_ERROR, "dbus: Not enough memory to construct " "signal"); } dbus_message_unref(_signal); } #ifdef CONFIG_WPS void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, const struct wps_credential *cred) { struct wpas_dbus_priv *iface; DBusMessage *_signal = NULL; /* Do nothing if the control interface is not turned on */ if (wpa_s->global == NULL) return; iface = wpa_s->global->dbus; if (iface == NULL) return; _signal = dbus_message_new_signal(wpa_s->dbus_path, WPAS_DBUS_IFACE_INTERFACE, "WpsCred"); if (_signal == NULL) { wpa_printf(MSG_ERROR, "dbus: wpa_supplicant_dbus_notify_wps_cred: " "Could not create dbus signal; likely out of " "memory"); return; } if (!dbus_message_append_args(_signal, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &cred->cred_attr, cred->cred_attr_len, DBUS_TYPE_INVALID)) { wpa_printf(MSG_ERROR, "dbus: wpa_supplicant_dbus_notify_wps_cred: " "Not enough memory to construct signal"); goto out; } dbus_connection_send(iface->con, _signal, NULL); out: dbus_message_unref(_signal); } #else /* CONFIG_WPS */ void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, const struct wps_credential *cred) { } #endif /* CONFIG_WPS */ void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s, int depth, const char *subject, const char *cert_hash, const struct wpabuf *cert) { struct wpas_dbus_priv *iface; DBusMessage *_signal = NULL; const char *hash; const char *cert_hex; int cert_hex_len; /* Do nothing if the control interface is not turned on */ if (wpa_s->global == NULL) return; iface = wpa_s->global->dbus; if (iface == NULL) return; _signal = dbus_message_new_signal(wpa_s->dbus_path, WPAS_DBUS_IFACE_INTERFACE, "Certification"); if (_signal == NULL) { wpa_printf(MSG_ERROR, "dbus: wpa_supplicant_dbus_notify_certification: " "Could not create dbus signal; likely out of " "memory"); return; } hash = cert_hash ? cert_hash : ""; cert_hex = cert ? wpabuf_head(cert) : ""; cert_hex_len = cert ? wpabuf_len(cert) : 0; if (!dbus_message_append_args(_signal, DBUS_TYPE_INT32,&depth, DBUS_TYPE_STRING, &subject, DBUS_TYPE_STRING, &hash, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &cert_hex, cert_hex_len, DBUS_TYPE_INVALID)) { wpa_printf(MSG_ERROR, "dbus: wpa_supplicant_dbus_notify_certification: " "Not enough memory to construct signal"); goto out; } dbus_connection_send(iface->con, _signal, NULL); out: dbus_message_unref(_signal); } /** * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface * @global: Pointer to global data from wpa_supplicant_init() * Returns: 0 on success, -1 on failure * * Initialize the dbus control interface and start receiving commands from * external programs over the bus. */ int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface) { DBusError error; int ret = -1; DBusObjectPathVTable wpas_vtable = { NULL, &wpas_message_handler, NULL, NULL, NULL, NULL }; /* Register the message handler for the global dbus interface */ if (!dbus_connection_register_object_path(iface->con, WPAS_DBUS_PATH, &wpas_vtable, iface)) { wpa_printf(MSG_ERROR, "dbus: Could not set up message " "handler"); return -1; } /* Register our service with the message bus */ dbus_error_init(&error); switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE, 0, &error)) { case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: ret = 0; break; case DBUS_REQUEST_NAME_REPLY_EXISTS: case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: wpa_printf(MSG_ERROR, "dbus: Could not request service name: " "already registered"); break; default: wpa_printf(MSG_ERROR, "dbus: Could not request service name: " "%s %s", error.name, error.message); break; } dbus_error_free(&error); if (ret != 0) return -1; wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE "'."); return 0; } /** * wpas_dbus_register_new_iface - Register a new interface with dbus * @wpa_s: %wpa_supplicant interface description structure to register * Returns: 0 on success, -1 on error * * Registers a new interface with dbus and assigns it a dbus object path. */ int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) { struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus; DBusConnection * con; u32 next; DBusObjectPathVTable vtable = { NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL }; /* Do nothing if the control interface is not turned on */ if (ctrl_iface == NULL) return 0; con = ctrl_iface->con; next = ctrl_iface->next_objid++; /* Create and set the interface's object path */ wpa_s->dbus_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); if (wpa_s->dbus_path == NULL) return -1; os_snprintf(wpa_s->dbus_path, WPAS_DBUS_OBJECT_PATH_MAX, WPAS_DBUS_PATH_INTERFACES "/%u", next); /* Register the message handler for the interface functions */ if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable, wpa_s)) { wpa_printf(MSG_ERROR, "dbus: Could not set up message " "handler for interface %s", wpa_s->ifname); return -1; } return 0; } /** * wpas_dbus_unregister_iface - Unregister an interface from dbus * @wpa_s: wpa_supplicant interface structure * Returns: 0 on success, -1 on failure * * Unregisters the interface with dbus */ int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) { struct wpas_dbus_priv *ctrl_iface; DBusConnection *con; /* Do nothing if the control interface is not turned on */ if (wpa_s == NULL || wpa_s->global == NULL) return 0; ctrl_iface = wpa_s->global->dbus; if (ctrl_iface == NULL) return 0; con = ctrl_iface->con; if (!dbus_connection_unregister_object_path(con, wpa_s->dbus_path)) return -1; os_free(wpa_s->dbus_path); wpa_s->dbus_path = NULL; return 0; } /** * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface * @global: Pointer to global data from wpa_supplicant_init() * @path: Pointer to a dbus object path representing an interface * Returns: Pointer to the interface or %NULL if not found */ struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path( struct wpa_global *global, const char *path) { struct wpa_supplicant *wpa_s; for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { if (strcmp(wpa_s->dbus_path, path) == 0) return wpa_s; } return NULL; } wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_new.c0000664000175000017500000030576212343617166020174 0ustar jmjm/* * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * Copyright (c) 2009-2010, Witold Sowa * Copyright (c) 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 "common/ieee802_11_defs.h" #include "wps/wps.h" #include "../config.h" #include "../wpa_supplicant_i.h" #include "../bss.h" #include "../wpas_glue.h" #include "dbus_new_helpers.h" #include "dbus_dict_helpers.h" #include "dbus_new.h" #include "dbus_new_handlers.h" #include "dbus_common_i.h" #include "dbus_new_handlers_p2p.h" #include "p2p/p2p.h" #ifdef CONFIG_AP /* until needed by something else */ /* * NameOwnerChanged handling * * Some services we provide allow an application to register for * a signal that it needs. While it can also unregister, we must * be prepared for the case where the application simply crashes * and thus doesn't clean up properly. The way to handle this in * DBus is to register for the NameOwnerChanged signal which will * signal an owner change to NULL if the peer closes the socket * for whatever reason. * * Handle this signal via a filter function whenever necessary. * The code below also handles refcounting in case in the future * there will be multiple instances of this subscription scheme. */ static const char wpas_dbus_noc_filter_str[] = "interface=org.freedesktop.DBus,member=NameOwnerChanged"; static DBusHandlerResult noc_filter(DBusConnection *conn, DBusMessage *message, void *data) { struct wpas_dbus_priv *priv = data; if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { const char *name; const char *prev_owner; const char *new_owner; DBusError derr; struct wpa_supplicant *wpa_s; dbus_error_init(&derr); if (!dbus_message_get_args(message, &derr, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &prev_owner, DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID)) { /* Ignore this error */ dbus_error_free(&derr); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next) { if (wpa_s->preq_notify_peer != NULL && os_strcmp(name, wpa_s->preq_notify_peer) == 0 && (new_owner == NULL || os_strlen(new_owner) == 0)) { /* probe request owner disconnected */ os_free(wpa_s->preq_notify_peer); wpa_s->preq_notify_peer = NULL; wpas_dbus_unsubscribe_noc(priv); } } } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv) { priv->dbus_noc_refcnt++; if (priv->dbus_noc_refcnt > 1) return; if (!dbus_connection_add_filter(priv->con, noc_filter, priv, NULL)) { wpa_printf(MSG_ERROR, "dbus: failed to add filter"); return; } dbus_bus_add_match(priv->con, wpas_dbus_noc_filter_str, NULL); } void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv) { priv->dbus_noc_refcnt--; if (priv->dbus_noc_refcnt > 0) return; dbus_bus_remove_match(priv->con, wpas_dbus_noc_filter_str, NULL); dbus_connection_remove_filter(priv->con, noc_filter, priv); } #endif /* CONFIG_AP */ /** * wpas_dbus_signal_interface - Send a interface related event signal * @wpa_s: %wpa_supplicant network interface data * @sig_name: signal name - InterfaceAdded or InterfaceRemoved * @properties: Whether to add second argument with object properties * * Notify listeners about event related with interface */ static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s, const char *sig_name, int properties) { struct wpas_dbus_priv *iface; DBusMessage *msg; DBusMessageIter iter; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(WPAS_DBUS_NEW_PATH, WPAS_DBUS_NEW_INTERFACE, sig_name); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &wpa_s->dbus_new_path)) goto err; if (properties) { if (!wpa_dbus_get_object_properties( iface, wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_INTERFACE, &iter)) goto err; } dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); return; err: wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); dbus_message_unref(msg); } /** * wpas_dbus_signal_interface_added - Send a interface created signal * @wpa_s: %wpa_supplicant network interface data * * Notify listeners about creating new interface */ static void wpas_dbus_signal_interface_added(struct wpa_supplicant *wpa_s) { wpas_dbus_signal_interface(wpa_s, "InterfaceAdded", TRUE); } /** * wpas_dbus_signal_interface_removed - Send a interface removed signal * @wpa_s: %wpa_supplicant network interface data * * Notify listeners about removing interface */ static void wpas_dbus_signal_interface_removed(struct wpa_supplicant *wpa_s) { wpas_dbus_signal_interface(wpa_s, "InterfaceRemoved", FALSE); } /** * wpas_dbus_signal_scan_done - send scan done signal * @wpa_s: %wpa_supplicant network interface data * @success: indicates if scanning succeed or failed * * Notify listeners about finishing a scan */ void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success) { struct wpas_dbus_priv *iface; DBusMessage *msg; dbus_bool_t succ; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_INTERFACE, "ScanDone"); if (msg == NULL) return; succ = success ? TRUE : FALSE; if (dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &succ, DBUS_TYPE_INVALID)) dbus_connection_send(iface->con, msg, NULL); else wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); dbus_message_unref(msg); } /** * wpas_dbus_signal_blob - Send a BSS related event signal * @wpa_s: %wpa_supplicant network interface data * @bss_obj_path: BSS object path * @sig_name: signal name - BSSAdded or BSSRemoved * @properties: Whether to add second argument with object properties * * Notify listeners about event related with BSS */ static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s, const char *bss_obj_path, const char *sig_name, int properties) { struct wpas_dbus_priv *iface; DBusMessage *msg; DBusMessageIter iter; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &bss_obj_path)) goto err; if (properties) { if (!wpa_dbus_get_object_properties(iface, bss_obj_path, WPAS_DBUS_NEW_IFACE_BSS, &iter)) goto err; } dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); return; err: wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); dbus_message_unref(msg); } /** * wpas_dbus_signal_bss_added - Send a BSS added signal * @wpa_s: %wpa_supplicant network interface data * @bss_obj_path: new BSS object path * * Notify listeners about adding new BSS */ static void wpas_dbus_signal_bss_added(struct wpa_supplicant *wpa_s, const char *bss_obj_path) { wpas_dbus_signal_bss(wpa_s, bss_obj_path, "BSSAdded", TRUE); } /** * wpas_dbus_signal_bss_removed - Send a BSS removed signal * @wpa_s: %wpa_supplicant network interface data * @bss_obj_path: BSS object path * * Notify listeners about removing BSS */ static void wpas_dbus_signal_bss_removed(struct wpa_supplicant *wpa_s, const char *bss_obj_path) { wpas_dbus_signal_bss(wpa_s, bss_obj_path, "BSSRemoved", FALSE); } /** * wpas_dbus_signal_blob - Send a blob related event signal * @wpa_s: %wpa_supplicant network interface data * @name: blob name * @sig_name: signal name - BlobAdded or BlobRemoved * * Notify listeners about event related with blob */ static void wpas_dbus_signal_blob(struct wpa_supplicant *wpa_s, const char *name, const char *sig_name) { struct wpas_dbus_priv *iface; DBusMessage *msg; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name); if (msg == NULL) return; if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) dbus_connection_send(iface->con, msg, NULL); else wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); dbus_message_unref(msg); } /** * wpas_dbus_signal_blob_added - Send a blob added signal * @wpa_s: %wpa_supplicant network interface data * @name: blob name * * Notify listeners about adding a new blob */ void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s, const char *name) { wpas_dbus_signal_blob(wpa_s, name, "BlobAdded"); } /** * wpas_dbus_signal_blob_removed - Send a blob removed signal * @wpa_s: %wpa_supplicant network interface data * @name: blob name * * Notify listeners about removing blob */ void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s, const char *name) { wpas_dbus_signal_blob(wpa_s, name, "BlobRemoved"); } /** * wpas_dbus_signal_network - Send a network related event signal * @wpa_s: %wpa_supplicant network interface data * @id: new network id * @sig_name: signal name - NetworkAdded, NetworkRemoved or NetworkSelected * @properties: determines if add second argument with object properties * * Notify listeners about event related with configured network */ static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s, int id, const char *sig_name, int properties) { struct wpas_dbus_priv *iface; DBusMessage *msg; DBusMessageIter iter; char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", wpa_s->dbus_new_path, id); msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); path = net_obj_path; if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path)) goto err; if (properties) { if (!wpa_dbus_get_object_properties( iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK, &iter)) goto err; } dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); return; err: wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); dbus_message_unref(msg); } /** * wpas_dbus_signal_network_added - Send a network added signal * @wpa_s: %wpa_supplicant network interface data * @id: new network id * * Notify listeners about adding new network */ static void wpas_dbus_signal_network_added(struct wpa_supplicant *wpa_s, int id) { wpas_dbus_signal_network(wpa_s, id, "NetworkAdded", TRUE); } /** * wpas_dbus_signal_network_removed - Send a network removed signal * @wpa_s: %wpa_supplicant network interface data * @id: network id * * Notify listeners about removing a network */ static void wpas_dbus_signal_network_removed(struct wpa_supplicant *wpa_s, int id) { wpas_dbus_signal_network(wpa_s, id, "NetworkRemoved", FALSE); } /** * wpas_dbus_signal_network_selected - Send a network selected signal * @wpa_s: %wpa_supplicant network interface data * @id: network id * * Notify listeners about selecting a network */ void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id) { wpas_dbus_signal_network(wpa_s, id, "NetworkSelected", FALSE); } /** * wpas_dbus_signal_network_request - Indicate that additional information * (EAP password, etc.) is required to complete the association to this SSID * @wpa_s: %wpa_supplicant network interface data * @rtype: The specific additional information required * @default_text: Optional description of required information * * Request additional information or passwords to complete an association * request. */ void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, enum wpa_ctrl_req_type rtype, const char *default_txt) { struct wpas_dbus_priv *iface; DBusMessage *msg; DBusMessageIter iter; char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; const char *field, *txt = NULL, *net_ptr; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; field = wpa_supplicant_ctrl_req_to_string(rtype, default_txt, &txt); if (field == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_INTERFACE, "NetworkRequest"); if (msg == NULL) return; os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", wpa_s->dbus_new_path, ssid->id); net_ptr = &net_obj_path[0]; dbus_message_iter_init_append(msg, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &net_ptr)) goto err; if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field)) goto err; if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt)) goto err; dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); return; err: wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); dbus_message_unref(msg); } /** * wpas_dbus_signal_network_enabled_changed - Signals Enabled property changes * @wpa_s: %wpa_supplicant network interface data * @ssid: configured network which Enabled property has changed * * Sends PropertyChanged signals containing new value of Enabled property * for specified network */ void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { char path[WPAS_DBUS_OBJECT_PATH_MAX]; os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", wpa_s->dbus_new_path, ssid->id); wpa_dbus_mark_property_changed(wpa_s->global->dbus, path, WPAS_DBUS_NEW_IFACE_NETWORK, "Enabled"); } #ifdef CONFIG_WPS /** * wpas_dbus_signal_wps_event_success - Signals Success WPS event * @wpa_s: %wpa_supplicant network interface data * * Sends Event dbus signal with name "success" and empty dict as arguments */ void wpas_dbus_signal_wps_event_success(struct wpa_supplicant *wpa_s) { DBusMessage *msg; DBusMessageIter iter, dict_iter; struct wpas_dbus_priv *iface; char *key = "success"; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_WPS, "Event"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) || !wpa_dbus_dict_open_write(&iter, &dict_iter) || !wpa_dbus_dict_close_write(&iter, &dict_iter)) wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); else dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); } /** * wpas_dbus_signal_wps_event_fail - Signals Fail WPS event * @wpa_s: %wpa_supplicant network interface data * * Sends Event dbus signal with name "fail" and dictionary containing * "msg field with fail message number (int32) as arguments */ void wpas_dbus_signal_wps_event_fail(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail) { DBusMessage *msg; DBusMessageIter iter, dict_iter; struct wpas_dbus_priv *iface; char *key = "fail"; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_WPS, "Event"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) || !wpa_dbus_dict_open_write(&iter, &dict_iter) || !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) || !wpa_dbus_dict_close_write(&iter, &dict_iter)) wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); else dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); } /** * wpas_dbus_signal_wps_event_m2d - Signals M2D WPS event * @wpa_s: %wpa_supplicant network interface data * * Sends Event dbus signal with name "m2d" and dictionary containing * fields of wps_event_m2d structure. */ void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s, struct wps_event_m2d *m2d) { DBusMessage *msg; DBusMessageIter iter, dict_iter; struct wpas_dbus_priv *iface; char *key = "m2d"; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_WPS, "Event"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) || !wpa_dbus_dict_open_write(&iter, &dict_iter) || !wpa_dbus_dict_append_uint16(&dict_iter, "config_methods", m2d->config_methods) || !wpa_dbus_dict_append_byte_array(&dict_iter, "manufacturer", (const char *) m2d->manufacturer, m2d->manufacturer_len) || !wpa_dbus_dict_append_byte_array(&dict_iter, "model_name", (const char *) m2d->model_name, m2d->model_name_len) || !wpa_dbus_dict_append_byte_array(&dict_iter, "model_number", (const char *) m2d->model_number, m2d->model_number_len) || !wpa_dbus_dict_append_byte_array(&dict_iter, "serial_number", (const char *) m2d->serial_number, m2d->serial_number_len) || !wpa_dbus_dict_append_byte_array(&dict_iter, "dev_name", (const char *) m2d->dev_name, m2d->dev_name_len) || !wpa_dbus_dict_append_byte_array(&dict_iter, "primary_dev_type", (const char *) m2d->primary_dev_type, 8) || !wpa_dbus_dict_append_uint16(&dict_iter, "config_error", m2d->config_error) || !wpa_dbus_dict_append_uint16(&dict_iter, "dev_password_id", m2d->dev_password_id) || !wpa_dbus_dict_close_write(&iter, &dict_iter)) wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); else dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); } /** * wpas_dbus_signal_wps_cred - Signals new credentials * @wpa_s: %wpa_supplicant network interface data * * Sends signal with credentials in directory argument */ void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s, const struct wps_credential *cred) { DBusMessage *msg; DBusMessageIter iter, dict_iter; struct wpas_dbus_priv *iface; char *auth_type[5]; /* we have five possible authentication types */ int at_num = 0; char *encr_type[3]; /* we have three possible encryption types */ int et_num = 0; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_WPS, "Credentials"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) goto nomem; if (cred->auth_type & WPS_AUTH_OPEN) auth_type[at_num++] = "open"; if (cred->auth_type & WPS_AUTH_WPAPSK) auth_type[at_num++] = "wpa-psk"; if (cred->auth_type & WPS_AUTH_WPA) auth_type[at_num++] = "wpa-eap"; if (cred->auth_type & WPS_AUTH_WPA2) auth_type[at_num++] = "wpa2-eap"; if (cred->auth_type & WPS_AUTH_WPA2PSK) auth_type[at_num++] = "wpa2-psk"; if (cred->encr_type & WPS_ENCR_NONE) encr_type[et_num++] = "none"; if (cred->encr_type & WPS_ENCR_TKIP) encr_type[et_num++] = "tkip"; if (cred->encr_type & WPS_ENCR_AES) encr_type[et_num++] = "aes"; if (wpa_s->current_ssid) { if (!wpa_dbus_dict_append_byte_array( &dict_iter, "BSSID", (const char *) wpa_s->current_ssid->bssid, ETH_ALEN)) goto nomem; } if (!wpa_dbus_dict_append_byte_array(&dict_iter, "SSID", (const char *) cred->ssid, cred->ssid_len) || !wpa_dbus_dict_append_string_array(&dict_iter, "AuthType", (const char **) auth_type, at_num) || !wpa_dbus_dict_append_string_array(&dict_iter, "EncrType", (const char **) encr_type, et_num) || !wpa_dbus_dict_append_byte_array(&dict_iter, "Key", (const char *) cred->key, cred->key_len) || !wpa_dbus_dict_append_uint32(&dict_iter, "KeyIndex", cred->key_idx) || !wpa_dbus_dict_close_write(&iter, &dict_iter)) goto nomem; dbus_connection_send(iface->con, msg, NULL); nomem: dbus_message_unref(msg); } #endif /* CONFIG_WPS */ void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s, int depth, const char *subject, const char *cert_hash, const struct wpabuf *cert) { struct wpas_dbus_priv *iface; DBusMessage *msg; DBusMessageIter iter, dict_iter; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_INTERFACE, "Certification"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) goto nomem; if (!wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) || !wpa_dbus_dict_append_string(&dict_iter, "subject", subject)) goto nomem; if (cert_hash && !wpa_dbus_dict_append_string(&dict_iter, "cert_hash", cert_hash)) goto nomem; if (cert && !wpa_dbus_dict_append_byte_array(&dict_iter, "cert", wpabuf_head(cert), wpabuf_len(cert))) goto nomem; if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) goto nomem; dbus_connection_send(iface->con, msg, NULL); nomem: dbus_message_unref(msg); } void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s, const char *status, const char *parameter) { struct wpas_dbus_priv *iface; DBusMessage *msg; DBusMessageIter iter; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_INTERFACE, "EAP"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status) || !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, ¶meter)) goto nomem; dbus_connection_send(iface->con, msg, NULL); nomem: dbus_message_unref(msg); } /** * wpas_dbus_signal_sta - Send a station related event signal * @wpa_s: %wpa_supplicant network interface data * @sta: station mac address * @sig_name: signal name - StaAuthorized or StaDeauthorized * * Notify listeners about event related with station */ static void wpas_dbus_signal_sta(struct wpa_supplicant *wpa_s, const u8 *sta, const char *sig_name) { struct wpas_dbus_priv *iface; DBusMessage *msg; char sta_mac[WPAS_DBUS_OBJECT_PATH_MAX]; char *dev_mac; os_snprintf(sta_mac, WPAS_DBUS_OBJECT_PATH_MAX, MACSTR, MAC2STR(sta)); dev_mac = sta_mac; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name); if (msg == NULL) return; if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &dev_mac, DBUS_TYPE_INVALID)) dbus_connection_send(iface->con, msg, NULL); else wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); dbus_message_unref(msg); wpa_printf(MSG_DEBUG, "dbus: Station MAC address '%s' '%s'", sta_mac, sig_name); } /** * wpas_dbus_signal_sta_authorized - Send a STA authorized signal * @wpa_s: %wpa_supplicant network interface data * @sta: station mac address * * Notify listeners a new station has been authorized */ void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *sta) { wpas_dbus_signal_sta(wpa_s, sta, "StaAuthorized"); } /** * wpas_dbus_signal_sta_deauthorized - Send a STA deauthorized signal * @wpa_s: %wpa_supplicant network interface data * @sta: station mac address * * Notify listeners a station has been deauthorized */ void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s, const u8 *sta) { wpas_dbus_signal_sta(wpa_s, sta, "StaDeauthorized"); } #ifdef CONFIG_P2P /** * wpas_dbus_signal_p2p_group_removed - Signals P2P group was removed * @wpa_s: %wpa_supplicant network interface data * @role: role of this device (client or GO) * Sends signal with i/f name and role as string arguments */ void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s, const char *role) { DBusMessage *msg; DBusMessageIter iter; struct wpas_dbus_priv *iface = wpa_s->global->dbus; char *ifname = wpa_s->ifname; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_P2PDEVICE, "GroupFinished"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &ifname)) { wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished" "signal -not enough memory for ifname "); goto err; } if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &role)) wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished" "signal -not enough memory for role "); else dbus_connection_send(iface->con, msg, NULL); err: dbus_message_unref(msg); } /** * wpas_dbus_signal_p2p_provision_discovery - Signals various PD events * * @dev_addr - who sent the request or responded to our request. * @request - Will be 1 if request, 0 for response. * @status - valid only in case of response * @config_methods - wps config methods * @generated_pin - pin to be displayed in case of WPS_CONFIG_DISPLAY method * * Sends following provision discovery related events: * ProvisionDiscoveryRequestDisplayPin * ProvisionDiscoveryResponseDisplayPin * ProvisionDiscoveryRequestEnterPin * ProvisionDiscoveryResponseEnterPin * ProvisionDiscoveryPBCRequest * ProvisionDiscoveryPBCResponse * * TODO:: * ProvisionDiscoveryFailure (timeout case) */ void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request, enum p2p_prov_disc_status status, u16 config_methods, unsigned int generated_pin) { DBusMessage *msg; DBusMessageIter iter; struct wpas_dbus_priv *iface; char *_signal; int add_pin = 0; char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; int error_ret = 1; char pin[9], *p_pin = NULL; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; if (request || !status) { if (config_methods & WPS_CONFIG_DISPLAY) _signal = request ? "ProvisionDiscoveryRequestDisplayPin" : "ProvisionDiscoveryResponseEnterPin"; else if (config_methods & WPS_CONFIG_KEYPAD) _signal = request ? "ProvisionDiscoveryRequestEnterPin" : "ProvisionDiscoveryResponseDisplayPin"; else if (config_methods & WPS_CONFIG_PUSHBUTTON) _signal = request ? "ProvisionDiscoveryPBCRequest" : "ProvisionDiscoveryPBCResponse"; else return; /* Unknown or un-supported method */ } else if (!request && status) /* Explicit check for failure response */ _signal = "ProvisionDiscoveryFailure"; add_pin = ((request && (config_methods & WPS_CONFIG_DISPLAY)) || (!request && !status && (config_methods & WPS_CONFIG_KEYPAD))); if (add_pin) { os_snprintf(pin, sizeof(pin), "%08d", generated_pin); p_pin = pin; } msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_P2PDEVICE, _signal); if (msg == NULL) return; /* Check if this is a known peer */ if (!p2p_peer_known(wpa_s->global->p2p, dev_addr)) goto error; os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(dev_addr)); path = peer_obj_path; dbus_message_iter_init_append(msg, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path)) goto error; if (!request && status) /* Attach status to ProvisionDiscoveryFailure */ error_ret = !dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &status); else error_ret = (add_pin && !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &p_pin)); error: if (!error_ret) dbus_connection_send(iface->con, msg, NULL); else wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); dbus_message_unref(msg); } void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s, const u8 *src, u16 dev_passwd_id) { DBusMessage *msg; DBusMessageIter iter; struct wpas_dbus_priv *iface; char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(src)); path = peer_obj_path; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_P2PDEVICE, "GONegotiationRequest"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path) || !dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16, &dev_passwd_id)) wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); else dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); } static int wpas_dbus_get_group_obj_path(struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, char *group_obj_path) { char group_name[3]; if (os_memcmp(ssid->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN)) return -1; os_memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2); group_name[2] = '\0'; os_snprintf(group_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_GROUPS_PART "/%s", wpa_s->dbus_new_path, group_name); return 0; } /** * wpas_dbus_signal_p2p_group_started - Signals P2P group has * started. Emitted when a group is successfully started * irrespective of the role (client/GO) of the current device * * @wpa_s: %wpa_supplicant network interface data * @ssid: SSID object * @client: this device is P2P client * @network_id: network id of the group started, use instead of ssid->id * to account for persistent groups */ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int client, int network_id) { DBusMessage *msg; DBusMessageIter iter, dict_iter; struct wpas_dbus_priv *iface; iface = wpa_s->parent->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; if (wpa_s->dbus_groupobj_path == NULL) return; /* New interface has been created for this group */ msg = dbus_message_new_signal(wpa_s->parent->dbus_new_path, WPAS_DBUS_NEW_IFACE_P2PDEVICE, "GroupStarted"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) goto nomem; /* * In case the device supports creating a separate interface the * DBus client will need to know the object path for the interface * object this group was created on, so include it here. */ if (!wpa_dbus_dict_append_object_path(&dict_iter, "interface_object", wpa_s->dbus_new_path)) goto nomem; if (!wpa_dbus_dict_append_string(&dict_iter, "role", client ? "client" : "GO")) goto nomem; if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object", wpa_s->dbus_groupobj_path) || !wpa_dbus_dict_close_write(&iter, &dict_iter)) goto nomem; dbus_connection_send(iface->con, msg, NULL); nomem: dbus_message_unref(msg); } /** * * Method to emit GONegotiation Success or Failure signals based * on status. * @status: Status of the GO neg request. 0 for success, other for errors. */ void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *res) { DBusMessage *msg; DBusMessageIter iter, dict_iter; DBusMessageIter iter_dict_entry, iter_dict_val, iter_dict_array; struct wpas_dbus_priv *iface; char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; dbus_int32_t freqs[P2P_MAX_CHANNELS]; dbus_int32_t *f_array = freqs; iface = wpa_s->global->dbus; os_memset(freqs, 0, sizeof(freqs)); /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(res->peer_device_addr)); path = peer_obj_path; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_P2PDEVICE, res->status ? "GONegotiationFailure" : "GONegotiationSuccess"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) goto err; if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object", path) || !wpa_dbus_dict_append_int32(&dict_iter, "status", res->status)) goto err; if (!res->status) { int i = 0; int freq_list_num = 0; if (res->role_go) { if (!wpa_dbus_dict_append_byte_array( &dict_iter, "passphrase", (const char *) res->passphrase, sizeof(res->passphrase))) goto err; } if (!wpa_dbus_dict_append_string(&dict_iter, "role_go", res->role_go ? "GO" : "client") || !wpa_dbus_dict_append_int32(&dict_iter, "frequency", res->freq) || !wpa_dbus_dict_append_byte_array(&dict_iter, "ssid", (const char *) res->ssid, res->ssid_len) || !wpa_dbus_dict_append_byte_array(&dict_iter, "peer_device_addr", (const char *) res->peer_device_addr, ETH_ALEN) || !wpa_dbus_dict_append_byte_array(&dict_iter, "peer_interface_addr", (const char *) res->peer_interface_addr, ETH_ALEN) || !wpa_dbus_dict_append_string(&dict_iter, "wps_method", p2p_wps_method_text( res->wps_method))) goto err; for (i = 0; i < P2P_MAX_CHANNELS; i++) { if (res->freq_list[i]) { freqs[i] = res->freq_list[i]; freq_list_num++; } } if (!wpa_dbus_dict_begin_array(&dict_iter, "frequency_list", DBUS_TYPE_INT32_AS_STRING, &iter_dict_entry, &iter_dict_val, &iter_dict_array)) goto err; if (!dbus_message_iter_append_fixed_array(&iter_dict_array, DBUS_TYPE_INT32, &f_array, freq_list_num)) goto err; if (!wpa_dbus_dict_end_array(&dict_iter, &iter_dict_entry, &iter_dict_val, &iter_dict_array)) goto err; if (!wpa_dbus_dict_append_int32(&dict_iter, "persistent_group", res->persistent_group) || !wpa_dbus_dict_append_uint32(&dict_iter, "peer_config_timeout", res->peer_config_timeout)) goto err; } if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) goto err; dbus_connection_send(iface->con, msg, NULL); err: dbus_message_unref(msg); } /** * * Method to emit Invitation Result signal based on status and * bssid * @status: Status of the Invite request. 0 for success, other * for errors * @bssid : Basic Service Set Identifier */ void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s, int status, const u8 *bssid) { DBusMessage *msg; DBusMessageIter iter, dict_iter; struct wpas_dbus_priv *iface; wpa_printf(MSG_DEBUG, "%s", __func__); iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_P2PDEVICE, "InvitationResult"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) goto nomem; if (!wpa_dbus_dict_append_int32(&dict_iter, "status", status)) goto nomem; if (bssid) { if (!wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID", (const char *) bssid, ETH_ALEN)) goto nomem; } if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) goto nomem; dbus_connection_send(iface->con, msg, NULL); nomem: dbus_message_unref(msg); } /** * * Method to emit a signal for a peer joining the group. * The signal will carry path to the group member object * constructed using p2p i/f addr used for connecting. * * @wpa_s: %wpa_supplicant network interface data * @member_addr: addr (p2p i/f) of the peer joining the group */ void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s, const u8 *member) { struct wpas_dbus_priv *iface; DBusMessage *msg; DBusMessageIter iter; char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; if (!wpa_s->dbus_groupobj_path) return; os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_groupobj_path, MAC2STR(member)); msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path, WPAS_DBUS_NEW_IFACE_P2P_GROUP, "PeerJoined"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); path = groupmember_obj_path; if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path)) goto err; dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); return; err: wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); dbus_message_unref(msg); } /** * * Method to emit a signal for a peer disconnecting the group. * The signal will carry path to the group member object * constructed using p2p i/f addr used for connecting. * * @wpa_s: %wpa_supplicant network interface data * @member_addr: addr (p2p i/f) of the peer joining the group */ void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s, const u8 *member) { struct wpas_dbus_priv *iface; DBusMessage *msg; DBusMessageIter iter; char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; if (!wpa_s->dbus_groupobj_path) return; os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_groupobj_path, MAC2STR(member)); msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path, WPAS_DBUS_NEW_IFACE_P2P_GROUP, "PeerDisconnected"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); path = groupmember_obj_path; if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path)) goto err; dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); return; err: wpa_printf(MSG_ERROR, "dbus: Failed to construct PeerDisconnected " "signal"); dbus_message_unref(msg); } /** * * Method to emit a signal for a service discovery request. * The signal will carry station address, frequency, dialog token, * update indicator and it tlvs * * @wpa_s: %wpa_supplicant network interface data * @sa: station addr (p2p i/f) of the peer * @dialog_token: service discovery request dialog token * @update_indic: service discovery request update indicator * @tlvs: service discovery request genrated byte array of tlvs * @tlvs_len: service discovery request tlvs length */ void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s, int freq, const u8 *sa, u8 dialog_token, u16 update_indic, const u8 *tlvs, size_t tlvs_len) { DBusMessage *msg; DBusMessageIter iter, dict_iter; struct wpas_dbus_priv *iface; char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ServiceDiscoveryRequest"); if (msg == NULL) return; /* Check if this is a known peer */ if (!p2p_peer_known(wpa_s->global->p2p, sa)) goto error; os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa)); path = peer_obj_path; dbus_message_iter_init_append(msg, &iter); if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) goto error; if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object", path) || !wpa_dbus_dict_append_int32(&dict_iter, "frequency", freq) || !wpa_dbus_dict_append_int32(&dict_iter, "dialog_token", dialog_token) || !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator", update_indic) || !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs", (const char *) tlvs, tlvs_len) || !wpa_dbus_dict_close_write(&iter, &dict_iter)) goto error; dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); return; error: wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); dbus_message_unref(msg); } /** * * Method to emit a signal for a service discovery response. * The signal will carry station address, update indicator and it * tlvs * * @wpa_s: %wpa_supplicant network interface data * @sa: station addr (p2p i/f) of the peer * @update_indic: service discovery request update indicator * @tlvs: service discovery request genrated byte array of tlvs * @tlvs_len: service discovery request tlvs length */ void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic, const u8 *tlvs, size_t tlvs_len) { DBusMessage *msg; DBusMessageIter iter, dict_iter; struct wpas_dbus_priv *iface; char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ServiceDiscoveryResponse"); if (msg == NULL) return; /* Check if this is a known peer */ if (!p2p_peer_known(wpa_s->global->p2p, sa)) goto error; os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa)); path = peer_obj_path; dbus_message_iter_init_append(msg, &iter); if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) goto error; if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object", path) || !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator", update_indic) || !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs", (const char *) tlvs, tlvs_len) || !wpa_dbus_dict_close_write(&iter, &dict_iter)) goto error; dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); return; error: wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); dbus_message_unref(msg); } /** * wpas_dbus_signal_persistent_group - Send a persistent group related * event signal * @wpa_s: %wpa_supplicant network interface data * @id: new persistent group id * @sig_name: signal name - PersistentGroupAdded, PersistentGroupRemoved * @properties: determines if add second argument with object properties * * Notify listeners about an event related to persistent groups. */ static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s, int id, const char *sig_name, int properties) { struct wpas_dbus_priv *iface; DBusMessage *msg; DBusMessageIter iter; char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u", wpa_s->dbus_new_path, id); msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_P2PDEVICE, sig_name); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); path = pgrp_obj_path; if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path)) goto err; if (properties) { if (!wpa_dbus_get_object_properties( iface, pgrp_obj_path, WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter)) goto err; } dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); return; err: wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); dbus_message_unref(msg); } /** * wpas_dbus_signal_persistent_group_added - Send a persistent_group * added signal * @wpa_s: %wpa_supplicant network interface data * @id: new persistent group id * * Notify listeners about addition of a new persistent group. */ static void wpas_dbus_signal_persistent_group_added( struct wpa_supplicant *wpa_s, int id) { wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupAdded", TRUE); } /** * wpas_dbus_signal_persistent_group_removed - Send a persistent_group * removed signal * @wpa_s: %wpa_supplicant network interface data * @id: persistent group id * * Notify listeners about removal of a persistent group. */ static void wpas_dbus_signal_persistent_group_removed( struct wpa_supplicant *wpa_s, int id) { wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupRemoved", FALSE); } /** * wpas_dbus_signal_p2p_wps_failed - Signals WpsFailed event * @wpa_s: %wpa_supplicant network interface data * * Sends Event dbus signal with name "fail" and dictionary containing * "msg" field with fail message number (int32) as arguments */ void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail) { DBusMessage *msg; DBusMessageIter iter, dict_iter; struct wpas_dbus_priv *iface; char *key = "fail"; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_P2PDEVICE, "WpsFailed"); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) || !wpa_dbus_dict_open_write(&iter, &dict_iter) || !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) || !wpa_dbus_dict_append_int16(&dict_iter, "config_error", fail->config_error) || !wpa_dbus_dict_close_write(&iter, &dict_iter)) wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); else dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); } #endif /*CONFIG_P2P*/ /** * wpas_dbus_signal_prop_changed - Signals change of property * @wpa_s: %wpa_supplicant network interface data * @property: indicates which property has changed * * Sends PropertyChanged signals with path, interface and arguments * depending on which property has changed. */ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s, enum wpas_dbus_prop property) { char *prop; dbus_bool_t flush; if (wpa_s->dbus_new_path == NULL) return; /* Skip signal since D-Bus setup is not yet ready */ flush = FALSE; switch (property) { case WPAS_DBUS_PROP_AP_SCAN: prop = "ApScan"; break; case WPAS_DBUS_PROP_SCANNING: prop = "Scanning"; break; case WPAS_DBUS_PROP_STATE: prop = "State"; break; case WPAS_DBUS_PROP_CURRENT_BSS: prop = "CurrentBSS"; break; case WPAS_DBUS_PROP_CURRENT_NETWORK: prop = "CurrentNetwork"; break; case WPAS_DBUS_PROP_BSSS: prop = "BSSs"; break; case WPAS_DBUS_PROP_CURRENT_AUTH_MODE: prop = "CurrentAuthMode"; break; case WPAS_DBUS_PROP_DISCONNECT_REASON: prop = "DisconnectReason"; flush = TRUE; break; default: wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d", __func__, property); return; } wpa_dbus_mark_property_changed(wpa_s->global->dbus, wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_INTERFACE, prop); if (flush) { wpa_dbus_flush_object_changed_properties( wpa_s->global->dbus->con, wpa_s->dbus_new_path); } } /** * wpas_dbus_bss_signal_prop_changed - Signals change of BSS property * @wpa_s: %wpa_supplicant network interface data * @property: indicates which property has changed * @id: unique BSS identifier * * Sends PropertyChanged signals with path, interface, and arguments depending * on which property has changed. */ void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s, enum wpas_dbus_bss_prop property, unsigned int id) { char path[WPAS_DBUS_OBJECT_PATH_MAX]; char *prop; switch (property) { case WPAS_DBUS_BSS_PROP_SIGNAL: prop = "Signal"; break; case WPAS_DBUS_BSS_PROP_FREQ: prop = "Frequency"; break; case WPAS_DBUS_BSS_PROP_MODE: prop = "Mode"; break; case WPAS_DBUS_BSS_PROP_PRIVACY: prop = "Privacy"; break; case WPAS_DBUS_BSS_PROP_RATES: prop = "Rates"; break; case WPAS_DBUS_BSS_PROP_WPA: prop = "WPA"; break; case WPAS_DBUS_BSS_PROP_RSN: prop = "RSN"; break; case WPAS_DBUS_BSS_PROP_WPS: prop = "WPS"; break; case WPAS_DBUS_BSS_PROP_IES: prop = "IEs"; break; default: wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d", __func__, property); return; } os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", wpa_s->dbus_new_path, id); wpa_dbus_mark_property_changed(wpa_s->global->dbus, path, WPAS_DBUS_NEW_IFACE_BSS, prop); } /** * wpas_dbus_signal_debug_level_changed - Signals change of debug param * @global: wpa_global structure * * Sends PropertyChanged signals informing that debug level has changed. */ void wpas_dbus_signal_debug_level_changed(struct wpa_global *global) { wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH, WPAS_DBUS_NEW_INTERFACE, "DebugLevel"); } /** * wpas_dbus_signal_debug_timestamp_changed - Signals change of debug param * @global: wpa_global structure * * Sends PropertyChanged signals informing that debug timestamp has changed. */ void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global) { wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH, WPAS_DBUS_NEW_INTERFACE, "DebugTimestamp"); } /** * wpas_dbus_signal_debug_show_keys_changed - Signals change of debug param * @global: wpa_global structure * * Sends PropertyChanged signals informing that debug show_keys has changed. */ void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global) { wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH, WPAS_DBUS_NEW_INTERFACE, "DebugShowKeys"); } static void wpas_dbus_register(struct wpa_dbus_object_desc *obj_desc, void *priv, WPADBusArgumentFreeFunction priv_free, const struct wpa_dbus_method_desc *methods, const struct wpa_dbus_property_desc *properties, const struct wpa_dbus_signal_desc *signals) { int n; obj_desc->user_data = priv; obj_desc->user_data_free_func = priv_free; obj_desc->methods = methods; obj_desc->properties = properties; obj_desc->signals = signals; for (n = 0; properties && properties->dbus_property; properties++) n++; obj_desc->prop_changed_flags = os_zalloc(n); if (!obj_desc->prop_changed_flags) wpa_printf(MSG_DEBUG, "dbus: %s: can't register handlers", __func__); } static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = { { "CreateInterface", WPAS_DBUS_NEW_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_create_interface, { { "args", "a{sv}", ARG_IN }, { "path", "o", ARG_OUT }, END_ARGS } }, { "RemoveInterface", WPAS_DBUS_NEW_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_remove_interface, { { "path", "o", ARG_IN }, END_ARGS } }, { "GetInterface", WPAS_DBUS_NEW_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_get_interface, { { "ifname", "s", ARG_IN }, { "path", "o", ARG_OUT }, END_ARGS } }, { NULL, NULL, NULL, { END_ARGS } } }; static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = { { "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s", wpas_dbus_getter_debug_level, wpas_dbus_setter_debug_level }, { "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b", wpas_dbus_getter_debug_timestamp, wpas_dbus_setter_debug_timestamp }, { "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b", wpas_dbus_getter_debug_show_keys, wpas_dbus_setter_debug_show_keys }, { "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao", wpas_dbus_getter_interfaces, NULL }, { "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as", wpas_dbus_getter_eap_methods, NULL }, { "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as", wpas_dbus_getter_global_capabilities, NULL }, { NULL, NULL, NULL, NULL, NULL } }; static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = { { "InterfaceAdded", WPAS_DBUS_NEW_INTERFACE, { { "path", "o", ARG_OUT }, { "properties", "a{sv}", ARG_OUT }, END_ARGS } }, { "InterfaceRemoved", WPAS_DBUS_NEW_INTERFACE, { { "path", "o", ARG_OUT }, END_ARGS } }, { "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "path", "o", ARG_OUT }, { "field", "s", ARG_OUT }, { "text", "s", ARG_OUT }, END_ARGS } }, /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */ { "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE, { { "properties", "a{sv}", ARG_OUT }, END_ARGS } }, { NULL, NULL, { END_ARGS } } }; /** * wpas_dbus_ctrl_iface_init - Initialize dbus control interface * @global: Pointer to global data from wpa_supplicant_init() * Returns: 0 on success or -1 on failure * * Initialize the dbus control interface for wpa_supplicantand and start * receiving commands from external programs over the bus. */ int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv) { struct wpa_dbus_object_desc *obj_desc; int ret; obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); if (!obj_desc) { wpa_printf(MSG_ERROR, "Not enough memory " "to create object description"); return -1; } wpas_dbus_register(obj_desc, priv->global, NULL, wpas_dbus_global_methods, wpas_dbus_global_properties, wpas_dbus_global_signals); wpa_printf(MSG_DEBUG, "dbus: Register D-Bus object '%s'", WPAS_DBUS_NEW_PATH); ret = wpa_dbus_ctrl_iface_init(priv, WPAS_DBUS_NEW_PATH, WPAS_DBUS_NEW_SERVICE, obj_desc); if (ret < 0) free_dbus_object_desc(obj_desc); else priv->dbus_new_initialized = 1; return ret; } /** * wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for * wpa_supplicant * @iface: Pointer to dbus private data from wpas_dbus_init() * * Deinitialize the dbus control interface that was initialized with * wpas_dbus_ctrl_iface_init(). */ void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface) { if (!iface->dbus_new_initialized) return; wpa_printf(MSG_DEBUG, "dbus: Unregister D-Bus object '%s'", WPAS_DBUS_NEW_PATH); dbus_connection_unregister_object_path(iface->con, WPAS_DBUS_NEW_PATH); } static void wpa_dbus_free(void *ptr) { os_free(ptr); } static const struct wpa_dbus_property_desc wpas_dbus_network_properties[] = { { "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}", wpas_dbus_getter_network_properties, wpas_dbus_setter_network_properties }, { "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b", wpas_dbus_getter_enabled, wpas_dbus_setter_enabled }, { NULL, NULL, NULL, NULL, NULL } }; static const struct wpa_dbus_signal_desc wpas_dbus_network_signals[] = { /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */ { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_NETWORK, { { "properties", "a{sv}", ARG_OUT }, END_ARGS } }, { NULL, NULL, { END_ARGS } } }; /** * wpas_dbus_register_network - Register a configured network with dbus * @wpa_s: wpa_supplicant interface structure * @ssid: network configuration data * Returns: 0 on success, -1 on failure * * Registers network representing object with dbus */ int wpas_dbus_register_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct wpas_dbus_priv *ctrl_iface; struct wpa_dbus_object_desc *obj_desc; struct network_handler_args *arg; char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; #ifdef CONFIG_P2P /* * If it is a persistent group register it as such. * This is to handle cases where an interface is being initialized * with a list of networks read from config. */ if (network_is_persistent_group(ssid)) return wpas_dbus_register_persistent_group(wpa_s, ssid); #endif /* CONFIG_P2P */ /* Do nothing if the control interface is not turned on */ if (wpa_s == NULL || wpa_s->global == NULL) return 0; ctrl_iface = wpa_s->global->dbus; if (ctrl_iface == NULL) return 0; os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", wpa_s->dbus_new_path, ssid->id); wpa_printf(MSG_DEBUG, "dbus: Register network object '%s'", net_obj_path); obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); if (!obj_desc) { wpa_printf(MSG_ERROR, "Not enough memory " "to create object description"); goto err; } /* allocate memory for handlers arguments */ arg = os_zalloc(sizeof(struct network_handler_args)); if (!arg) { wpa_printf(MSG_ERROR, "Not enough memory " "to create arguments for method"); goto err; } arg->wpa_s = wpa_s; arg->ssid = ssid; wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL, wpas_dbus_network_properties, wpas_dbus_network_signals); if (wpa_dbus_register_object_per_iface(ctrl_iface, net_obj_path, wpa_s->ifname, obj_desc)) goto err; wpas_dbus_signal_network_added(wpa_s, ssid->id); return 0; err: free_dbus_object_desc(obj_desc); return -1; } /** * wpas_dbus_unregister_network - Unregister a configured network from dbus * @wpa_s: wpa_supplicant interface structure * @nid: network id * Returns: 0 on success, -1 on failure * * Unregisters network representing object from dbus */ int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid) { struct wpas_dbus_priv *ctrl_iface; char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; int ret; #ifdef CONFIG_P2P struct wpa_ssid *ssid; ssid = wpa_config_get_network(wpa_s->conf, nid); /* If it is a persistent group unregister it as such */ if (ssid && network_is_persistent_group(ssid)) return wpas_dbus_unregister_persistent_group(wpa_s, nid); #endif /* CONFIG_P2P */ /* Do nothing if the control interface is not turned on */ if (wpa_s->global == NULL || wpa_s->dbus_new_path == NULL) return 0; ctrl_iface = wpa_s->global->dbus; if (ctrl_iface == NULL) return 0; os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", wpa_s->dbus_new_path, nid); wpa_printf(MSG_DEBUG, "dbus: Unregister network object '%s'", net_obj_path); ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, net_obj_path); if (!ret) wpas_dbus_signal_network_removed(wpa_s, nid); return ret; } static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = { { "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay", wpas_dbus_getter_bss_ssid, NULL }, { "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay", wpas_dbus_getter_bss_bssid, NULL }, { "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b", wpas_dbus_getter_bss_privacy, NULL }, { "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s", wpas_dbus_getter_bss_mode, NULL }, { "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n", wpas_dbus_getter_bss_signal, NULL }, { "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q", wpas_dbus_getter_bss_frequency, NULL }, { "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au", wpas_dbus_getter_bss_rates, NULL }, { "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}", wpas_dbus_getter_bss_wpa, NULL }, { "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}", wpas_dbus_getter_bss_rsn, NULL }, { "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}", wpas_dbus_getter_bss_wps, NULL }, { "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay", wpas_dbus_getter_bss_ies, NULL }, { NULL, NULL, NULL, NULL, NULL } }; static const struct wpa_dbus_signal_desc wpas_dbus_bss_signals[] = { /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */ { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_BSS, { { "properties", "a{sv}", ARG_OUT }, END_ARGS } }, { NULL, NULL, { END_ARGS } } }; /** * wpas_dbus_unregister_bss - Unregister a scanned BSS from dbus * @wpa_s: wpa_supplicant interface structure * @bssid: scanned network bssid * @id: unique BSS identifier * Returns: 0 on success, -1 on failure * * Unregisters BSS representing object from dbus */ int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s, u8 bssid[ETH_ALEN], unsigned int id) { struct wpas_dbus_priv *ctrl_iface; char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; /* Do nothing if the control interface is not turned on */ if (wpa_s == NULL || wpa_s->global == NULL) return 0; ctrl_iface = wpa_s->global->dbus; if (ctrl_iface == NULL) return 0; os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", wpa_s->dbus_new_path, id); wpa_printf(MSG_DEBUG, "dbus: Unregister BSS object '%s'", bss_obj_path); if (wpa_dbus_unregister_object_per_iface(ctrl_iface, bss_obj_path)) { wpa_printf(MSG_ERROR, "dbus: Cannot unregister BSS object %s", bss_obj_path); return -1; } wpas_dbus_signal_bss_removed(wpa_s, bss_obj_path); wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS); return 0; } /** * wpas_dbus_register_bss - Register a scanned BSS with dbus * @wpa_s: wpa_supplicant interface structure * @bssid: scanned network bssid * @id: unique BSS identifier * Returns: 0 on success, -1 on failure * * Registers BSS representing object with dbus */ int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s, u8 bssid[ETH_ALEN], unsigned int id) { struct wpas_dbus_priv *ctrl_iface; struct wpa_dbus_object_desc *obj_desc; char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; struct bss_handler_args *arg; /* Do nothing if the control interface is not turned on */ if (wpa_s == NULL || wpa_s->global == NULL) return 0; ctrl_iface = wpa_s->global->dbus; if (ctrl_iface == NULL) return 0; os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", wpa_s->dbus_new_path, id); obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); if (!obj_desc) { wpa_printf(MSG_ERROR, "Not enough memory " "to create object description"); goto err; } arg = os_zalloc(sizeof(struct bss_handler_args)); if (!arg) { wpa_printf(MSG_ERROR, "Not enough memory " "to create arguments for handler"); goto err; } arg->wpa_s = wpa_s; arg->id = id; wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL, wpas_dbus_bss_properties, wpas_dbus_bss_signals); wpa_printf(MSG_DEBUG, "dbus: Register BSS object '%s'", bss_obj_path); if (wpa_dbus_register_object_per_iface(ctrl_iface, bss_obj_path, wpa_s->ifname, obj_desc)) { wpa_printf(MSG_ERROR, "Cannot register BSSID dbus object %s.", bss_obj_path); goto err; } wpas_dbus_signal_bss_added(wpa_s, bss_obj_path); wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS); return 0; err: free_dbus_object_desc(obj_desc); return -1; } static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { { "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_scan, { { "args", "a{sv}", ARG_IN }, END_ARGS } }, { "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_disconnect, { END_ARGS } }, { "AddNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_add_network, { { "args", "a{sv}", ARG_IN }, { "path", "o", ARG_OUT }, END_ARGS } }, { "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_reassociate, { END_ARGS } }, { "Reattach", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_reattach, { END_ARGS } }, { "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_remove_network, { { "path", "o", ARG_IN }, END_ARGS } }, { "RemoveAllNetworks", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_remove_all_networks, { END_ARGS } }, { "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_select_network, { { "path", "o", ARG_IN }, END_ARGS } }, { "NetworkReply", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_network_reply, { { "path", "o", ARG_IN }, { "field", "s", ARG_IN }, { "value", "s", ARG_IN }, END_ARGS } }, #ifndef CONFIG_NO_CONFIG_BLOBS { "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_add_blob, { { "name", "s", ARG_IN }, { "data", "ay", ARG_IN }, END_ARGS } }, { "GetBlob", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_get_blob, { { "name", "s", ARG_IN }, { "data", "ay", ARG_OUT }, END_ARGS } }, { "RemoveBlob", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_remove_blob, { { "name", "s", ARG_IN }, END_ARGS } }, #endif /* CONFIG_NO_CONFIG_BLOBS */ { "SetPKCS11EngineAndModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_set_pkcs11_engine_and_module_path, { { "pkcs11_engine_path", "s", ARG_IN }, { "pkcs11_module_path", "s", ARG_IN }, END_ARGS } }, #ifdef CONFIG_WPS { "Start", WPAS_DBUS_NEW_IFACE_WPS, (WPADBusMethodHandler) &wpas_dbus_handler_wps_start, { { "args", "a{sv}", ARG_IN }, { "output", "a{sv}", ARG_OUT }, END_ARGS } }, #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P { "Find", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_find, { { "args", "a{sv}", ARG_IN }, END_ARGS } }, { "StopFind", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_stop_find, { END_ARGS } }, { "Listen", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_listen, { { "timeout", "i", ARG_IN }, END_ARGS } }, { "ExtendedListen", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_extendedlisten, { { "args", "a{sv}", ARG_IN }, END_ARGS } }, { "PresenceRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_presence_request, { { "args", "a{sv}", ARG_IN }, END_ARGS } }, { "ProvisionDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_prov_disc_req, { { "peer", "o", ARG_IN }, { "config_method", "s", ARG_IN }, END_ARGS } }, { "Connect", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_connect, { { "args", "a{sv}", ARG_IN }, { "generated_pin", "s", ARG_OUT }, END_ARGS } }, { "GroupAdd", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_group_add, { { "args", "a{sv}", ARG_IN }, END_ARGS } }, { "Invite", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_invite, { { "args", "a{sv}", ARG_IN }, END_ARGS } }, { "Disconnect", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_disconnect, { END_ARGS } }, { "RejectPeer", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_rejectpeer, { { "peer", "o", ARG_IN }, END_ARGS } }, { "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush, { END_ARGS } }, { "AddService", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_add_service, { { "args", "a{sv}", ARG_IN }, END_ARGS } }, { "DeleteService", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_delete_service, { { "args", "a{sv}", ARG_IN }, END_ARGS } }, { "FlushService", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush_service, { END_ARGS } }, { "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_req, { { "args", "a{sv}", ARG_IN }, { "ref", "t", ARG_OUT }, END_ARGS } }, { "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_res, { { "args", "a{sv}", ARG_IN }, END_ARGS } }, { "ServiceDiscoveryCancelRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_cancel_req, { { "args", "t", ARG_IN }, END_ARGS } }, { "ServiceUpdate", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_update, { END_ARGS } }, { "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external, { { "arg", "i", ARG_IN }, END_ARGS } }, { "AddPersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler) wpas_dbus_handler_add_persistent_group, { { "args", "a{sv}", ARG_IN }, { "path", "o", ARG_OUT }, END_ARGS } }, { "RemovePersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler) wpas_dbus_handler_remove_persistent_group, { { "path", "o", ARG_IN }, END_ARGS } }, { "RemoveAllPersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, (WPADBusMethodHandler) wpas_dbus_handler_remove_all_persistent_groups, { END_ARGS } }, #endif /* CONFIG_P2P */ { "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_flush_bss, { { "age", "u", ARG_IN }, END_ARGS } }, #ifdef CONFIG_AP { "SubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) wpas_dbus_handler_subscribe_preq, { END_ARGS } }, { "UnsubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) wpas_dbus_handler_unsubscribe_preq, { END_ARGS } }, #endif /* CONFIG_AP */ { "EAPLogoff", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_eap_logoff, { END_ARGS } }, { "EAPLogon", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_eap_logon, { END_ARGS } }, #ifdef CONFIG_AUTOSCAN { "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_autoscan, { { "arg", "s", ARG_IN }, END_ARGS } }, #endif /* CONFIG_AUTOSCAN */ #ifdef CONFIG_TDLS { "TDLSDiscover", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) wpas_dbus_handler_tdls_discover, { { "peer_address", "s", ARG_IN }, END_ARGS } }, { "TDLSSetup", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) wpas_dbus_handler_tdls_setup, { { "peer_address", "s", ARG_IN }, END_ARGS } }, { "TDLSStatus", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) wpas_dbus_handler_tdls_status, { { "peer_address", "s", ARG_IN }, { "status", "s", ARG_OUT }, END_ARGS } }, { "TDLSTeardown", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) wpas_dbus_handler_tdls_teardown, { { "peer_address", "s", ARG_IN }, END_ARGS } }, #endif /* CONFIG_TDLS */ { NULL, NULL, NULL, { END_ARGS } } }; static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = { { "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}", wpas_dbus_getter_capabilities, NULL }, { "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_state, NULL }, { "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b", wpas_dbus_getter_scanning, NULL }, { "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", wpas_dbus_getter_ap_scan, wpas_dbus_setter_ap_scan }, { "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", wpas_dbus_getter_bss_expire_age, wpas_dbus_setter_bss_expire_age }, { "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", wpas_dbus_getter_bss_expire_count, wpas_dbus_setter_bss_expire_count }, { "Country", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_country, wpas_dbus_setter_country }, { "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_ifname, NULL }, { "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_driver, NULL }, { "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_bridge_ifname, NULL }, { "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o", wpas_dbus_getter_current_bss, NULL }, { "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o", wpas_dbus_getter_current_network, NULL }, { "CurrentAuthMode", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_current_auth_mode, NULL }, { "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}", wpas_dbus_getter_blobs, NULL }, { "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao", wpas_dbus_getter_bsss, NULL }, { "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao", wpas_dbus_getter_networks, NULL }, { "FastReauth", WPAS_DBUS_NEW_IFACE_INTERFACE, "b", wpas_dbus_getter_fast_reauth, wpas_dbus_setter_fast_reauth }, { "ScanInterval", WPAS_DBUS_NEW_IFACE_INTERFACE, "i", wpas_dbus_getter_scan_interval, wpas_dbus_setter_scan_interval }, { "PKCS11EnginePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_pkcs11_engine_path, NULL }, { "PKCS11ModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", wpas_dbus_getter_pkcs11_module_path, NULL }, #ifdef CONFIG_WPS { "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b", wpas_dbus_getter_process_credentials, wpas_dbus_setter_process_credentials }, #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P { "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}", wpas_dbus_getter_p2p_device_config, wpas_dbus_setter_p2p_device_config }, { "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao", wpas_dbus_getter_p2p_peers, NULL }, { "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s", wpas_dbus_getter_p2p_role, NULL }, { "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o", wpas_dbus_getter_p2p_group, NULL }, { "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o", wpas_dbus_getter_p2p_peergo, NULL }, { "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao", wpas_dbus_getter_persistent_groups, NULL }, #endif /* CONFIG_P2P */ { "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i", wpas_dbus_getter_disconnect_reason, NULL }, { NULL, NULL, NULL, NULL, NULL } }; static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = { { "ScanDone", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "success", "b", ARG_OUT }, END_ARGS } }, { "BSSAdded", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "path", "o", ARG_OUT }, { "properties", "a{sv}", ARG_OUT }, END_ARGS } }, { "BSSRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "path", "o", ARG_OUT }, END_ARGS } }, { "BlobAdded", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "name", "s", ARG_OUT }, END_ARGS } }, { "BlobRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "name", "s", ARG_OUT }, END_ARGS } }, { "NetworkAdded", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "path", "o", ARG_OUT }, { "properties", "a{sv}", ARG_OUT }, END_ARGS } }, { "NetworkRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "path", "o", ARG_OUT }, END_ARGS } }, { "NetworkSelected", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "path", "o", ARG_OUT }, END_ARGS } }, /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */ { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "properties", "a{sv}", ARG_OUT }, END_ARGS } }, #ifdef CONFIG_WPS { "Event", WPAS_DBUS_NEW_IFACE_WPS, { { "name", "s", ARG_OUT }, { "args", "a{sv}", ARG_OUT }, END_ARGS } }, { "Credentials", WPAS_DBUS_NEW_IFACE_WPS, { { "credentials", "a{sv}", ARG_OUT }, END_ARGS } }, /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */ { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_WPS, { { "properties", "a{sv}", ARG_OUT }, END_ARGS } }, #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P { "P2PStateChanged", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "states", "a{ss}", ARG_OUT }, END_ARGS } }, { "DeviceFound", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "path", "o", ARG_OUT }, END_ARGS } }, { "DeviceLost", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "path", "o", ARG_OUT }, END_ARGS } }, { "ProvisionDiscoveryRequestDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "peer_object", "o", ARG_OUT }, { "pin", "s", ARG_OUT }, END_ARGS } }, { "ProvisionDiscoveryResponseDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "peer_object", "o", ARG_OUT }, { "pin", "s", ARG_OUT }, END_ARGS } }, { "ProvisionDiscoveryRequestEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "peer_object", "o", ARG_OUT }, END_ARGS } }, { "ProvisionDiscoveryResponseEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "peer_object", "o", ARG_OUT }, END_ARGS } }, { "ProvisionDiscoveryPBCRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "peer_object", "o", ARG_OUT }, END_ARGS } }, { "ProvisionDiscoveryPBCResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "peer_object", "o", ARG_OUT }, END_ARGS } }, { "ProvisionDiscoveryFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "peer_object", "o", ARG_OUT }, { "status", "i", ARG_OUT }, END_ARGS } }, { "GroupStarted", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "properties", "a{sv}", ARG_OUT }, END_ARGS } }, { "GONegotiationSuccess", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "properties", "a{sv}", ARG_OUT }, END_ARGS } }, { "GONegotiationFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "properties", "a{sv}", ARG_OUT }, END_ARGS } }, { "GONegotiationRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "path", "o", ARG_OUT }, { "dev_passwd_id", "i", ARG_OUT }, END_ARGS } }, { "InvitationResult", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "invite_result", "a{sv}", ARG_OUT }, END_ARGS } }, { "GroupFinished", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "ifname", "s", ARG_OUT }, { "role", "s", ARG_OUT }, END_ARGS } }, { "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "sd_request", "a{sv}", ARG_OUT }, END_ARGS } }, { "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "sd_response", "a{sv}", ARG_OUT }, END_ARGS } }, { "PersistentGroupAdded", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "path", "o", ARG_OUT }, { "properties", "a{sv}", ARG_OUT }, END_ARGS } }, { "PersistentGroupRemoved", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "path", "o", ARG_OUT }, END_ARGS } }, { "WpsFailed", WPAS_DBUS_NEW_IFACE_P2PDEVICE, { { "name", "s", ARG_OUT }, { "args", "a{sv}", ARG_OUT }, END_ARGS } }, #endif /* CONFIG_P2P */ #ifdef CONFIG_AP { "ProbeRequest", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "args", "a{sv}", ARG_OUT }, END_ARGS } }, #endif /* CONFIG_AP */ { "Certification", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "certification", "a{sv}", ARG_OUT }, END_ARGS } }, { "EAP", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "status", "s", ARG_OUT }, { "parameter", "s", ARG_OUT }, END_ARGS } }, { "StaAuthorized", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "name", "s", ARG_OUT }, END_ARGS } }, { "StaDeauthorized", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "name", "s", ARG_OUT }, END_ARGS } }, { NULL, NULL, { END_ARGS } } }; int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s) { struct wpa_dbus_object_desc *obj_desc = NULL; struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus; int next; /* Do nothing if the control interface is not turned on */ if (ctrl_iface == NULL) return 0; /* Create and set the interface's object path */ wpa_s->dbus_new_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); if (wpa_s->dbus_new_path == NULL) return -1; next = ctrl_iface->next_objid++; os_snprintf(wpa_s->dbus_new_path, WPAS_DBUS_OBJECT_PATH_MAX, WPAS_DBUS_NEW_PATH_INTERFACES "/%u", next); obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); if (!obj_desc) { wpa_printf(MSG_ERROR, "Not enough memory " "to create object description"); goto err; } wpas_dbus_register(obj_desc, wpa_s, NULL, wpas_dbus_interface_methods, wpas_dbus_interface_properties, wpas_dbus_interface_signals); wpa_printf(MSG_DEBUG, "dbus: Register interface object '%s'", wpa_s->dbus_new_path); if (wpa_dbus_register_object_per_iface(ctrl_iface, wpa_s->dbus_new_path, wpa_s->ifname, obj_desc)) goto err; wpas_dbus_signal_interface_added(wpa_s); return 0; err: os_free(wpa_s->dbus_new_path); wpa_s->dbus_new_path = NULL; free_dbus_object_desc(obj_desc); return -1; } int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s) { struct wpas_dbus_priv *ctrl_iface; /* Do nothing if the control interface is not turned on */ if (wpa_s == NULL || wpa_s->global == NULL) return 0; ctrl_iface = wpa_s->global->dbus; if (ctrl_iface == NULL) return 0; wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'", wpa_s->dbus_new_path); #ifdef CONFIG_AP if (wpa_s->preq_notify_peer) { wpas_dbus_unsubscribe_noc(ctrl_iface); os_free(wpa_s->preq_notify_peer); wpa_s->preq_notify_peer = NULL; } #endif /* CONFIG_AP */ if (wpa_dbus_unregister_object_per_iface(ctrl_iface, wpa_s->dbus_new_path)) return -1; wpas_dbus_signal_interface_removed(wpa_s); os_free(wpa_s->dbus_new_path); wpa_s->dbus_new_path = NULL; return 0; } #ifdef CONFIG_P2P static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = { { "DeviceName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s", wpas_dbus_getter_p2p_peer_device_name, NULL }, { "PrimaryDeviceType", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay", wpas_dbus_getter_p2p_peer_primary_device_type, NULL }, { "config_method", WPAS_DBUS_NEW_IFACE_P2P_PEER, "q", wpas_dbus_getter_p2p_peer_config_method, NULL }, { "level", WPAS_DBUS_NEW_IFACE_P2P_PEER, "i", wpas_dbus_getter_p2p_peer_level, NULL }, { "devicecapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y", wpas_dbus_getter_p2p_peer_device_capability, NULL }, { "groupcapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y", wpas_dbus_getter_p2p_peer_group_capability, NULL }, { "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay", wpas_dbus_getter_p2p_peer_secondary_device_types, NULL }, { "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay", wpas_dbus_getter_p2p_peer_vendor_extension, NULL }, { "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay", wpas_dbus_getter_p2p_peer_ies, NULL }, { "DeviceAddress", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay", wpas_dbus_getter_p2p_peer_device_address, NULL }, { NULL, NULL, NULL, NULL, NULL } }; static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = { { NULL, NULL, { END_ARGS } } }; /** * wpas_dbus_signal_peer - Send a peer related event signal * @wpa_s: %wpa_supplicant network interface data * @dev: peer device object * @interface: name of the interface emitting this signal. * In case of peer objects, it would be emitted by either * the "interface object" or by "peer objects" * @sig_name: signal name - DeviceFound * * Notify listeners about event related with newly found p2p peer device */ static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr, const char *interface, const char *sig_name) { struct wpas_dbus_priv *iface; DBusMessage *msg; DBusMessageIter iter; char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; iface = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (iface == NULL) return; os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(dev_addr)); msg = dbus_message_new_signal(wpa_s->dbus_new_path, interface, sig_name); if (msg == NULL) return; dbus_message_iter_init_append(msg, &iter); path = peer_obj_path; if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path)) goto err; dbus_connection_send(iface->con, msg, NULL); dbus_message_unref(msg); return; err: wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); dbus_message_unref(msg); } /** * wpas_dbus_signal_peer_found - Send a peer found signal * @wpa_s: %wpa_supplicant network interface data * @dev: peer device object * * Notify listeners about find a p2p peer device found */ void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s, const u8 *dev_addr) { wpas_dbus_signal_peer(wpa_s, dev_addr, WPAS_DBUS_NEW_IFACE_P2PDEVICE, "DeviceFound"); } /** * wpas_dbus_signal_peer_lost - Send a peer lost signal * @wpa_s: %wpa_supplicant network interface data * @dev: peer device object * * Notify listeners about lost a p2p peer device */ void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s, const u8 *dev_addr) { wpas_dbus_signal_peer(wpa_s, dev_addr, WPAS_DBUS_NEW_IFACE_P2PDEVICE, "DeviceLost"); } /** * wpas_dbus_register_peer - Register a discovered peer object with dbus * @wpa_s: wpa_supplicant interface structure * @ssid: network configuration data * Returns: 0 on success, -1 on failure * * Registers network representing object with dbus */ int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr) { struct wpas_dbus_priv *ctrl_iface; struct wpa_dbus_object_desc *obj_desc; struct peer_handler_args *arg; char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; /* Do nothing if the control interface is not turned on */ if (wpa_s == NULL || wpa_s->global == NULL) return 0; ctrl_iface = wpa_s->global->dbus; if (ctrl_iface == NULL) return 0; os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(dev_addr)); wpa_printf(MSG_INFO, "dbus: Register peer object '%s'", peer_obj_path); obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); if (!obj_desc) { wpa_printf(MSG_ERROR, "Not enough memory " "to create object description"); goto err; } /* allocate memory for handlers arguments */ arg = os_zalloc(sizeof(struct peer_handler_args)); if (!arg) { wpa_printf(MSG_ERROR, "Not enough memory " "to create arguments for method"); goto err; } arg->wpa_s = wpa_s; os_memcpy(arg->p2p_device_addr, dev_addr, ETH_ALEN); wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL, wpas_dbus_p2p_peer_properties, wpas_dbus_p2p_peer_signals); if (wpa_dbus_register_object_per_iface(ctrl_iface, peer_obj_path, wpa_s->ifname, obj_desc)) goto err; return 0; err: free_dbus_object_desc(obj_desc); return -1; } /** * wpas_dbus_unregister_peer - Unregister a peer object with dbus * @wpa_s: wpa_supplicant interface structure * @dev_addr: p2p device addr * Returns: 0 on success, -1 on failure * * Registers network representing object with dbus */ int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr) { struct wpas_dbus_priv *ctrl_iface; char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; int ret; /* Do nothing if the control interface is not turned on */ if (wpa_s == NULL || wpa_s->global == NULL || wpa_s->dbus_new_path == NULL) return 0; ctrl_iface = wpa_s->global->dbus; if (ctrl_iface == NULL) return 0; os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(dev_addr)); wpa_printf(MSG_INFO, "dbus: Unregister peer object '%s'", peer_obj_path); ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, peer_obj_path); return ret; } static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = { { "Members", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ao", wpas_dbus_getter_p2p_group_members, NULL }, { "Group", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "o", wpas_dbus_getter_p2p_group, NULL }, { "Role", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s", wpas_dbus_getter_p2p_role, NULL }, { "SSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay", wpas_dbus_getter_p2p_group_ssid, NULL }, { "BSSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay", wpas_dbus_getter_p2p_group_bssid, NULL }, { "Frequency", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "q", wpas_dbus_getter_p2p_group_frequency, NULL }, { "Passphrase", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s", wpas_dbus_getter_p2p_group_passphrase, NULL }, { "PSK", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay", wpas_dbus_getter_p2p_group_psk, NULL }, { "WPSVendorExtensions", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "aay", wpas_dbus_getter_p2p_group_vendor_ext, wpas_dbus_setter_p2p_group_vendor_ext }, { NULL, NULL, NULL, NULL, NULL } }; static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = { { "PeerJoined", WPAS_DBUS_NEW_IFACE_P2P_GROUP, { { "peer", "o", ARG_OUT }, END_ARGS } }, { "PeerDisconnected", WPAS_DBUS_NEW_IFACE_P2P_GROUP, { { "peer", "o", ARG_OUT }, END_ARGS } }, { NULL, NULL, { END_ARGS } } }; /** * wpas_dbus_register_p2p_group - Register a p2p group object with dbus * @wpa_s: wpa_supplicant interface structure * @ssid: SSID struct * Returns: 0 on success, -1 on failure * * Registers p2p group representing object with dbus */ void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct wpas_dbus_priv *ctrl_iface; struct wpa_dbus_object_desc *obj_desc; char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; /* Do nothing if the control interface is not turned on */ if (wpa_s == NULL || wpa_s->global == NULL) return; ctrl_iface = wpa_s->global->dbus; if (ctrl_iface == NULL) return; if (wpa_s->dbus_groupobj_path) { wpa_printf(MSG_INFO, "%s: Group object '%s' already exists", __func__, wpa_s->dbus_groupobj_path); return; } if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0) return; wpa_s->dbus_groupobj_path = os_strdup(group_obj_path); if (wpa_s->dbus_groupobj_path == NULL) return; wpa_printf(MSG_INFO, "dbus: Register group object '%s'", group_obj_path); obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); if (!obj_desc) { wpa_printf(MSG_ERROR, "Not enough memory " "to create object description"); goto err; } wpas_dbus_register(obj_desc, wpa_s, NULL, NULL, wpas_dbus_p2p_group_properties, wpas_dbus_p2p_group_signals); if (wpa_dbus_register_object_per_iface(ctrl_iface, group_obj_path, wpa_s->ifname, obj_desc)) goto err; return; err: if (wpa_s->dbus_groupobj_path) { os_free(wpa_s->dbus_groupobj_path); wpa_s->dbus_groupobj_path = NULL; } free_dbus_object_desc(obj_desc); } /** * wpas_dbus_unregister_p2p_group - Unregister a p2p group object from dbus * @wpa_s: wpa_supplicant interface structure * @ssid: network name of the p2p group started */ void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid) { struct wpas_dbus_priv *ctrl_iface; /* Do nothing if the control interface is not turned on */ if (wpa_s == NULL || wpa_s->global == NULL) return; ctrl_iface = wpa_s->global->dbus; if (ctrl_iface == NULL) return; if (!wpa_s->dbus_groupobj_path) { wpa_printf(MSG_DEBUG, "%s: Group object '%s' already unregistered", __func__, wpa_s->dbus_groupobj_path); return; } wpa_printf(MSG_DEBUG, "dbus: Unregister group object '%s'", wpa_s->dbus_groupobj_path); wpa_dbus_unregister_object_per_iface(ctrl_iface, wpa_s->dbus_groupobj_path); os_free(wpa_s->dbus_groupobj_path); wpa_s->dbus_groupobj_path = NULL; } static const struct wpa_dbus_property_desc wpas_dbus_p2p_groupmember_properties[] = { { NULL, NULL, NULL, NULL, NULL } }; /** * wpas_dbus_register_p2p_groupmember - Register a p2p groupmember * object with dbus * @wpa_s: wpa_supplicant interface structure * @p2p_if_addr: i/f addr of the device joining this group * * Registers p2p groupmember representing object with dbus */ void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s, const u8 *p2p_if_addr) { struct wpas_dbus_priv *ctrl_iface; struct wpa_dbus_object_desc *obj_desc = NULL; struct groupmember_handler_args *arg; char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; /* Do nothing if the control interface is not turned on */ if (wpa_s == NULL || wpa_s->global == NULL) return; ctrl_iface = wpa_s->global->dbus; if (ctrl_iface == NULL) return; if (!wpa_s->dbus_groupobj_path) return; os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr)); obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); if (!obj_desc) { wpa_printf(MSG_ERROR, "Not enough memory " "to create object description"); goto err; } /* allocate memory for handlers arguments */ arg = os_zalloc(sizeof(struct groupmember_handler_args)); if (!arg) { wpa_printf(MSG_ERROR, "Not enough memory " "to create arguments for method"); goto err; } arg->wpa_s = wpa_s; os_memcpy(arg->member_addr, p2p_if_addr, ETH_ALEN); wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL, wpas_dbus_p2p_groupmember_properties, NULL); if (wpa_dbus_register_object_per_iface(ctrl_iface, groupmember_obj_path, wpa_s->ifname, obj_desc)) goto err; wpa_printf(MSG_INFO, "dbus: Registered group member object '%s' successfully", groupmember_obj_path); return; err: free_dbus_object_desc(obj_desc); } /** * wpas_dbus_unregister_p2p_groupmember - Unregister a p2p groupmember * object with dbus * @wpa_s: wpa_supplicant interface structure * @p2p_if_addr: i/f addr of the device joining this group * * Unregisters p2p groupmember representing object with dbus */ void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s, const u8 *p2p_if_addr) { struct wpas_dbus_priv *ctrl_iface; char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; /* Do nothing if the control interface is not turned on */ if (wpa_s == NULL || wpa_s->global == NULL) return; ctrl_iface = wpa_s->global->dbus; if (ctrl_iface == NULL) return; if (!wpa_s->dbus_groupobj_path) return; os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr)); wpa_dbus_unregister_object_per_iface(ctrl_iface, groupmember_obj_path); } static const struct wpa_dbus_property_desc wpas_dbus_persistent_group_properties[] = { { "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}", wpas_dbus_getter_persistent_group_properties, wpas_dbus_setter_persistent_group_properties }, { NULL, NULL, NULL, NULL, NULL } }; /* No signals intended for persistent group objects */ /** * wpas_dbus_register_persistent_group - Register a configured(saved) * persistent group with dbus * @wpa_s: wpa_supplicant interface structure * @ssid: persistent group (still represented as a network within wpa) * configuration data * Returns: 0 on success, -1 on failure * * Registers a persistent group representing object with dbus. */ int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct wpas_dbus_priv *ctrl_iface; struct wpa_dbus_object_desc *obj_desc; struct network_handler_args *arg; char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; /* Do nothing if the control interface is not turned on */ if (wpa_s == NULL || wpa_s->global == NULL) return 0; /* Make sure ssid is a persistent group */ if (ssid->disabled != 2 && !ssid->p2p_persistent_group) return -1; /* should we return w/o complaining? */ ctrl_iface = wpa_s->global->dbus; if (ctrl_iface == NULL) return 0; /* * Intentionally not coming up with different numbering scheme * for persistent groups. */ os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u", wpa_s->dbus_new_path, ssid->id); wpa_printf(MSG_DEBUG, "dbus: Register persistent group object '%s'", pgrp_obj_path); obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc)); if (!obj_desc) { wpa_printf(MSG_ERROR, "dbus: Not enough memory to create " "object description"); goto err; } /* * Reusing the same context structure as that for networks * since these are represented using same data structure. */ /* allocate memory for handlers arguments */ arg = os_zalloc(sizeof(struct network_handler_args)); if (!arg) { wpa_printf(MSG_ERROR, "dbus: Not enough memory to create " "arguments for method"); goto err; } arg->wpa_s = wpa_s; arg->ssid = ssid; wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL, wpas_dbus_persistent_group_properties, NULL); if (wpa_dbus_register_object_per_iface(ctrl_iface, pgrp_obj_path, wpa_s->ifname, obj_desc)) goto err; wpas_dbus_signal_persistent_group_added(wpa_s, ssid->id); return 0; err: free_dbus_object_desc(obj_desc); return -1; } /** * wpas_dbus_unregister_persistent_group - Unregister a persistent_group * from dbus * @wpa_s: wpa_supplicant interface structure * @nid: network id * Returns: 0 on success, -1 on failure * * Unregisters persistent group representing object from dbus * * NOTE: There is a slight issue with the semantics here. While the * implementation simply means the persistent group is unloaded from memory, * it should not get interpreted as the group is actually being erased/removed * from persistent storage as well. */ int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s, int nid) { struct wpas_dbus_priv *ctrl_iface; char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX]; int ret; /* Do nothing if the control interface is not turned on */ if (wpa_s == NULL || wpa_s->global == NULL || wpa_s->dbus_new_path == NULL) return 0; ctrl_iface = wpa_s->global->dbus; if (ctrl_iface == NULL) return 0; os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u", wpa_s->dbus_new_path, nid); wpa_printf(MSG_DEBUG, "dbus: Unregister persistent group object '%s'", pgrp_obj_path); ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, pgrp_obj_path); if (!ret) wpas_dbus_signal_persistent_group_removed(wpa_s, nid); return ret; } #endif /* CONFIG_P2P */ wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_dict_helpers.c0000664000175000017500000007046212343617166022044 0ustar jmjm/* * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include #include "common.h" #include "wpabuf.h" #include "dbus_dict_helpers.h" /** * Start a dict in a dbus message. Should be paired with a call to * wpa_dbus_dict_close_write(). * * @param iter A valid dbus message iterator * @param iter_dict (out) A dict iterator to pass to further dict functions * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter, DBusMessageIter *iter_dict) { dbus_bool_t result; if (!iter || !iter_dict) return FALSE; result = dbus_message_iter_open_container( iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, iter_dict); return result; } /** * End a dict element in a dbus message. Should be paired with * a call to wpa_dbus_dict_open_write(). * * @param iter valid dbus message iterator, same as passed to * wpa_dbus_dict_open_write() * @param iter_dict a dbus dict iterator returned from * wpa_dbus_dict_open_write() * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter, DBusMessageIter *iter_dict) { if (!iter || !iter_dict) return FALSE; return dbus_message_iter_close_container(iter, iter_dict); } const char * wpa_dbus_type_as_string(const int type) { switch(type) { case DBUS_TYPE_BYTE: return DBUS_TYPE_BYTE_AS_STRING; case DBUS_TYPE_BOOLEAN: return DBUS_TYPE_BOOLEAN_AS_STRING; case DBUS_TYPE_INT16: return DBUS_TYPE_INT16_AS_STRING; case DBUS_TYPE_UINT16: return DBUS_TYPE_UINT16_AS_STRING; case DBUS_TYPE_INT32: return DBUS_TYPE_INT32_AS_STRING; case DBUS_TYPE_UINT32: return DBUS_TYPE_UINT32_AS_STRING; case DBUS_TYPE_INT64: return DBUS_TYPE_INT64_AS_STRING; case DBUS_TYPE_UINT64: return DBUS_TYPE_UINT64_AS_STRING; case DBUS_TYPE_DOUBLE: return DBUS_TYPE_DOUBLE_AS_STRING; case DBUS_TYPE_STRING: return DBUS_TYPE_STRING_AS_STRING; case DBUS_TYPE_OBJECT_PATH: return DBUS_TYPE_OBJECT_PATH_AS_STRING; case DBUS_TYPE_ARRAY: return DBUS_TYPE_ARRAY_AS_STRING; default: return NULL; } } static dbus_bool_t _wpa_dbus_add_dict_entry_start( DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry, const char *key, const int value_type) { if (!dbus_message_iter_open_container(iter_dict, DBUS_TYPE_DICT_ENTRY, NULL, iter_dict_entry)) return FALSE; if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING, &key)) return FALSE; return TRUE; } static dbus_bool_t _wpa_dbus_add_dict_entry_end( DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry, DBusMessageIter *iter_dict_val) { if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val)) return FALSE; if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry)) return FALSE; return TRUE; } static dbus_bool_t _wpa_dbus_add_dict_entry_basic(DBusMessageIter *iter_dict, const char *key, const int value_type, const void *value) { DBusMessageIter iter_dict_entry, iter_dict_val; const char *type_as_string = NULL; if (key == NULL) return FALSE; type_as_string = wpa_dbus_type_as_string(value_type); if (!type_as_string) return FALSE; if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry, key, value_type)) return FALSE; if (!dbus_message_iter_open_container(&iter_dict_entry, DBUS_TYPE_VARIANT, type_as_string, &iter_dict_val)) return FALSE; if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value)) return FALSE; if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry, &iter_dict_val)) return FALSE; return TRUE; } static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array( DBusMessageIter *iter_dict, const char *key, const char *value, const dbus_uint32_t value_len) { DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; dbus_uint32_t i; if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry, key, DBUS_TYPE_ARRAY)) return FALSE; if (!dbus_message_iter_open_container(&iter_dict_entry, DBUS_TYPE_VARIANT, DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING, &iter_dict_val)) return FALSE; if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &iter_array)) return FALSE; for (i = 0; i < value_len; i++) { if (!dbus_message_iter_append_basic(&iter_array, DBUS_TYPE_BYTE, &(value[i]))) return FALSE; } if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array)) return FALSE; if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry, &iter_dict_val)) return FALSE; return TRUE; } /** * Add a string entry to the dict. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param value The string value * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict, const char *key, const char *value) { if (!value) return FALSE; return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_STRING, &value); } /** * Add a byte entry to the dict. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param value The byte value * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict, const char *key, const char value) { return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE, &value); } /** * Add a boolean entry to the dict. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param value The boolean value * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict, const char *key, const dbus_bool_t value) { return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BOOLEAN, &value); } /** * Add a 16-bit signed integer entry to the dict. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param value The 16-bit signed integer value * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict, const char *key, const dbus_int16_t value) { return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT16, &value); } /** * Add a 16-bit unsigned integer entry to the dict. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param value The 16-bit unsigned integer value * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict, const char *key, const dbus_uint16_t value) { return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT16, &value); } /** * Add a 32-bit signed integer to the dict. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param value The 32-bit signed integer value * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict, const char *key, const dbus_int32_t value) { return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT32, &value); } /** * Add a 32-bit unsigned integer entry to the dict. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param value The 32-bit unsigned integer value * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict, const char *key, const dbus_uint32_t value) { return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT32, &value); } /** * Add a 64-bit integer entry to the dict. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param value The 64-bit integer value * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict, const char *key, const dbus_int64_t value) { return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64, &value); } /** * Add a 64-bit unsigned integer entry to the dict. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param value The 64-bit unsigned integer value * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict, const char *key, const dbus_uint64_t value) { return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64, &value); } /** * Add a double-precision floating point entry to the dict. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param value The double-precision floating point value * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict, const char *key, const double value) { return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE, &value); } /** * Add a DBus object path entry to the dict. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param value The DBus object path value * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict, const char *key, const char *value) { if (!value) return FALSE; return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_OBJECT_PATH, &value); } /** * Add a byte array entry to the dict. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param value The byte array * @param value_len The length of the byte array, in bytes * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict, const char *key, const char *value, const dbus_uint32_t value_len) { if (!key) return FALSE; if (!value && (value_len != 0)) return FALSE; return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value, value_len); } /** * Begin an array entry in the dict * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param type The type of the contained data * @param iter_dict_entry A private DBusMessageIter provided by the caller to * be passed to wpa_dbus_dict_end_string_array() * @param iter_dict_val A private DBusMessageIter provided by the caller to * be passed to wpa_dbus_dict_end_string_array() * @param iter_array On return, the DBusMessageIter to be passed to * wpa_dbus_dict_string_array_add_element() * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict, const char *key, const char *type, DBusMessageIter *iter_dict_entry, DBusMessageIter *iter_dict_val, DBusMessageIter *iter_array) { char array_type[10]; int err; err = os_snprintf(array_type, sizeof(array_type), DBUS_TYPE_ARRAY_AS_STRING "%s", type); if (err < 0 || err > (int) sizeof(array_type)) return FALSE; if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array) return FALSE; if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry, key, DBUS_TYPE_ARRAY)) return FALSE; if (!dbus_message_iter_open_container(iter_dict_entry, DBUS_TYPE_VARIANT, array_type, iter_dict_val)) return FALSE; if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY, type, iter_array)) return FALSE; return TRUE; } dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict, const char *key, DBusMessageIter *iter_dict_entry, DBusMessageIter *iter_dict_val, DBusMessageIter *iter_array) { return wpa_dbus_dict_begin_array( iter_dict, key, DBUS_TYPE_STRING_AS_STRING, iter_dict_entry, iter_dict_val, iter_array); } /** * Add a single string element to a string array dict entry * * @param iter_array A valid DBusMessageIter returned from * wpa_dbus_dict_begin_string_array()'s * iter_array parameter * @param elem The string element to be added to the dict entry's string array * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array, const char *elem) { if (!iter_array || !elem) return FALSE; return dbus_message_iter_append_basic(iter_array, DBUS_TYPE_STRING, &elem); } /** * Add a single byte array element to a string array dict entry * * @param iter_array A valid DBusMessageIter returned from * wpa_dbus_dict_begin_array()'s iter_array * parameter -- note that wpa_dbus_dict_begin_array() * must have been called with "ay" as the type * @param value The data to be added to the dict entry's array * @param value_len The length of the data * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array, const u8 *value, size_t value_len) { DBusMessageIter iter_bytes; size_t i; if (!iter_array || !value) return FALSE; if (!dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &iter_bytes)) return FALSE; for (i = 0; i < value_len; i++) { if (!dbus_message_iter_append_basic(&iter_bytes, DBUS_TYPE_BYTE, &(value[i]))) return FALSE; } if (!dbus_message_iter_close_container(iter_array, &iter_bytes)) return FALSE; return TRUE; } /** * End an array dict entry * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param iter_dict_entry A private DBusMessageIter returned from * wpa_dbus_dict_begin_string_array() or * wpa_dbus_dict_begin_array() * @param iter_dict_val A private DBusMessageIter returned from * wpa_dbus_dict_begin_string_array() or * wpa_dbus_dict_begin_array() * @param iter_array A DBusMessageIter returned from * wpa_dbus_dict_begin_string_array() or * wpa_dbus_dict_begin_array() * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry, DBusMessageIter *iter_dict_val, DBusMessageIter *iter_array) { if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array) return FALSE; if (!dbus_message_iter_close_container(iter_dict_val, iter_array)) return FALSE; if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry, iter_dict_val)) return FALSE; return TRUE; } /** * Convenience function to add an entire string array to the dict. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param items The array of strings * @param num_items The number of strings in the array * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict, const char *key, const char **items, const dbus_uint32_t num_items) { DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; dbus_uint32_t i; if (!key) return FALSE; if (!items && (num_items != 0)) return FALSE; if (!wpa_dbus_dict_begin_string_array(iter_dict, key, &iter_dict_entry, &iter_dict_val, &iter_array)) return FALSE; for (i = 0; i < num_items; i++) { if (!wpa_dbus_dict_string_array_add_element(&iter_array, items[i])) return FALSE; } if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) return FALSE; return TRUE; } /** * Convenience function to add an wpabuf binary array to the dict. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_write() * @param key The key of the dict item * @param items The array of wpabuf structures * @param num_items The number of strings in the array * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict, const char *key, const struct wpabuf **items, const dbus_uint32_t num_items) { DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; dbus_uint32_t i; if (!key) return FALSE; if (!items && (num_items != 0)) return FALSE; if (!wpa_dbus_dict_begin_array(iter_dict, key, DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING, &iter_dict_entry, &iter_dict_val, &iter_array)) return FALSE; for (i = 0; i < num_items; i++) { if (!wpa_dbus_dict_bin_array_add_element(&iter_array, wpabuf_head(items[i]), wpabuf_len(items[i]))) return FALSE; } if (!wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) return FALSE; return TRUE; } /*****************************************************/ /* Stuff for reading dicts */ /*****************************************************/ /** * Start reading from a dbus dict. * * @param iter A valid DBusMessageIter pointing to the start of the dict * @param iter_dict (out) A DBusMessageIter to be passed to * wpa_dbus_dict_read_next_entry() * @error on failure a descriptive error * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter, DBusMessageIter *iter_dict, DBusError *error) { if (!iter || !iter_dict) { dbus_set_error_const(error, DBUS_ERROR_FAILED, "[internal] missing message iterators"); return FALSE; } if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) { dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, "unexpected message argument types"); return FALSE; } dbus_message_iter_recurse(iter, iter_dict); return TRUE; } #define BYTE_ARRAY_CHUNK_SIZE 34 #define BYTE_ARRAY_ITEM_SIZE (sizeof(char)) static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array( DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry) { dbus_uint32_t count = 0; dbus_bool_t success = FALSE; char *buffer, *nbuffer; entry->bytearray_value = NULL; entry->array_type = DBUS_TYPE_BYTE; buffer = os_calloc(BYTE_ARRAY_CHUNK_SIZE, BYTE_ARRAY_ITEM_SIZE); if (!buffer) return FALSE; entry->bytearray_value = buffer; entry->array_len = 0; while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) { char byte; if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) { nbuffer = os_realloc_array( buffer, count + BYTE_ARRAY_CHUNK_SIZE, BYTE_ARRAY_ITEM_SIZE); if (nbuffer == NULL) { os_free(buffer); wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_" "entry_get_byte_array out of " "memory trying to retrieve the " "string array"); goto done; } buffer = nbuffer; } entry->bytearray_value = buffer; dbus_message_iter_get_basic(iter, &byte); entry->bytearray_value[count] = byte; entry->array_len = ++count; dbus_message_iter_next(iter); } /* Zero-length arrays are valid. */ if (entry->array_len == 0) { os_free(entry->bytearray_value); entry->bytearray_value = NULL; } success = TRUE; done: return success; } #define STR_ARRAY_CHUNK_SIZE 8 #define STR_ARRAY_ITEM_SIZE (sizeof(char *)) static dbus_bool_t _wpa_dbus_dict_entry_get_string_array( DBusMessageIter *iter, int array_type, struct wpa_dbus_dict_entry *entry) { dbus_uint32_t count = 0; dbus_bool_t success = FALSE; char **buffer, **nbuffer; entry->strarray_value = NULL; entry->array_type = DBUS_TYPE_STRING; buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE); if (buffer == NULL) return FALSE; entry->strarray_value = buffer; entry->array_len = 0; while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) { const char *value; char *str; if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) { nbuffer = os_realloc_array( buffer, count + STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE); if (nbuffer == NULL) { os_free(buffer); wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_" "entry_get_string_array out of " "memory trying to retrieve the " "string array"); goto done; } buffer = nbuffer; } entry->strarray_value = buffer; dbus_message_iter_get_basic(iter, &value); str = os_strdup(value); if (str == NULL) { wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_entry_get_" "string_array out of memory trying to " "duplicate the string array"); goto done; } entry->strarray_value[count] = str; entry->array_len = ++count; dbus_message_iter_next(iter); } /* Zero-length arrays are valid. */ if (entry->array_len == 0) { os_free(entry->strarray_value); entry->strarray_value = NULL; } success = TRUE; done: return success; } #define BIN_ARRAY_CHUNK_SIZE 10 #define BIN_ARRAY_ITEM_SIZE (sizeof(struct wpabuf *)) static dbus_bool_t _wpa_dbus_dict_entry_get_binarray( DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry) { struct wpa_dbus_dict_entry tmpentry; size_t buflen = 0; int i; if (dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE) return FALSE; entry->array_type = WPAS_DBUS_TYPE_BINARRAY; entry->array_len = 0; entry->binarray_value = NULL; while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) { DBusMessageIter iter_array; if (entry->array_len == buflen) { struct wpabuf **newbuf; buflen += BIN_ARRAY_CHUNK_SIZE; newbuf = os_realloc_array(entry->binarray_value, buflen, BIN_ARRAY_ITEM_SIZE); if (!newbuf) goto cleanup; entry->binarray_value = newbuf; } dbus_message_iter_recurse(iter, &iter_array); if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry) == FALSE) goto cleanup; entry->binarray_value[entry->array_len] = wpabuf_alloc_ext_data((u8 *) tmpentry.bytearray_value, tmpentry.array_len); if (entry->binarray_value[entry->array_len] == NULL) { wpa_dbus_dict_entry_clear(&tmpentry); goto cleanup; } entry->array_len++; dbus_message_iter_next(iter); } return TRUE; cleanup: for (i = 0; i < (int) entry->array_len; i++) wpabuf_free(entry->binarray_value[i]); os_free(entry->binarray_value); entry->array_len = 0; entry->binarray_value = NULL; return FALSE; } static dbus_bool_t _wpa_dbus_dict_entry_get_array( DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry) { int array_type = dbus_message_iter_get_element_type(iter_dict_val); dbus_bool_t success = FALSE; DBusMessageIter iter_array; if (!entry) return FALSE; dbus_message_iter_recurse(iter_dict_val, &iter_array); switch (array_type) { case DBUS_TYPE_BYTE: success = _wpa_dbus_dict_entry_get_byte_array(&iter_array, entry); break; case DBUS_TYPE_STRING: success = _wpa_dbus_dict_entry_get_string_array(&iter_array, array_type, entry); break; case DBUS_TYPE_ARRAY: success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry); default: break; } return success; } static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant( struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter) { const char *v; switch (entry->type) { case DBUS_TYPE_OBJECT_PATH: case DBUS_TYPE_STRING: dbus_message_iter_get_basic(iter, &v); entry->str_value = os_strdup(v); if (entry->str_value == NULL) return FALSE; break; case DBUS_TYPE_BOOLEAN: dbus_message_iter_get_basic(iter, &entry->bool_value); break; case DBUS_TYPE_BYTE: dbus_message_iter_get_basic(iter, &entry->byte_value); break; case DBUS_TYPE_INT16: dbus_message_iter_get_basic(iter, &entry->int16_value); break; case DBUS_TYPE_UINT16: dbus_message_iter_get_basic(iter, &entry->uint16_value); break; case DBUS_TYPE_INT32: dbus_message_iter_get_basic(iter, &entry->int32_value); break; case DBUS_TYPE_UINT32: dbus_message_iter_get_basic(iter, &entry->uint32_value); break; case DBUS_TYPE_INT64: dbus_message_iter_get_basic(iter, &entry->int64_value); break; case DBUS_TYPE_UINT64: dbus_message_iter_get_basic(iter, &entry->uint64_value); break; case DBUS_TYPE_DOUBLE: dbus_message_iter_get_basic(iter, &entry->double_value); break; case DBUS_TYPE_ARRAY: return _wpa_dbus_dict_entry_get_array(iter, entry); default: return FALSE; } return TRUE; } /** * Read the current key/value entry from the dict. Entries are dynamically * allocated when needed and must be freed after use with the * wpa_dbus_dict_entry_clear() function. * * The returned entry object will be filled with the type and value of the next * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error * occurred. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_read() * @param entry A valid dict entry object into which the dict key and value * will be placed * @return TRUE on success, FALSE on failure * */ dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict, struct wpa_dbus_dict_entry * entry) { DBusMessageIter iter_dict_entry, iter_dict_val; int type; const char *key; if (!iter_dict || !entry) goto error; if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY) goto error; dbus_message_iter_recurse(iter_dict, &iter_dict_entry); dbus_message_iter_get_basic(&iter_dict_entry, &key); entry->key = key; if (!dbus_message_iter_next(&iter_dict_entry)) goto error; type = dbus_message_iter_get_arg_type(&iter_dict_entry); if (type != DBUS_TYPE_VARIANT) goto error; dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val); entry->type = dbus_message_iter_get_arg_type(&iter_dict_val); if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val)) goto error; dbus_message_iter_next(iter_dict); return TRUE; error: if (entry) { wpa_dbus_dict_entry_clear(entry); entry->type = DBUS_TYPE_INVALID; entry->array_type = DBUS_TYPE_INVALID; } return FALSE; } /** * Return whether or not there are additional dictionary entries. * * @param iter_dict A valid DBusMessageIter returned from * wpa_dbus_dict_open_read() * @return TRUE if more dict entries exists, FALSE if no more dict entries * exist */ dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict) { if (!iter_dict) return FALSE; return dbus_message_iter_get_arg_type(iter_dict) == DBUS_TYPE_DICT_ENTRY; } /** * Free any memory used by the entry object. * * @param entry The entry object */ void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry) { unsigned int i; if (!entry) return; switch (entry->type) { case DBUS_TYPE_OBJECT_PATH: case DBUS_TYPE_STRING: os_free(entry->str_value); break; case DBUS_TYPE_ARRAY: switch (entry->array_type) { case DBUS_TYPE_BYTE: os_free(entry->bytearray_value); break; case DBUS_TYPE_STRING: for (i = 0; i < entry->array_len; i++) os_free(entry->strarray_value[i]); os_free(entry->strarray_value); break; case WPAS_DBUS_TYPE_BINARRAY: for (i = 0; i < entry->array_len; i++) wpabuf_free(entry->binarray_value[i]); os_free(entry->binarray_value); break; } break; } os_memset(entry, 0, sizeof(struct wpa_dbus_dict_entry)); } wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_new_handlers_wps.c0000664000175000017500000002671012343617166022736 0ustar jmjm/* * WPA Supplicant / dbus-based control interface (WPS) * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * Copyright (c) 2009, Witold Sowa * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include "common.h" #include "../config.h" #include "../wpa_supplicant_i.h" #include "../wps_supplicant.h" #include "../driver_i.h" #include "../ap.h" #include "dbus_new_helpers.h" #include "dbus_new.h" #include "dbus_new_handlers.h" #include "dbus_dict_helpers.h" struct wps_start_params { int role; /* 0 - not set, 1 - enrollee, 2 - registrar */ int type; /* 0 - not set, 1 - pin, 2 - pbc */ u8 *bssid; char *pin; u8 *p2p_dev_addr; }; static int wpas_dbus_handler_wps_role(DBusMessage *message, DBusMessageIter *entry_iter, struct wps_start_params *params, DBusMessage **reply) { DBusMessageIter variant_iter; char *val; dbus_message_iter_recurse(entry_iter, &variant_iter); if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) { wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Role type, " "string required"); *reply = wpas_dbus_error_invalid_args(message, "Role must be a string"); return -1; } dbus_message_iter_get_basic(&variant_iter, &val); if (os_strcmp(val, "enrollee") == 0) params->role = 1; else if (os_strcmp(val, "registrar") == 0) params->role = 2; else { wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Uknown role %s", val); *reply = wpas_dbus_error_invalid_args(message, val); return -1; } return 0; } static int wpas_dbus_handler_wps_type(DBusMessage *message, DBusMessageIter *entry_iter, struct wps_start_params *params, DBusMessage **reply) { DBusMessageIter variant_iter; char *val; dbus_message_iter_recurse(entry_iter, &variant_iter); if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) { wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Type type, " "string required"); *reply = wpas_dbus_error_invalid_args(message, "Type must be a string"); return -1; } dbus_message_iter_get_basic(&variant_iter, &val); if (os_strcmp(val, "pin") == 0) params->type = 1; else if (os_strcmp(val, "pbc") == 0) params->type = 2; else { wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Unknown type %s", val); *reply = wpas_dbus_error_invalid_args(message, val); return -1; } return 0; } static int wpas_dbus_handler_wps_bssid(DBusMessage *message, DBusMessageIter *entry_iter, struct wps_start_params *params, DBusMessage **reply) { DBusMessageIter variant_iter, array_iter; int len; dbus_message_iter_recurse(entry_iter, &variant_iter); if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&variant_iter) != DBUS_TYPE_BYTE) { wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Bssid type, " "byte array required"); *reply = wpas_dbus_error_invalid_args( message, "Bssid must be a byte array"); return -1; } dbus_message_iter_recurse(&variant_iter, &array_iter); dbus_message_iter_get_fixed_array(&array_iter, ¶ms->bssid, &len); if (len != ETH_ALEN) { wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length " "%d", len); *reply = wpas_dbus_error_invalid_args(message, "Bssid is wrong length"); return -1; } return 0; } static int wpas_dbus_handler_wps_pin(DBusMessage *message, DBusMessageIter *entry_iter, struct wps_start_params *params, DBusMessage **reply) { DBusMessageIter variant_iter; dbus_message_iter_recurse(entry_iter, &variant_iter); if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) { wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Pin type, " "string required"); *reply = wpas_dbus_error_invalid_args(message, "Pin must be a string"); return -1; } dbus_message_iter_get_basic(&variant_iter, ¶ms->pin); return 0; } #ifdef CONFIG_P2P static int wpas_dbus_handler_wps_p2p_dev_addr(DBusMessage *message, DBusMessageIter *entry_iter, struct wps_start_params *params, DBusMessage **reply) { DBusMessageIter variant_iter, array_iter; int len; dbus_message_iter_recurse(entry_iter, &variant_iter); if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&variant_iter) != DBUS_TYPE_BYTE) { wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong " "P2PDeviceAddress type, byte array required"); *reply = wpas_dbus_error_invalid_args( message, "P2PDeviceAddress must be a byte array"); return -1; } dbus_message_iter_recurse(&variant_iter, &array_iter); dbus_message_iter_get_fixed_array(&array_iter, ¶ms->p2p_dev_addr, &len); if (len != ETH_ALEN) { wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong " "P2PDeviceAddress length %d", len); *reply = wpas_dbus_error_invalid_args(message, "P2PDeviceAddress " "has wrong length"); return -1; } return 0; } #endif /* CONFIG_P2P */ static int wpas_dbus_handler_wps_start_entry(DBusMessage *message, char *key, DBusMessageIter *entry_iter, struct wps_start_params *params, DBusMessage **reply) { if (os_strcmp(key, "Role") == 0) return wpas_dbus_handler_wps_role(message, entry_iter, params, reply); else if (os_strcmp(key, "Type") == 0) return wpas_dbus_handler_wps_type(message, entry_iter, params, reply); else if (os_strcmp(key, "Bssid") == 0) return wpas_dbus_handler_wps_bssid(message, entry_iter, params, reply); else if (os_strcmp(key, "Pin") == 0) return wpas_dbus_handler_wps_pin(message, entry_iter, params, reply); #ifdef CONFIG_P2P else if (os_strcmp(key, "P2PDeviceAddress") == 0) return wpas_dbus_handler_wps_p2p_dev_addr(message, entry_iter, params, reply); #endif /* CONFIG_P2P */ wpa_printf(MSG_DEBUG, "dbus: WPS.Start - unknown key %s", key); *reply = wpas_dbus_error_invalid_args(message, key); return -1; } /** * wpas_dbus_handler_wps_start - Start WPS configuration * @message: Pointer to incoming dbus message * @wpa_s: %wpa_supplicant data structure * Returns: DBus message dictionary on success or DBus error on failure * * Handler for "Start" method call. DBus dictionary argument contains * information about role (enrollee or registrar), authorization method * (pin or push button) and optionally pin and bssid. Returned message * has a dictionary argument which may contain newly generated pin (optional). */ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; DBusMessageIter iter, dict_iter, entry_iter; struct wps_start_params params; char *key; char npin[9] = { '\0' }; int ret; os_memset(¶ms, 0, sizeof(params)); dbus_message_iter_init(message, &iter); dbus_message_iter_recurse(&iter, &dict_iter); while (dbus_message_iter_get_arg_type(&dict_iter) == DBUS_TYPE_DICT_ENTRY) { dbus_message_iter_recurse(&dict_iter, &entry_iter); dbus_message_iter_get_basic(&entry_iter, &key); dbus_message_iter_next(&entry_iter); if (wpas_dbus_handler_wps_start_entry(message, key, &entry_iter, ¶ms, &reply)) return reply; dbus_message_iter_next(&dict_iter); } if (params.role == 0) { wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Role not specified"); return wpas_dbus_error_invalid_args(message, "Role not specified"); } else if (params.role == 1 && params.type == 0) { wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Type not specified"); return wpas_dbus_error_invalid_args(message, "Type not specified"); } else if (params.role == 2 && params.pin == NULL) { wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Pin required for " "registrar role"); return wpas_dbus_error_invalid_args( message, "Pin required for registrar role."); } if (params.role == 2) ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin, NULL); else if (params.type == 1) { #ifdef CONFIG_AP if (wpa_s->ap_iface) ret = wpa_supplicant_ap_wps_pin(wpa_s, params.bssid, params.pin, npin, sizeof(npin), 0); else #endif /* CONFIG_AP */ { ret = wpas_wps_start_pin(wpa_s, params.bssid, params.pin, 0, DEV_PW_DEFAULT); if (ret > 0) os_snprintf(npin, sizeof(npin), "%08d", ret); } } else { #ifdef CONFIG_AP if (wpa_s->ap_iface) ret = wpa_supplicant_ap_wps_pbc(wpa_s, params.bssid, params.p2p_dev_addr); else #endif /* CONFIG_AP */ ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0); } if (ret < 0) { wpa_printf(MSG_DEBUG, "dbus: WPS.Start wpas_wps_failed in " "role %s and key %s", (params.role == 1 ? "enrollee" : "registrar"), (params.type == 0 ? "" : (params.type == 1 ? "pin" : "pbc"))); return wpas_dbus_error_unknown_error(message, "WPS start failed"); } reply = dbus_message_new_method_return(message); if (!reply) { return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); } dbus_message_iter_init_append(reply, &iter); if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) { dbus_message_unref(reply); return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); } if (os_strlen(npin) > 0) { if (!wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) { dbus_message_unref(reply); return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); } } if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) { dbus_message_unref(reply); return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); } return reply; } /** * wpas_dbus_getter_process_credentials - Check if credentials are processed * @message: Pointer to incoming dbus message * @wpa_s: %wpa_supplicant data structure * Returns: TRUE on success, FALSE on failure * * Getter for "ProcessCredentials" property. Returns returned boolean will be * true if wps_cred_processing configuration field is not equal to 1 or false * if otherwise. */ dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1); return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, &process, error); } /** * wpas_dbus_setter_process_credentials - Set credentials_processed conf param * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Setter for "ProcessCredentials" property. Sets credentials_processed on 2 * if boolean argument is true or on 1 if otherwise. */ dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; dbus_bool_t process_credentials, old_pc; if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, &process_credentials)) return FALSE; old_pc = (wpa_s->conf->wps_cred_processing != 1); wpa_s->conf->wps_cred_processing = (process_credentials ? 2 : 1); if ((wpa_s->conf->wps_cred_processing != 1) != old_pc) wpa_dbus_mark_property_changed(wpa_s->global->dbus, wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_WPS, "ProcessCredentials"); return TRUE; } wpa_supplicant-2.2/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in0000664000175000017500000000017312343617166024232 0ustar jmjm[D-BUS Service] Name=fi.w1.wpa_supplicant1 Exec=@BINDIR@/wpa_supplicant -u User=root SystemdService=wpa_supplicant.service wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_new.h0000664000175000017500000003606612343617166020177 0ustar jmjm/* * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * Copyright (c) 2009-2010, Witold Sowa * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef CTRL_IFACE_DBUS_NEW_H #define CTRL_IFACE_DBUS_NEW_H #include "common/defs.h" #include "p2p/p2p.h" struct wpa_global; struct wpa_supplicant; struct wpa_ssid; struct wps_event_m2d; struct wps_event_fail; struct wps_credential; enum wpas_dbus_prop { WPAS_DBUS_PROP_AP_SCAN, WPAS_DBUS_PROP_SCANNING, WPAS_DBUS_PROP_STATE, WPAS_DBUS_PROP_CURRENT_BSS, WPAS_DBUS_PROP_CURRENT_NETWORK, WPAS_DBUS_PROP_CURRENT_AUTH_MODE, WPAS_DBUS_PROP_BSSS, WPAS_DBUS_PROP_DISCONNECT_REASON, }; enum wpas_dbus_bss_prop { WPAS_DBUS_BSS_PROP_SIGNAL, WPAS_DBUS_BSS_PROP_FREQ, WPAS_DBUS_BSS_PROP_MODE, WPAS_DBUS_BSS_PROP_PRIVACY, WPAS_DBUS_BSS_PROP_RATES, WPAS_DBUS_BSS_PROP_WPA, WPAS_DBUS_BSS_PROP_RSN, WPAS_DBUS_BSS_PROP_WPS, WPAS_DBUS_BSS_PROP_IES, }; #define WPAS_DBUS_OBJECT_PATH_MAX 150 #define WPAS_DBUS_NEW_SERVICE "fi.w1.wpa_supplicant1" #define WPAS_DBUS_NEW_PATH "/fi/w1/wpa_supplicant1" #define WPAS_DBUS_NEW_INTERFACE "fi.w1.wpa_supplicant1" #define WPAS_DBUS_NEW_PATH_INTERFACES WPAS_DBUS_NEW_PATH "/Interfaces" #define WPAS_DBUS_NEW_IFACE_INTERFACE WPAS_DBUS_NEW_INTERFACE ".Interface" #define WPAS_DBUS_NEW_IFACE_WPS WPAS_DBUS_NEW_IFACE_INTERFACE ".WPS" #define WPAS_DBUS_NEW_NETWORKS_PART "Networks" #define WPAS_DBUS_NEW_IFACE_NETWORK WPAS_DBUS_NEW_INTERFACE ".Network" #define WPAS_DBUS_NEW_BSSIDS_PART "BSSs" #define WPAS_DBUS_NEW_IFACE_BSS WPAS_DBUS_NEW_INTERFACE ".BSS" #define WPAS_DBUS_NEW_IFACE_P2PDEVICE \ WPAS_DBUS_NEW_IFACE_INTERFACE ".P2PDevice" /* * Groups correspond to P2P groups where this device is a GO (owner) */ #define WPAS_DBUS_NEW_P2P_GROUPS_PART "Groups" #define WPAS_DBUS_NEW_IFACE_P2P_GROUP WPAS_DBUS_NEW_INTERFACE ".Group" /* * Different dbus object for persistent groups so they do not get confused * with regular (configured) network objects. */ #define WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "PersistentGroups" #define WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP \ WPAS_DBUS_NEW_INTERFACE ".PersistentGroup" #define WPAS_DBUS_NEW_P2P_PEERS_PART "Peers" #define WPAS_DBUS_NEW_IFACE_P2P_PEER WPAS_DBUS_NEW_INTERFACE ".Peer" #define WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "Members" #define WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER \ WPAS_DBUS_NEW_INTERFACE ".GroupMember" /* Top-level Errors */ #define WPAS_DBUS_ERROR_UNKNOWN_ERROR \ WPAS_DBUS_NEW_INTERFACE ".UnknownError" #define WPAS_DBUS_ERROR_INVALID_ARGS \ WPAS_DBUS_NEW_INTERFACE ".InvalidArgs" #define WPAS_DBUS_ERROR_IFACE_EXISTS \ WPAS_DBUS_NEW_INTERFACE ".InterfaceExists" #define WPAS_DBUS_ERROR_IFACE_DISABLED \ WPAS_DBUS_NEW_INTERFACE ".InterfaceDisabled" #define WPAS_DBUS_ERROR_IFACE_UNKNOWN \ WPAS_DBUS_NEW_INTERFACE ".InterfaceUnknown" #define WPAS_DBUS_ERROR_NOT_CONNECTED \ WPAS_DBUS_NEW_INTERFACE ".NotConnected" #define WPAS_DBUS_ERROR_NETWORK_UNKNOWN \ WPAS_DBUS_NEW_INTERFACE ".NetworkUnknown" #define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE \ WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnavailable" #define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED \ WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnsupported" #define WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR \ WPAS_DBUS_NEW_INTERFACE ".ConnectUnspecifiedError" #define WPAS_DBUS_ERROR_BLOB_EXISTS \ WPAS_DBUS_NEW_INTERFACE ".BlobExists" #define WPAS_DBUS_ERROR_BLOB_UNKNOWN \ WPAS_DBUS_NEW_INTERFACE ".BlobUnknown" #define WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE \ WPAS_DBUS_NEW_INTERFACE ".SubscriptionInUse" #define WPAS_DBUS_ERROR_NO_SUBSCRIPTION \ WPAS_DBUS_NEW_INTERFACE ".NoSubscription" #define WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM \ WPAS_DBUS_NEW_INTERFACE ".SubscriptionNotYou" /* Interface-level errors */ #define WPAS_DBUS_ERROR_IFACE_SCAN_ERROR \ WPAS_DBUS_NEW_IFACE_INTERFACE ".ScanError" void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv); void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv); #ifdef CONFIG_CTRL_IFACE_DBUS_NEW int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv); void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface); int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s); int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s); void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s, enum wpas_dbus_prop property); void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s, enum wpas_dbus_bss_prop property, unsigned int id); void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id); void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, enum wpa_ctrl_req_type rtype, const char *default_text); void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success); void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s, const struct wps_credential *cred); void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s, struct wps_event_m2d *m2d); void wpas_dbus_signal_wps_event_fail(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail); void wpas_dbus_signal_wps_event_success(struct wpa_supplicant *wpa_s); int wpas_dbus_register_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid); int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s, u8 bssid[ETH_ALEN], unsigned int id); int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s, u8 bssid[ETH_ALEN], unsigned int id); void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s, const char *name); void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s, const char *name); void wpas_dbus_signal_debug_level_changed(struct wpa_global *global); void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global); void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global); int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr); void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s, const u8 *dev_addr); int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr); void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s, const u8 *dev_addr); void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s, const char *role); void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request, enum p2p_prov_disc_status status, u16 config_methods, unsigned int generated_pin); void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s, const u8 *src, u16 dev_passwd_id); void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int client, int network_id); void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *res); void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid); int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s, int nid); void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s, int status, const u8 *bssid); void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s, const u8 *p2p_if_addr); void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s, const u8 *p2p_if_addr); void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s, const u8 *member); void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s, int freq, const u8 *sa, u8 dialog_token, u16 update_indic, const u8 *tlvs, size_t tlvs_len); void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic, const u8 *tlvs, size_t tlvs_len); void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s, const u8 *member); void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail); void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s, int depth, const char *subject, const char *cert_hash, const struct wpabuf *cert); void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *dst, const u8 *bssid, const u8 *ie, size_t ie_len, u32 ssi_signal); void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s, const char *status, const char *parameter); void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *sta); void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s, const u8 *sta); #else /* CONFIG_CTRL_IFACE_DBUS_NEW */ static inline int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s) { return 0; } static inline int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s) { return 0; } #define wpas_dbus_signal_state_changed(w, n, o) do { } while (0) static inline void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s, enum wpas_dbus_prop property) { } static inline void wpas_dbus_bss_signal_prop_changed( struct wpa_supplicant *wpa_s, enum wpas_dbus_bss_prop property, unsigned int id) { } static inline void wpas_dbus_signal_network_enabled_changed( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { } static inline void wpas_dbus_signal_network_selected( struct wpa_supplicant *wpa_s, int id) { } static inline void wpas_dbus_signal_network_request( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, enum wpa_ctrl_req_type rtype, const char *default_txt) { } static inline void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success) { } static inline void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s, const struct wps_credential *cred) { } static inline void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s, struct wps_event_m2d *m2d) { } static inline void wpas_dbus_signal_wps_event_fail( struct wpa_supplicant *wpa_s, struct wps_event_fail *fail) { } static inline void wpas_dbus_signal_wps_event_success( struct wpa_supplicant *wpa_s) { } static inline int wpas_dbus_register_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { return 0; } static inline int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid) { return 0; } static inline int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s, u8 bssid[ETH_ALEN], unsigned int id) { return 0; } static inline int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s, u8 bssid[ETH_ALEN], unsigned int id) { return 0; } static inline void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s, const char *name) { } static inline void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s, const char *name) { } static inline void wpas_dbus_signal_debug_level_changed( struct wpa_global *global) { } static inline void wpas_dbus_signal_debug_timestamp_changed( struct wpa_global *global) { } static inline void wpas_dbus_signal_debug_show_keys_changed( struct wpa_global *global) { } static inline int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr) { return 0; } static inline int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr) { return 0; } static inline void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s, const char *role) { } static inline void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request, enum p2p_prov_disc_status status, u16 config_methods, unsigned int generated_pin) { } static inline void wpas_dbus_signal_p2p_go_neg_req( struct wpa_supplicant *wpa_s, const u8 *src, u16 dev_passwd_id) { } static inline void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int client, int network_id) { } static inline void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { } static inline int wpas_dbus_register_persistent_group( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { return 0; } static inline int wpas_dbus_unregister_persistent_group( struct wpa_supplicant *wpa_s, int nid) { return 0; } static inline void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *res) { } static inline void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid) { } static inline void wpas_dbus_signal_p2p_invitation_result( struct wpa_supplicant *wpa_s, int status, const u8 *bssid) { } static inline void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s, const u8 *p2p_if_addr) { } static inline void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s, int freq, const u8 *sa, u8 dialog_token, u16 update_indic, const u8 *tlvs, size_t tlvs_len) { } static inline void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic, const u8 *tlvs, size_t tlvs_len) { } static inline void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s, const u8 *p2p_if_addr) { } static inline void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s, const u8 *member) { } static inline void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s, const u8 *dev_addr) { } static inline void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s, const u8 *dev_addr) { } static inline void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s, const u8 *member) { } static inline void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail) { } static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s, int depth, const char *subject, const char *cert_hash, const struct wpabuf *cert) { } static inline void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *dst, const u8 *bssid, const u8 *ie, size_t ie_len, u32 ssi_signal) { } static inline void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s, const char *status, const char *parameter) { } static inline void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *sta) { } static inline void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s, const u8 *sta) { } #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ #endif /* CTRL_IFACE_DBUS_H_NEW */ wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_new_handlers.h0000664000175000017500000002444212343617166022052 0ustar jmjm/* * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * Copyright (c) 2009-2010, Witold Sowa * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef CTRL_IFACE_DBUS_NEW_HANDLERS_H #define CTRL_IFACE_DBUS_NEW_HANDLERS_H struct network_handler_args { struct wpa_supplicant *wpa_s; struct wpa_ssid *ssid; }; struct bss_handler_args { struct wpa_supplicant *wpa_s; unsigned int id; }; dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter, const int type, const void *val, DBusError *error); dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter, DBusError *error, const int type, void *val); dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter, const int type, const void *array, size_t array_len, DBusError *error); dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter, const int type, struct wpabuf **array, size_t array_len, DBusError *error); DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, struct wpa_global *global); DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message, struct wpa_global *global); DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message, struct wpa_global *global); dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter, DBusError *error, void *user_data); DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message, struct wpa_supplicant *wpa_s); dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, DBusMessageIter *iter, DBusError *error); DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_remove_all_networks( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message, struct wpa_supplicant *wpa_s); dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter, DBusError *error, void *user_data); DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message, struct wpa_supplicant *wpa_s); dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter, DBusError *error, void *user_data); DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message, const char *arg); DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message, const char *arg); DBusMessage * wpas_dbus_handler_subscribe_preq( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_unsubscribe_preq( DBusMessage *message, struct wpa_supplicant *wpa_s); #endif /* CTRL_IFACE_DBUS_HANDLERS_NEW_H */ wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_new_handlers_p2p.c0000664000175000017500000020266412343617166022632 0ustar jmjm/* * WPA Supplicant / dbus-based control interface (P2P) * Copyright (c) 2011-2012, Intel Corporation * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include "utils/includes.h" #include "common.h" #include "../config.h" #include "../wpa_supplicant_i.h" #include "../wps_supplicant.h" #include "../notify.h" #include "dbus_new_helpers.h" #include "dbus_new.h" #include "dbus_new_handlers.h" #include "dbus_new_handlers_p2p.h" #include "dbus_dict_helpers.h" #include "p2p/p2p.h" #include "common/ieee802_11_defs.h" #include "ap/hostapd.h" #include "ap/ap_config.h" #include "ap/wps_hostapd.h" #include "../p2p_supplicant.h" /** * Parses out the mac address from the peer object path. * @peer_path - object path of the form * /fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons) * @addr - out param must be of ETH_ALEN size * Returns 0 if valid (including MAC), -1 otherwise */ static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN]) { char *p; if (!peer_path) return -1; p = os_strrchr(peer_path, '/'); if (!p) return -1; p++; return hwaddr_compact_aton(p, addr); } /** * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown * error message * @message: Pointer to incoming dbus message this error refers to * Returns: a dbus error message * * Convenience function to create and return an invalid persistent group error. */ static DBusMessage * wpas_dbus_error_persistent_group_unknown( DBusMessage *message) { return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN, "There is no such persistent group in " "this P2P device."); } DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message, struct wpa_supplicant *wpa_s) { struct wpa_dbus_dict_entry entry; DBusMessage *reply = NULL; DBusMessageIter iter; DBusMessageIter iter_dict; unsigned int timeout = 0; enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL; int num_req_dev_types = 0; unsigned int i; u8 *req_dev_types = NULL; dbus_message_iter_init(message, &iter); entry.key = NULL; if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto error; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; if (!os_strcmp(entry.key, "Timeout") && (entry.type == DBUS_TYPE_INT32)) { timeout = entry.uint32_value; } else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) { if ((entry.type != DBUS_TYPE_ARRAY) || (entry.array_type != WPAS_DBUS_TYPE_BINARRAY)) goto error_clear; os_free(req_dev_types); req_dev_types = os_malloc(WPS_DEV_TYPE_LEN * entry.array_len); if (!req_dev_types) goto error_clear; for (i = 0; i < entry.array_len; i++) { if (wpabuf_len(entry.binarray_value[i]) != WPS_DEV_TYPE_LEN) goto error_clear; os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN, wpabuf_head(entry.binarray_value[i]), WPS_DEV_TYPE_LEN); } num_req_dev_types = entry.array_len; } else if (!os_strcmp(entry.key, "DiscoveryType") && (entry.type == DBUS_TYPE_STRING)) { if (!os_strcmp(entry.str_value, "start_with_full")) type = P2P_FIND_START_WITH_FULL; else if (!os_strcmp(entry.str_value, "social")) type = P2P_FIND_ONLY_SOCIAL; else if (!os_strcmp(entry.str_value, "progressive")) type = P2P_FIND_PROGRESSIVE; else goto error_clear; } else goto error_clear; wpa_dbus_dict_entry_clear(&entry); } wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types, NULL, 0); os_free(req_dev_types); return reply; error_clear: wpa_dbus_dict_entry_clear(&entry); error: os_free(req_dev_types); reply = wpas_dbus_error_invalid_args(message, entry.key); return reply; } DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message, struct wpa_supplicant *wpa_s) { wpas_p2p_stop_find(wpa_s); return NULL; } DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessageIter iter; char *peer_object_path = NULL; u8 peer_addr[ETH_ALEN]; dbus_message_iter_init(message, &iter); dbus_message_iter_get_basic(&iter, &peer_object_path); if (parse_peer_object_path(peer_object_path, peer_addr) < 0) return wpas_dbus_error_invalid_args(message, NULL); if (wpas_p2p_reject(wpa_s, peer_addr) < 0) return wpas_dbus_error_unknown_error(message, "Failed to call wpas_p2p_reject method."); return NULL; } DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message, struct wpa_supplicant *wpa_s) { dbus_int32_t timeout = 0; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout, DBUS_TYPE_INVALID)) return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); if (wpas_p2p_listen(wpa_s, (unsigned int)timeout)) return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } DBusMessage * wpas_dbus_handler_p2p_extendedlisten( DBusMessage *message, struct wpa_supplicant *wpa_s) { unsigned int period = 0, interval = 0; struct wpa_dbus_dict_entry entry; DBusMessageIter iter; DBusMessageIter iter_dict; dbus_message_iter_init(message, &iter); entry.key = NULL; if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto error; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; if (!os_strcmp(entry.key, "period") && (entry.type == DBUS_TYPE_INT32)) period = entry.uint32_value; else if (!os_strcmp(entry.key, "interval") && (entry.type == DBUS_TYPE_INT32)) interval = entry.uint32_value; else goto error_clear; wpa_dbus_dict_entry_clear(&entry); } if (wpas_p2p_ext_listen(wpa_s, period, interval)) return wpas_dbus_error_unknown_error( message, "failed to initiate a p2p_ext_listen."); return NULL; error_clear: wpa_dbus_dict_entry_clear(&entry); error: return wpas_dbus_error_invalid_args(message, entry.key); } DBusMessage * wpas_dbus_handler_p2p_presence_request( DBusMessage *message, struct wpa_supplicant *wpa_s) { unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0; struct wpa_dbus_dict_entry entry; DBusMessageIter iter; DBusMessageIter iter_dict; dbus_message_iter_init(message, &iter); entry.key = NULL; if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto error; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; if (!os_strcmp(entry.key, "duration1") && (entry.type == DBUS_TYPE_INT32)) dur1 = entry.uint32_value; else if (!os_strcmp(entry.key, "interval1") && entry.type == DBUS_TYPE_INT32) int1 = entry.uint32_value; else if (!os_strcmp(entry.key, "duration2") && entry.type == DBUS_TYPE_INT32) dur2 = entry.uint32_value; else if (!os_strcmp(entry.key, "interval2") && entry.type == DBUS_TYPE_INT32) int2 = entry.uint32_value; else goto error_clear; wpa_dbus_dict_entry_clear(&entry); } if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0) return wpas_dbus_error_unknown_error(message, "Failed to invoke presence request."); return NULL; error_clear: wpa_dbus_dict_entry_clear(&entry); error: return wpas_dbus_error_invalid_args(message, entry.key); } DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessageIter iter_dict; DBusMessage *reply = NULL; DBusMessageIter iter; struct wpa_dbus_dict_entry entry; char *pg_object_path = NULL; int persistent_group = 0; int freq = 0; char *iface = NULL; char *net_id_str = NULL; unsigned int group_id = 0; struct wpa_ssid *ssid; dbus_message_iter_init(message, &iter); if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto inv_args; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto inv_args; if (!os_strcmp(entry.key, "persistent") && (entry.type == DBUS_TYPE_BOOLEAN)) { persistent_group = (entry.bool_value == TRUE) ? 1 : 0; } else if (!os_strcmp(entry.key, "frequency") && (entry.type == DBUS_TYPE_INT32)) { freq = entry.int32_value; if (freq <= 0) goto inv_args_clear; } else if (!os_strcmp(entry.key, "persistent_group_object") && entry.type == DBUS_TYPE_OBJECT_PATH) pg_object_path = os_strdup(entry.str_value); else goto inv_args_clear; wpa_dbus_dict_entry_clear(&entry); } if (pg_object_path != NULL) { /* * A persistent group Object Path is defined meaning we want * to re-invoke a persistent group. */ iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1, &net_id_str, NULL); if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { reply = wpas_dbus_error_invalid_args(message, pg_object_path); goto out; } group_id = strtoul(net_id_str, NULL, 10); if (errno == EINVAL) { reply = wpas_dbus_error_invalid_args( message, pg_object_path); goto out; } /* Get the SSID structure from the persistent group id */ ssid = wpa_config_get_network(wpa_s->conf, group_id); if (ssid == NULL || ssid->disabled != 2) goto inv_args; if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0, NULL, 0)) { reply = wpas_dbus_error_unknown_error( message, "Failed to reinvoke a persistent group"); goto out; } } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0)) goto inv_args; out: os_free(pg_object_path); os_free(net_id_str); os_free(iface); return reply; inv_args_clear: wpa_dbus_dict_entry_clear(&entry); inv_args: reply = wpas_dbus_error_invalid_args(message, NULL); goto out; } DBusMessage * wpas_dbus_handler_p2p_disconnect(DBusMessage *message, struct wpa_supplicant *wpa_s) { if (wpas_p2p_disconnect(wpa_s)) return wpas_dbus_error_unknown_error(message, "failed to disconnect"); return NULL; } static dbus_bool_t wpa_dbus_p2p_check_enabled(struct wpa_supplicant *wpa_s, DBusMessage *message, DBusMessage **out_reply, DBusError *error) { /* Return an error message or an error if P2P isn't available */ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) { if (out_reply) { *out_reply = dbus_message_new_error( message, DBUS_ERROR_FAILED, "P2P is not available for this interface"); } dbus_set_error_const(error, DBUS_ERROR_FAILED, "P2P is not available for this " "interface"); return FALSE; } return TRUE; } DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL)) return reply; os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); wpa_s->force_long_sd = 0; p2p_flush(wpa_s->global->p2p); return NULL; } DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessageIter iter_dict; DBusMessage *reply = NULL; DBusMessageIter iter; struct wpa_dbus_dict_entry entry; char *peer_object_path = NULL; int persistent_group = 0; int join = 0; int authorize_only = 0; int go_intent = -1; int freq = 0; u8 addr[ETH_ALEN]; char *pin = NULL; enum p2p_wps_method wps_method = WPS_NOT_READY; int new_pin; char *err_msg = NULL; char *iface = NULL; if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL)) return reply; dbus_message_iter_init(message, &iter); if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto inv_args; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto inv_args; if (!os_strcmp(entry.key, "peer") && (entry.type == DBUS_TYPE_OBJECT_PATH)) { peer_object_path = os_strdup(entry.str_value); } else if (!os_strcmp(entry.key, "persistent") && (entry.type == DBUS_TYPE_BOOLEAN)) { persistent_group = (entry.bool_value == TRUE) ? 1 : 0; } else if (!os_strcmp(entry.key, "join") && (entry.type == DBUS_TYPE_BOOLEAN)) { join = (entry.bool_value == TRUE) ? 1 : 0; } else if (!os_strcmp(entry.key, "authorize_only") && (entry.type == DBUS_TYPE_BOOLEAN)) { authorize_only = (entry.bool_value == TRUE) ? 1 : 0; } else if (!os_strcmp(entry.key, "frequency") && (entry.type == DBUS_TYPE_INT32)) { freq = entry.int32_value; if (freq <= 0) goto inv_args_clear; } else if (!os_strcmp(entry.key, "go_intent") && (entry.type == DBUS_TYPE_INT32)) { go_intent = entry.int32_value; if ((go_intent < 0) || (go_intent > 15)) goto inv_args_clear; } else if (!os_strcmp(entry.key, "wps_method") && (entry.type == DBUS_TYPE_STRING)) { if (!os_strcmp(entry.str_value, "pbc")) wps_method = WPS_PBC; else if (!os_strcmp(entry.str_value, "pin")) wps_method = WPS_PIN_DISPLAY; else if (!os_strcmp(entry.str_value, "display")) wps_method = WPS_PIN_DISPLAY; else if (!os_strcmp(entry.str_value, "keypad")) wps_method = WPS_PIN_KEYPAD; else goto inv_args_clear; } else if (!os_strcmp(entry.key, "pin") && (entry.type == DBUS_TYPE_STRING)) { pin = os_strdup(entry.str_value); } else goto inv_args_clear; wpa_dbus_dict_entry_clear(&entry); } if (!peer_object_path || (wps_method == WPS_NOT_READY) || (parse_peer_object_path(peer_object_path, addr) < 0) || !p2p_peer_known(wpa_s->global->p2p, addr)) goto inv_args; /* * Validate the wps_method specified and the pin value. */ if ((!pin || !pin[0]) && (wps_method == WPS_PIN_KEYPAD)) goto inv_args; new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, persistent_group, 0, join, authorize_only, go_intent, freq, -1, 0, 0, 0); if (new_pin >= 0) { char npin[9]; char *generated_pin; os_snprintf(npin, sizeof(npin), "%08d", new_pin); generated_pin = npin; reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_STRING, &generated_pin, DBUS_TYPE_INVALID); } else { switch (new_pin) { case -2: err_msg = "connect failed due to channel " "unavailability."; iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE; break; case -3: err_msg = "connect failed due to unsupported channel."; iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED; break; default: err_msg = "connect failed due to unspecified error."; iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR; break; } /* * TODO: * Do we need specialized errors corresponding to above * error conditions as against just returning a different * error message? */ reply = dbus_message_new_error(message, iface, err_msg); } out: os_free(peer_object_path); os_free(pin); return reply; inv_args_clear: wpa_dbus_dict_entry_clear(&entry); inv_args: reply = wpas_dbus_error_invalid_args(message, NULL); goto out; } DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessageIter iter_dict; DBusMessage *reply = NULL; DBusMessageIter iter; struct wpa_dbus_dict_entry entry; char *peer_object_path = NULL; char *pg_object_path = NULL; char *iface = NULL; char *net_id_str = NULL; u8 peer_addr[ETH_ALEN]; unsigned int group_id = 0; int persistent = 0; struct wpa_ssid *ssid; if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL)) return reply; dbus_message_iter_init(message, &iter); if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto err; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto err; if (!os_strcmp(entry.key, "peer") && (entry.type == DBUS_TYPE_OBJECT_PATH)) { peer_object_path = os_strdup(entry.str_value); wpa_dbus_dict_entry_clear(&entry); } else if (!os_strcmp(entry.key, "persistent_group_object") && (entry.type == DBUS_TYPE_OBJECT_PATH)) { pg_object_path = os_strdup(entry.str_value); persistent = 1; wpa_dbus_dict_entry_clear(&entry); } else { wpa_dbus_dict_entry_clear(&entry); goto err; } } if (!peer_object_path || (parse_peer_object_path(peer_object_path, peer_addr) < 0) || !p2p_peer_known(wpa_s->global->p2p, peer_addr)) { goto err; } if (persistent) { /* * A group ID is defined meaning we want to re-invoke a * persistent group */ iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1, &net_id_str, NULL); if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { reply = wpas_dbus_error_invalid_args(message, pg_object_path); goto out; } group_id = strtoul(net_id_str, NULL, 10); if (errno == EINVAL) { reply = wpas_dbus_error_invalid_args( message, pg_object_path); goto out; } /* Get the SSID structure from the persistent group id */ ssid = wpa_config_get_network(wpa_s->conf, group_id); if (ssid == NULL || ssid->disabled != 2) goto err; if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0) < 0) { reply = wpas_dbus_error_unknown_error( message, "Failed to reinvoke a persistent group"); goto out; } } else { /* * No group ID means propose to a peer to join my active group */ if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname, peer_addr, NULL)) { reply = wpas_dbus_error_unknown_error( message, "Failed to join to an active group"); goto out; } } out: os_free(pg_object_path); os_free(peer_object_path); return reply; err: reply = wpas_dbus_error_invalid_args(message, NULL); goto out; } DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessageIter iter; char *peer_object_path = NULL; char *config_method = NULL; u8 peer_addr[ETH_ALEN]; dbus_message_iter_init(message, &iter); dbus_message_iter_get_basic(&iter, &peer_object_path); if (parse_peer_object_path(peer_object_path, peer_addr) < 0) return wpas_dbus_error_invalid_args(message, NULL); dbus_message_iter_next(&iter); dbus_message_iter_get_basic(&iter, &config_method); /* * Validation checks on config_method are being duplicated here * to be able to return invalid args reply since the error code * from p2p module are not granular enough (yet). */ if (os_strcmp(config_method, "display") && os_strcmp(config_method, "keypad") && os_strcmp(config_method, "pbc") && os_strcmp(config_method, "pushbutton")) return wpas_dbus_error_invalid_args(message, NULL); if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method, WPAS_P2P_PD_FOR_GO_NEG) < 0) return wpas_dbus_error_unknown_error(message, "Failed to send provision discovery request"); return NULL; } /* * P2P Device property accessor methods. */ dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; DBusMessageIter variant_iter, dict_iter; DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val, iter_secdev_dict_array; const char *dev_name; int num_vendor_extensions = 0; int i; const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT]; if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error)) return FALSE; if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}", &variant_iter) || !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) goto err_no_mem; /* DeviceName */ dev_name = wpa_s->conf->device_name; if (dev_name && !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name)) goto err_no_mem; /* Primary device type */ if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType", (char *)wpa_s->conf->device_type, WPS_DEV_TYPE_LEN)) goto err_no_mem; /* Secondary device types */ if (wpa_s->conf->num_sec_device_types) { if (!wpa_dbus_dict_begin_array(&dict_iter, "SecondaryDeviceTypes", DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING, &iter_secdev_dict_entry, &iter_secdev_dict_val, &iter_secdev_dict_array)) goto err_no_mem; for (i = 0; i < wpa_s->conf->num_sec_device_types; i++) wpa_dbus_dict_bin_array_add_element( &iter_secdev_dict_array, wpa_s->conf->sec_device_type[i], WPS_DEV_TYPE_LEN); if (!wpa_dbus_dict_end_array(&dict_iter, &iter_secdev_dict_entry, &iter_secdev_dict_val, &iter_secdev_dict_array)) goto err_no_mem; } /* Vendor Extensions */ for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { if (wpa_s->conf->wps_vendor_ext[i] == NULL) continue; vendor_ext[num_vendor_extensions++] = wpa_s->conf->wps_vendor_ext[i]; } if (num_vendor_extensions && !wpa_dbus_dict_append_wpabuf_array(&dict_iter, "VendorExtension", vendor_ext, num_vendor_extensions)) goto err_no_mem; /* GO Intent */ if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent", wpa_s->conf->p2p_go_intent)) goto err_no_mem; /* Persistent Reconnect */ if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect", wpa_s->conf->persistent_reconnect)) goto err_no_mem; /* Listen Reg Class */ if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass", wpa_s->conf->p2p_listen_reg_class)) goto err_no_mem; /* Listen Channel */ if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel", wpa_s->conf->p2p_listen_channel)) goto err_no_mem; /* Oper Reg Class */ if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass", wpa_s->conf->p2p_oper_reg_class)) goto err_no_mem; /* Oper Channel */ if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel", wpa_s->conf->p2p_oper_channel)) goto err_no_mem; /* SSID Postfix */ if (wpa_s->conf->p2p_ssid_postfix && !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix", wpa_s->conf->p2p_ssid_postfix)) goto err_no_mem; /* Intra Bss */ if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss", wpa_s->conf->p2p_intra_bss)) goto err_no_mem; /* Group Idle */ if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle", wpa_s->conf->p2p_group_idle)) goto err_no_mem; /* Dissasociation low ack */ if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack", wpa_s->conf->disassoc_low_ack)) goto err_no_mem; /* No Group Iface */ if (!wpa_dbus_dict_append_bool(&dict_iter, "NoGroupIface", wpa_s->conf->p2p_no_group_iface)) goto err_no_mem; if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) || !dbus_message_iter_close_container(iter, &variant_iter)) goto err_no_mem; return TRUE; err_no_mem: dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; DBusMessageIter variant_iter, iter_dict; struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING }; unsigned int i; if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error)) return FALSE; dbus_message_iter_recurse(iter, &variant_iter); if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error)) return FALSE; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, "invalid message format"); return FALSE; } if (os_strcmp(entry.key, "DeviceName") == 0) { char *devname; if (entry.type != DBUS_TYPE_STRING) goto error; devname = os_strdup(entry.str_value); if (devname == NULL) goto err_no_mem_clear; os_free(wpa_s->conf->device_name); wpa_s->conf->device_name = devname; wpa_s->conf->changed_parameters |= CFG_CHANGED_DEVICE_NAME; } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) { if (entry.type != DBUS_TYPE_ARRAY || entry.array_type != DBUS_TYPE_BYTE || entry.array_len != WPS_DEV_TYPE_LEN) goto error; os_memcpy(wpa_s->conf->device_type, entry.bytearray_value, WPS_DEV_TYPE_LEN); wpa_s->conf->changed_parameters |= CFG_CHANGED_DEVICE_TYPE; } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) { if (entry.type != DBUS_TYPE_ARRAY || entry.array_type != WPAS_DBUS_TYPE_BINARRAY || entry.array_len > MAX_SEC_DEVICE_TYPES) goto error; for (i = 0; i < entry.array_len; i++) if (wpabuf_len(entry.binarray_value[i]) != WPS_DEV_TYPE_LEN) goto err_no_mem_clear; for (i = 0; i < entry.array_len; i++) os_memcpy(wpa_s->conf->sec_device_type[i], wpabuf_head(entry.binarray_value[i]), WPS_DEV_TYPE_LEN); wpa_s->conf->num_sec_device_types = entry.array_len; wpa_s->conf->changed_parameters |= CFG_CHANGED_SEC_DEVICE_TYPE; } else if (os_strcmp(entry.key, "VendorExtension") == 0) { if ((entry.type != DBUS_TYPE_ARRAY) || (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) || (entry.array_len > P2P_MAX_WPS_VENDOR_EXT)) goto error; wpa_s->conf->changed_parameters |= CFG_CHANGED_VENDOR_EXTENSION; for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { wpabuf_free(wpa_s->conf->wps_vendor_ext[i]); if (i < entry.array_len) { wpa_s->conf->wps_vendor_ext[i] = entry.binarray_value[i]; entry.binarray_value[i] = NULL; } else wpa_s->conf->wps_vendor_ext[i] = NULL; } } else if ((os_strcmp(entry.key, "GOIntent") == 0) && (entry.type == DBUS_TYPE_UINT32) && (entry.uint32_value <= 15)) wpa_s->conf->p2p_go_intent = entry.uint32_value; else if ((os_strcmp(entry.key, "PersistentReconnect") == 0) && (entry.type == DBUS_TYPE_BOOLEAN)) wpa_s->conf->persistent_reconnect = entry.bool_value; else if ((os_strcmp(entry.key, "ListenRegClass") == 0) && (entry.type == DBUS_TYPE_UINT32)) { wpa_s->conf->p2p_listen_reg_class = entry.uint32_value; wpa_s->conf->changed_parameters |= CFG_CHANGED_P2P_LISTEN_CHANNEL; } else if ((os_strcmp(entry.key, "ListenChannel") == 0) && (entry.type == DBUS_TYPE_UINT32)) { wpa_s->conf->p2p_listen_channel = entry.uint32_value; wpa_s->conf->changed_parameters |= CFG_CHANGED_P2P_LISTEN_CHANNEL; } else if ((os_strcmp(entry.key, "OperRegClass") == 0) && (entry.type == DBUS_TYPE_UINT32)) { wpa_s->conf->p2p_oper_reg_class = entry.uint32_value; wpa_s->conf->changed_parameters |= CFG_CHANGED_P2P_OPER_CHANNEL; } else if ((os_strcmp(entry.key, "OperChannel") == 0) && (entry.type == DBUS_TYPE_UINT32)) { wpa_s->conf->p2p_oper_channel = entry.uint32_value; wpa_s->conf->changed_parameters |= CFG_CHANGED_P2P_OPER_CHANNEL; } else if (os_strcmp(entry.key, "SsidPostfix") == 0) { char *postfix; if (entry.type != DBUS_TYPE_STRING) goto error; postfix = os_strdup(entry.str_value); if (!postfix) goto err_no_mem_clear; os_free(wpa_s->conf->p2p_ssid_postfix); wpa_s->conf->p2p_ssid_postfix = postfix; wpa_s->conf->changed_parameters |= CFG_CHANGED_P2P_SSID_POSTFIX; } else if ((os_strcmp(entry.key, "IntraBss") == 0) && (entry.type == DBUS_TYPE_BOOLEAN)) { wpa_s->conf->p2p_intra_bss = entry.bool_value; wpa_s->conf->changed_parameters |= CFG_CHANGED_P2P_INTRA_BSS; } else if ((os_strcmp(entry.key, "GroupIdle") == 0) && (entry.type == DBUS_TYPE_UINT32)) wpa_s->conf->p2p_group_idle = entry.uint32_value; else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 && entry.type == DBUS_TYPE_UINT32) wpa_s->conf->disassoc_low_ack = entry.uint32_value; else if (os_strcmp(entry.key, "NoGroupIface") == 0 && entry.type == DBUS_TYPE_BOOLEAN) wpa_s->conf->p2p_no_group_iface = entry.bool_value; else goto error; wpa_dbus_dict_entry_clear(&entry); } if (wpa_s->conf->changed_parameters) { /* Some changed parameters requires to update config*/ wpa_supplicant_update_config(wpa_s); } return TRUE; error: dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, "invalid message format"); wpa_dbus_dict_entry_clear(&entry); return FALSE; err_no_mem_clear: dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); wpa_dbus_dict_entry_clear(&entry); return FALSE; } dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; struct p2p_data *p2p = wpa_s->global->p2p; int next = 0, i = 0; int num = 0, out_of_mem = 0; const u8 *addr; const struct p2p_peer_info *peer_info = NULL; dbus_bool_t success = FALSE; struct dl_list peer_objpath_list; struct peer_objpath_node { struct dl_list list; char path[WPAS_DBUS_OBJECT_PATH_MAX]; } *node, *tmp; char **peer_obj_paths = NULL; if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error)) return FALSE; dl_list_init(&peer_objpath_list); /* Get the first peer info */ peer_info = p2p_get_peer_found(p2p, NULL, next); /* Get next and accumulate them */ next = 1; while (peer_info != NULL) { node = os_zalloc(sizeof(struct peer_objpath_node)); if (!node) { out_of_mem = 1; goto error; } addr = peer_info->p2p_device_addr; os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(addr)); dl_list_add_tail(&peer_objpath_list, &node->list); num++; peer_info = p2p_get_peer_found(p2p, addr, next); } /* * Now construct the peer object paths in a form suitable for * array_property_getter helper below. */ peer_obj_paths = os_calloc(num, sizeof(char *)); if (!peer_obj_paths) { out_of_mem = 1; goto error; } dl_list_for_each_safe(node, tmp, &peer_objpath_list, struct peer_objpath_node, list) peer_obj_paths[i++] = node->path; success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_OBJECT_PATH, peer_obj_paths, num, error); error: if (peer_obj_paths) os_free(peer_obj_paths); dl_list_for_each_safe(node, tmp, &peer_objpath_list, struct peer_objpath_node, list) { dl_list_del(&node->list); os_free(node); } if (out_of_mem) dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return success; } enum wpas_p2p_role { WPAS_P2P_ROLE_DEVICE, WPAS_P2P_ROLE_GO, WPAS_P2P_ROLE_CLIENT, }; static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid = wpa_s->current_ssid; if (!ssid) return WPAS_P2P_ROLE_DEVICE; if (wpa_s->wpa_state != WPA_COMPLETED) return WPAS_P2P_ROLE_DEVICE; switch (ssid->mode) { case WPAS_MODE_P2P_GO: case WPAS_MODE_P2P_GROUP_FORMATION: return WPAS_P2P_ROLE_GO; case WPAS_MODE_INFRA: if (ssid->p2p_group) return WPAS_P2P_ROLE_CLIENT; return WPAS_P2P_ROLE_DEVICE; default: return WPAS_P2P_ROLE_DEVICE; } } dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char *str; switch (wpas_get_p2p_role(wpa_s)) { case WPAS_P2P_ROLE_GO: str = "GO"; break; case WPAS_P2P_ROLE_CLIENT: str = "client"; break; default: str = "device"; } return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str, error); } dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char path_buf[WPAS_DBUS_OBJECT_PATH_MAX]; char *dbus_groupobj_path = path_buf; if (wpa_s->dbus_groupobj_path == NULL) os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); else os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s", wpa_s->dbus_groupobj_path); return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, &dbus_groupobj_path, error); } dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT) os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); else os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr)); path = go_peer_obj_path; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, &path, error); } /* * Peer object properties accessor methods */ dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter, DBusError *error, void *user_data) { struct peer_handler_args *peer_args = user_data; const struct p2p_peer_info *info; char *tmp; if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error)) return FALSE; /* get the peer info */ info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, peer_args->p2p_device_addr, 0); if (info == NULL) { dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer"); return FALSE; } tmp = os_strdup(info->device_name); if (!tmp) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp, error)) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); os_free(tmp); return FALSE; } os_free(tmp); return TRUE; } dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type( DBusMessageIter *iter, DBusError *error, void *user_data) { struct peer_handler_args *peer_args = user_data; const struct p2p_peer_info *info; info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, peer_args->p2p_device_addr, 0); if (info == NULL) { dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer"); return FALSE; } if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, (char *) info->pri_dev_type, WPS_DEV_TYPE_LEN, error)) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } return TRUE; } dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter, DBusError *error, void *user_data) { struct peer_handler_args *peer_args = user_data; const struct p2p_peer_info *info; info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, peer_args->p2p_device_addr, 0); if (info == NULL) { dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer"); return FALSE; } if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, &info->config_methods, error)) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } return TRUE; } dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter, DBusError *error, void *user_data) { struct peer_handler_args *peer_args = user_data; const struct p2p_peer_info *info; info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, peer_args->p2p_device_addr, 0); if (info == NULL) { dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer"); return FALSE; } if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, &info->level, error)) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } return TRUE; } dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter, DBusError *error, void *user_data) { struct peer_handler_args *peer_args = user_data; const struct p2p_peer_info *info; info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, peer_args->p2p_device_addr, 0); if (info == NULL) { dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer"); return FALSE; } if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE, &info->dev_capab, error)) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } return TRUE; } dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter, DBusError *error, void *user_data) { struct peer_handler_args *peer_args = user_data; const struct p2p_peer_info *info; info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, peer_args->p2p_device_addr, 0); if (info == NULL) { dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer"); return FALSE; } if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE, &info->group_capab, error)) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } return TRUE; } dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types( DBusMessageIter *iter, DBusError *error, void *user_data) { struct peer_handler_args *peer_args = user_data; const struct p2p_peer_info *info; DBusMessageIter variant_iter, array_iter; info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, peer_args->p2p_device_addr, 0); if (info == NULL) { dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer"); return FALSE; } if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING, &variant_iter)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to construct message 1", __func__); return FALSE; } if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING, &array_iter)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to construct message 2", __func__); return FALSE; } if (info->wps_sec_dev_type_list_len) { const u8 *sec_dev_type_list = info->wps_sec_dev_type_list; int num_sec_device_types = info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; int i; DBusMessageIter inner_array_iter; for (i = 0; i < num_sec_device_types; i++) { if (!dbus_message_iter_open_container( &array_iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &inner_array_iter)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to construct " "message 3 (%d)", __func__, i); return FALSE; } if (!dbus_message_iter_append_fixed_array( &inner_array_iter, DBUS_TYPE_BYTE, &sec_dev_type_list, WPS_DEV_TYPE_LEN)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to construct " "message 4 (%d)", __func__, i); return FALSE; } if (!dbus_message_iter_close_container( &array_iter, &inner_array_iter)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to construct " "message 5 (%d)", __func__, i); return FALSE; } sec_dev_type_list += WPS_DEV_TYPE_LEN; } } if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to construct message 6", __func__); return FALSE; } if (!dbus_message_iter_close_container(iter, &variant_iter)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to construct message 7", __func__); return FALSE; } return TRUE; } dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT]; int i, num; struct peer_handler_args *peer_args = user_data; const struct p2p_peer_info *info; info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, peer_args->p2p_device_addr, 0); if (info == NULL) { dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer"); return FALSE; } /* Add WPS vendor extensions attribute */ for (i = 0, num = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { if (info->wps_vendor_ext[i] == NULL) continue; vendor_extension[num] = info->wps_vendor_ext[i]; num++; } if (!wpas_dbus_simple_array_array_property_getter(iter, DBUS_TYPE_BYTE, vendor_extension, num, error)) return FALSE; return TRUE; } dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter, DBusError *error, void *user_data) { struct peer_handler_args *peer_args = user_data; const struct p2p_peer_info *info; info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, peer_args->p2p_device_addr, 0); if (info == NULL) { dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer"); return FALSE; } if (info->wfd_subelems == NULL) return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, NULL, 0, error); return wpas_dbus_simple_array_property_getter( iter, DBUS_TYPE_BYTE, (char *) info->wfd_subelems->buf, info->wfd_subelems->used, error); } dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(DBusMessageIter *iter, DBusError *error, void *user_data) { struct peer_handler_args *peer_args = user_data; const struct p2p_peer_info *info; info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, peer_args->p2p_device_addr, 0); if (info == NULL) { dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer"); return FALSE; } return wpas_dbus_simple_array_property_getter( iter, DBUS_TYPE_BYTE, (char *) info->p2p_device_addr, ETH_ALEN, error); } /** * wpas_dbus_getter_persistent_groups - Get array of persistent group objects * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "PersistentGroups" property. */ dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; struct wpa_ssid *ssid; char **paths; unsigned int i = 0, num = 0; dbus_bool_t success = FALSE; if (wpa_s->conf == NULL) { wpa_printf(MSG_ERROR, "dbus: %s: " "An error occurred getting persistent groups list", __func__); dbus_set_error_const(error, DBUS_ERROR_FAILED, "an error " "occurred getting persistent groups list"); return FALSE; } for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) if (network_is_persistent_group(ssid)) num++; paths = os_calloc(num, sizeof(char *)); if (!paths) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } /* Loop through configured networks and append object path of each */ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (!network_is_persistent_group(ssid)) continue; paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); if (paths[i] == NULL) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); goto out; } /* Construct the object path for this network. */ os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d", wpa_s->dbus_new_path, ssid->id); } success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_OBJECT_PATH, paths, num, error); out: while (i) os_free(paths[--i]); os_free(paths); return success; } /** * wpas_dbus_getter_persistent_group_properties - Get options for a persistent * group * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "Properties" property of a persistent group. */ dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter, DBusError *error, void *user_data) { struct network_handler_args *net = user_data; /* Leveraging the fact that persistent group object is still * represented in same manner as network within. */ return wpas_dbus_getter_network_properties(iter, error, net); } /** * wpas_dbus_setter_persistent_group_properties - Get options for a persistent * group * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Setter for "Properties" property of a persistent group. */ dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter, DBusError *error, void *user_data) { struct network_handler_args *net = user_data; struct wpa_ssid *ssid = net->ssid; DBusMessageIter variant_iter; /* * Leveraging the fact that persistent group object is still * represented in same manner as network within. */ dbus_message_iter_recurse(iter, &variant_iter); return set_network_properties(net->wpa_s, ssid, &variant_iter, error); } /** * wpas_dbus_new_iface_add_persistent_group - Add a new configured * persistent_group * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A dbus message containing the object path of the new * persistent group * * Handler function for "AddPersistentGroup" method call of a P2P Device * interface. */ DBusMessage * wpas_dbus_handler_add_persistent_group( DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; DBusMessageIter iter; struct wpa_ssid *ssid = NULL; char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; DBusError error; dbus_message_iter_init(message, &iter); ssid = wpa_config_add_network(wpa_s->conf); if (ssid == NULL) { wpa_printf(MSG_ERROR, "dbus: %s: " "Cannot add new persistent group", __func__); reply = wpas_dbus_error_unknown_error( message, "wpa_supplicant could not add " "a persistent group on this interface."); goto err; } /* Mark the ssid as being a persistent group before the notification */ ssid->disabled = 2; ssid->p2p_persistent_group = 1; wpas_notify_persistent_group_added(wpa_s, ssid); wpa_config_set_network_defaults(ssid); dbus_error_init(&error); if (!set_network_properties(wpa_s, ssid, &iter, &error)) { wpa_printf(MSG_DEBUG, "dbus: %s: " "Control interface could not set persistent group " "properties", __func__); reply = wpas_dbus_reply_new_from_error(message, &error, DBUS_ERROR_INVALID_ARGS, "Failed to set network " "properties"); dbus_error_free(&error); goto err; } /* Construct the object path for this network. */ os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d", wpa_s->dbus_new_path, ssid->id); reply = dbus_message_new_method_return(message); if (reply == NULL) { reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); goto err; } if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { dbus_message_unref(reply); reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); goto err; } return reply; err: if (ssid) { wpas_notify_persistent_group_removed(wpa_s, ssid); wpa_config_remove_network(wpa_s->conf, ssid->id); } return reply; } /** * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent * group * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NULL on success or dbus error on failure * * Handler function for "RemovePersistentGroup" method call of a P2P Device * interface. */ DBusMessage * wpas_dbus_handler_remove_persistent_group( DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; const char *op; char *iface = NULL, *persistent_group_id = NULL; int id; struct wpa_ssid *ssid; dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, DBUS_TYPE_INVALID); /* * Extract the network ID and ensure the network is actually a child of * this interface. */ iface = wpas_dbus_new_decompose_object_path(op, 1, &persistent_group_id, NULL); if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { reply = wpas_dbus_error_invalid_args(message, op); goto out; } id = strtoul(persistent_group_id, NULL, 10); if (errno == EINVAL) { reply = wpas_dbus_error_invalid_args(message, op); goto out; } ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { reply = wpas_dbus_error_persistent_group_unknown(message); goto out; } wpas_notify_persistent_group_removed(wpa_s, ssid); if (wpa_config_remove_network(wpa_s->conf, id) < 0) { wpa_printf(MSG_ERROR, "dbus: %s: " "error occurred when removing persistent group %d", __func__, id); reply = wpas_dbus_error_unknown_error( message, "error removing the specified persistent group on " "this interface."); goto out; } out: os_free(iface); os_free(persistent_group_id); return reply; } static void remove_persistent_group(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { wpas_notify_persistent_group_removed(wpa_s, ssid); if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) { wpa_printf(MSG_ERROR, "dbus: %s: " "error occurred when removing persistent group %d", __func__, ssid->id); return; } } /** * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured * persistent groups * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NULL on success or dbus error on failure * * Handler function for "RemoveAllPersistentGroups" method call of a * P2P Device interface. */ DBusMessage * wpas_dbus_handler_remove_all_persistent_groups( DBusMessage *message, struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid, *next; struct wpa_config *config; config = wpa_s->conf; ssid = config->ssid; while (ssid) { next = ssid->next; if (network_is_persistent_group(ssid)) remove_persistent_group(wpa_s, ssid); ssid = next; } return NULL; } /* * Group object properties accessor methods */ dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; struct wpa_ssid *ssid; unsigned int num_members; char **paths; unsigned int i; void *next = NULL; const u8 *addr; dbus_bool_t success = FALSE; /* Verify correct role for this property */ if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_GO) { return wpas_dbus_simple_array_property_getter( iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error); } ssid = wpa_s->conf->ssid; /* At present WPAS P2P_GO mode only applicable for p2p_go */ if (ssid->mode != WPAS_MODE_P2P_GO && ssid->mode != WPAS_MODE_AP && ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) return FALSE; num_members = p2p_get_group_num_members(wpa_s->p2p_group); paths = os_calloc(num_members, sizeof(char *)); if (!paths) goto out_of_memory; i = 0; while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) { paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); if (!paths[i]) goto out_of_memory; os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR, wpa_s->dbus_groupobj_path, MAC2STR(addr)); i++; } success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_OBJECT_PATH, paths, num_members, error); for (i = 0; i < num_members; i++) os_free(paths[i]); os_free(paths); return success; out_of_memory: dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); if (paths) { for (i = 0; i < num_members; i++) os_free(paths[i]); os_free(paths); } return FALSE; } dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; if (wpa_s->current_ssid == NULL) return FALSE; return wpas_dbus_simple_array_property_getter( iter, DBUS_TYPE_BYTE, wpa_s->current_ssid->ssid, wpa_s->current_ssid->ssid_len, error); } dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; u8 role = wpas_get_p2p_role(wpa_s); u8 *p_bssid; if (role == WPAS_P2P_ROLE_CLIENT) { if (wpa_s->current_ssid == NULL) return FALSE; p_bssid = wpa_s->current_ssid->bssid; } else { if (wpa_s->ap_iface == NULL) return FALSE; p_bssid = wpa_s->ap_iface->bss[0]->own_addr; } return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, p_bssid, ETH_ALEN, error); } dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; u16 op_freq; u8 role = wpas_get_p2p_role(wpa_s); if (role == WPAS_P2P_ROLE_CLIENT) { if (wpa_s->go_params == NULL) return FALSE; op_freq = wpa_s->go_params->freq; } else { if (wpa_s->ap_iface == NULL) return FALSE; op_freq = wpa_s->ap_iface->freq; } return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, &op_freq, error); } dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; u8 role = wpas_get_p2p_role(wpa_s); char *p_pass = NULL; /* Verify correct role for this property */ if (role == WPAS_P2P_ROLE_GO) { if (wpa_s->current_ssid == NULL) return FALSE; p_pass = wpa_s->current_ssid->passphrase; } else p_pass = ""; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &p_pass, error); } dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; u8 role = wpas_get_p2p_role(wpa_s); u8 *p_psk = NULL; u8 psk_len = 0; /* Verify correct role for this property */ if (role == WPAS_P2P_ROLE_CLIENT) { if (wpa_s->current_ssid == NULL) return FALSE; p_psk = wpa_s->current_ssid->psk; psk_len = 32; } return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, &p_psk, psk_len, error); } dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; struct hostapd_data *hapd; struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; int num_vendor_ext = 0; int i; /* Verify correct role for this property */ if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO) { if (wpa_s->ap_iface == NULL) return FALSE; hapd = wpa_s->ap_iface->bss[0]; /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { if (hapd->conf->wps_vendor_ext[i] == NULL) vendor_ext[i] = NULL; else { vendor_ext[num_vendor_ext++] = hapd->conf->wps_vendor_ext[i]; } } } /* Return vendor extensions or no data */ return wpas_dbus_simple_array_array_property_getter(iter, DBUS_TYPE_BYTE, vendor_ext, num_vendor_ext, error); } dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; DBusMessageIter variant_iter, iter_dict; struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; unsigned int i; struct hostapd_data *hapd = NULL; if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO && wpa_s->ap_iface != NULL) hapd = wpa_s->ap_iface->bss[0]; else return FALSE; dbus_message_iter_recurse(iter, &variant_iter); if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error)) return FALSE; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, "invalid message format"); return FALSE; } if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) { if (entry.type != DBUS_TYPE_ARRAY || entry.array_type != WPAS_DBUS_TYPE_BINARRAY || entry.array_len > MAX_WPS_VENDOR_EXTENSIONS) goto error; for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { if (i < entry.array_len) { hapd->conf->wps_vendor_ext[i] = entry.binarray_value[i]; entry.binarray_value[i] = NULL; } else hapd->conf->wps_vendor_ext[i] = NULL; } hostapd_update_wps(hapd); } else goto error; wpa_dbus_dict_entry_clear(&entry); } return TRUE; error: wpa_dbus_dict_entry_clear(&entry); dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, "invalid message format"); return FALSE; } DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessageIter iter_dict; DBusMessage *reply = NULL; DBusMessageIter iter; struct wpa_dbus_dict_entry entry; int upnp = 0; int bonjour = 0; char *service = NULL; struct wpabuf *query = NULL; struct wpabuf *resp = NULL; u8 version = 0; dbus_message_iter_init(message, &iter); if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto error; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; if (!os_strcmp(entry.key, "service_type") && (entry.type == DBUS_TYPE_STRING)) { if (!os_strcmp(entry.str_value, "upnp")) upnp = 1; else if (!os_strcmp(entry.str_value, "bonjour")) bonjour = 1; else goto error_clear; } else if (!os_strcmp(entry.key, "version") && entry.type == DBUS_TYPE_INT32) { version = entry.uint32_value; } else if (!os_strcmp(entry.key, "service") && (entry.type == DBUS_TYPE_STRING)) { service = os_strdup(entry.str_value); } else if (!os_strcmp(entry.key, "query")) { if ((entry.type != DBUS_TYPE_ARRAY) || (entry.array_type != DBUS_TYPE_BYTE)) goto error_clear; query = wpabuf_alloc_copy( entry.bytearray_value, entry.array_len); } else if (!os_strcmp(entry.key, "response")) { if ((entry.type != DBUS_TYPE_ARRAY) || (entry.array_type != DBUS_TYPE_BYTE)) goto error_clear; resp = wpabuf_alloc_copy(entry.bytearray_value, entry.array_len); } wpa_dbus_dict_entry_clear(&entry); } if (upnp == 1) { if (version <= 0 || service == NULL) goto error; if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0) goto error; os_free(service); service = NULL; } else if (bonjour == 1) { if (query == NULL || resp == NULL) goto error; if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) goto error; query = NULL; resp = NULL; } else goto error; return reply; error_clear: wpa_dbus_dict_entry_clear(&entry); error: os_free(service); wpabuf_free(query); wpabuf_free(resp); return wpas_dbus_error_invalid_args(message, NULL); } DBusMessage * wpas_dbus_handler_p2p_delete_service( DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessageIter iter_dict; DBusMessage *reply = NULL; DBusMessageIter iter; struct wpa_dbus_dict_entry entry; int upnp = 0; int bonjour = 0; int ret = 0; char *service = NULL; struct wpabuf *query = NULL; u8 version = 0; dbus_message_iter_init(message, &iter); if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto error; if (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; if (!os_strcmp(entry.key, "service_type") && (entry.type == DBUS_TYPE_STRING)) { if (!os_strcmp(entry.str_value, "upnp")) upnp = 1; else if (!os_strcmp(entry.str_value, "bonjour")) bonjour = 1; else goto error_clear; wpa_dbus_dict_entry_clear(&entry); } } if (upnp == 1) { while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; if (!os_strcmp(entry.key, "version") && entry.type == DBUS_TYPE_INT32) version = entry.uint32_value; else if (!os_strcmp(entry.key, "service") && entry.type == DBUS_TYPE_STRING) service = os_strdup(entry.str_value); else goto error_clear; wpa_dbus_dict_entry_clear(&entry); } if (version <= 0 || service == NULL) goto error; ret = wpas_p2p_service_del_upnp(wpa_s, version, service); os_free(service); if (ret != 0) goto error; } else if (bonjour == 1) { while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; if (!os_strcmp(entry.key, "query")) { if ((entry.type != DBUS_TYPE_ARRAY) || (entry.array_type != DBUS_TYPE_BYTE)) goto error_clear; query = wpabuf_alloc_copy( entry.bytearray_value, entry.array_len); } else goto error_clear; wpa_dbus_dict_entry_clear(&entry); } if (query == NULL) goto error; ret = wpas_p2p_service_del_bonjour(wpa_s, query); if (ret != 0) goto error; wpabuf_free(query); } else goto error; return reply; error_clear: wpa_dbus_dict_entry_clear(&entry); error: return wpas_dbus_error_invalid_args(message, NULL); } DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message, struct wpa_supplicant *wpa_s) { wpas_p2p_service_flush(wpa_s); return NULL; } DBusMessage * wpas_dbus_handler_p2p_service_sd_req( DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessageIter iter_dict; DBusMessage *reply = NULL; DBusMessageIter iter; struct wpa_dbus_dict_entry entry; int upnp = 0; char *service = NULL; char *peer_object_path = NULL; struct wpabuf *tlv = NULL; u8 version = 0; u64 ref = 0; u8 addr_buf[ETH_ALEN], *addr; dbus_message_iter_init(message, &iter); if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto error; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; if (!os_strcmp(entry.key, "peer_object") && entry.type == DBUS_TYPE_OBJECT_PATH) { peer_object_path = os_strdup(entry.str_value); } else if (!os_strcmp(entry.key, "service_type") && entry.type == DBUS_TYPE_STRING) { if (!os_strcmp(entry.str_value, "upnp")) upnp = 1; else goto error_clear; } else if (!os_strcmp(entry.key, "version") && entry.type == DBUS_TYPE_INT32) { version = entry.uint32_value; } else if (!os_strcmp(entry.key, "service") && entry.type == DBUS_TYPE_STRING) { service = os_strdup(entry.str_value); } else if (!os_strcmp(entry.key, "tlv")) { if (entry.type != DBUS_TYPE_ARRAY || entry.array_type != DBUS_TYPE_BYTE) goto error_clear; tlv = wpabuf_alloc_copy(entry.bytearray_value, entry.array_len); } else goto error_clear; wpa_dbus_dict_entry_clear(&entry); } if (!peer_object_path) { addr = NULL; } else { if (parse_peer_object_path(peer_object_path, addr_buf) < 0 || !p2p_peer_known(wpa_s->global->p2p, addr_buf)) goto error; addr = addr_buf; } if (upnp == 1) { if (version <= 0 || service == NULL) goto error; ref = wpas_p2p_sd_request_upnp(wpa_s, addr, version, service); } else { if (tlv == NULL) goto error; ref = wpas_p2p_sd_request(wpa_s, addr, tlv); wpabuf_free(tlv); } if (ref != 0) { reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_UINT64, &ref, DBUS_TYPE_INVALID); } else { reply = wpas_dbus_error_unknown_error( message, "Unable to send SD request"); } out: os_free(service); os_free(peer_object_path); return reply; error_clear: wpa_dbus_dict_entry_clear(&entry); error: if (tlv) wpabuf_free(tlv); reply = wpas_dbus_error_invalid_args(message, NULL); goto out; } DBusMessage * wpas_dbus_handler_p2p_service_sd_res( DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessageIter iter_dict; DBusMessage *reply = NULL; DBusMessageIter iter; struct wpa_dbus_dict_entry entry; char *peer_object_path = NULL; struct wpabuf *tlv = NULL; int freq = 0; int dlg_tok = 0; u8 addr[ETH_ALEN]; dbus_message_iter_init(message, &iter); if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto error; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; if (!os_strcmp(entry.key, "peer_object") && entry.type == DBUS_TYPE_OBJECT_PATH) { peer_object_path = os_strdup(entry.str_value); } else if (!os_strcmp(entry.key, "frequency") && entry.type == DBUS_TYPE_INT32) { freq = entry.uint32_value; } else if (!os_strcmp(entry.key, "dialog_token") && entry.type == DBUS_TYPE_UINT32) { dlg_tok = entry.uint32_value; } else if (!os_strcmp(entry.key, "tlvs")) { if (entry.type != DBUS_TYPE_ARRAY || entry.array_type != DBUS_TYPE_BYTE) goto error_clear; tlv = wpabuf_alloc_copy(entry.bytearray_value, entry.array_len); } else goto error_clear; wpa_dbus_dict_entry_clear(&entry); } if (!peer_object_path || (parse_peer_object_path(peer_object_path, addr) < 0) || !p2p_peer_known(wpa_s->global->p2p, addr)) goto error; if (tlv == NULL) goto error; wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv); wpabuf_free(tlv); out: os_free(peer_object_path); return reply; error_clear: wpa_dbus_dict_entry_clear(&entry); error: reply = wpas_dbus_error_invalid_args(message, NULL); goto out; } DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req( DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessageIter iter; u64 req = 0; dbus_message_iter_init(message, &iter); dbus_message_iter_get_basic(&iter, &req); if (req == 0) goto error; if (wpas_p2p_sd_cancel_request(wpa_s, req) < 0) goto error; return NULL; error: return wpas_dbus_error_invalid_args(message, NULL); } DBusMessage * wpas_dbus_handler_p2p_service_update( DBusMessage *message, struct wpa_supplicant *wpa_s) { wpas_p2p_sd_service_update(wpa_s); return NULL; } DBusMessage * wpas_dbus_handler_p2p_serv_disc_external( DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessageIter iter; int ext = 0; dbus_message_iter_init(message, &iter); dbus_message_iter_get_basic(&iter, &ext); wpa_s->p2p_sd_over_ctrl_iface = ext; return NULL; } wpa_supplicant-2.2/wpa_supplicant/dbus/Makefile0000664000175000017500000000223112343617166017643 0ustar jmjmall: libwpadbus.a clean: rm -f *~ *.o *.d *.gcno *.gcda *.gcov rm -f libwpadbus.a install: @echo Nothing to be made. ifndef CC CC=gcc endif ifndef CFLAGS CFLAGS = -MMD -O2 -Wall -g endif PKG_CONFIG ?= pkg-config CFLAGS += -I../../src -I../../src/utils Q=@ E=echo ifeq ($(V), 1) Q= E=true endif %.o: %.c $(Q)$(CC) -c -o $@ $(CFLAGS) $< @$(E) " CC " $< ifdef CONFIG_WPS CFLAGS += -DCONFIG_WPS endif CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW CFLAGS += -DCONFIG_CTRL_IFACE_DBUS ifndef DBUS_LIBS DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1) endif ifndef DBUS_INCLUDE DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1) endif ifdef CONFIG_CTRL_IFACE_DBUS_INTRO CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO DBUS_INCLUDE += $(shell xml2-config --cflags) DBUS_LIBS += $(shell xml2-config --libs) endif CFLAGS += $(DBUS_INCLUDE) LIB_OBJS= \ dbus_common.o \ dbus_old.o \ dbus_old_handlers.o \ dbus_new.o \ dbus_new_handlers.o \ dbus_new_helpers.o \ dbus_new_introspect.o \ dbus_dict_helpers.o ifdef CONFIG_WPS LIB_OBJS += dbus_old_handlers_wps.o LIB_OBJS += dbus_new_handlers_wps.o endif libwpadbus.a: $(LIB_OBJS) $(AR) crT $@ $? -include $(OBJS:%.o=%.d) wpa_supplicant-2.2/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in0000664000175000017500000000020512343617166026231 0ustar jmjm[D-BUS Service] Name=fi.epitest.hostap.WPASupplicant Exec=@BINDIR@/wpa_supplicant -u User=root SystemdService=wpa_supplicant.service wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_new_handlers_p2p.h0000664000175000017500000001550612343617166022634 0ustar jmjm/* * WPA Supplicant / dbus-based control interface for p2p * Copyright (c) 2011-2012, Intel Corporation * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef DBUS_NEW_HANDLERS_P2P_H #define DBUS_NEW_HANDLERS_P2P_H struct peer_handler_args { struct wpa_supplicant *wpa_s; u8 p2p_device_addr[ETH_ALEN]; }; struct groupmember_handler_args { struct wpa_supplicant *wpa_s; u8 member_addr[ETH_ALEN]; }; /* * P2P Device methods */ DBusMessage *wpas_dbus_handler_p2p_find( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_stop_find( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_rejectpeer( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_listen( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_extendedlisten( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_presence_request( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_prov_disc_req( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_group_add( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_connect( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_invite( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_disconnect( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_flush( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_add_service( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_delete_service( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_flush_service( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_service_sd_req( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_service_sd_res( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_service_update( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage *wpas_dbus_handler_p2p_serv_disc_external( DBusMessage *message, struct wpa_supplicant *wpa_s); /* * P2P Device property accessor methods. */ dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter, DBusError *error, void *user_data); /* * P2P Peer properties. */ dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type( DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types( DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(DBusMessageIter *iter, DBusError *error, void *user_data); /* * P2P Group properties */ dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter, DBusError *error, void *user_data); /* * P2P Persistent Groups and properties */ dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter, DBusError *error, void *user_data); dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter, DBusError *error, void *user_data); DBusMessage * wpas_dbus_handler_add_persistent_group( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_remove_persistent_group( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_remove_all_persistent_groups( DBusMessage *message, struct wpa_supplicant *wpa_s); #endif /* DBUS_NEW_HANDLERS_P2P_H */ wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_old.h0000664000175000017500000000774612343617166020167 0ustar jmjm/* * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef CTRL_IFACE_DBUS_H #define CTRL_IFACE_DBUS_H struct wps_credential; #ifdef CONFIG_CTRL_IFACE_DBUS #define WPAS_DBUS_OBJECT_PATH_MAX 150 #define WPAS_DBUS_SERVICE "fi.epitest.hostap.WPASupplicant" #define WPAS_DBUS_PATH "/fi/epitest/hostap/WPASupplicant" #define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicant" #define WPAS_DBUS_PATH_INTERFACES WPAS_DBUS_PATH "/Interfaces" #define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface" #define WPAS_DBUS_NETWORKS_PART "Networks" #define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network" #define WPAS_DBUS_BSSIDS_PART "BSSIDs" #define WPAS_DBUS_IFACE_BSSID WPAS_DBUS_INTERFACE ".BSSID" /* Errors */ #define WPAS_ERROR_INVALID_NETWORK \ WPAS_DBUS_IFACE_INTERFACE ".InvalidNetwork" #define WPAS_ERROR_INVALID_BSSID \ WPAS_DBUS_IFACE_INTERFACE ".InvalidBSSID" #define WPAS_ERROR_INVALID_OPTS \ WPAS_DBUS_INTERFACE ".InvalidOptions" #define WPAS_ERROR_INVALID_IFACE \ WPAS_DBUS_INTERFACE ".InvalidInterface" #define WPAS_ERROR_ADD_ERROR \ WPAS_DBUS_INTERFACE ".AddError" #define WPAS_ERROR_EXISTS_ERROR \ WPAS_DBUS_INTERFACE ".ExistsError" #define WPAS_ERROR_REMOVE_ERROR \ WPAS_DBUS_INTERFACE ".RemoveError" #define WPAS_ERROR_SCAN_ERROR \ WPAS_DBUS_IFACE_INTERFACE ".ScanError" #define WPAS_ERROR_ADD_NETWORK_ERROR \ WPAS_DBUS_IFACE_INTERFACE ".AddNetworkError" #define WPAS_ERROR_INTERNAL_ERROR \ WPAS_DBUS_IFACE_INTERFACE ".InternalError" #define WPAS_ERROR_REMOVE_NETWORK_ERROR \ WPAS_DBUS_IFACE_INTERFACE ".RemoveNetworkError" #define WPAS_ERROR_WPS_PBC_ERROR \ WPAS_DBUS_IFACE_INTERFACE ".WpsPbcError" #define WPAS_ERROR_WPS_PIN_ERROR \ WPAS_DBUS_IFACE_INTERFACE ".WpsPinError" #define WPAS_ERROR_WPS_REG_ERROR \ WPAS_DBUS_IFACE_INTERFACE ".WpsRegError" #define WPAS_DBUS_BSSID_FORMAT "%02x%02x%02x%02x%02x%02x" struct wpa_global; struct wpa_supplicant; int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface); void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s); void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s); void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, enum wpa_states new_state, enum wpa_states old_state); void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, const struct wps_credential *cred); void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s, int depth, const char *subject, const char *cert_hash, const struct wpabuf *cert); char * wpas_dbus_decompose_object_path(const char *path, char **network, char **bssid); int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s); int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s); /* Methods internal to the dbus control interface */ struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path( struct wpa_global *global, const char *path); #else /* CONFIG_CTRL_IFACE_DBUS */ static inline void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) { } static inline void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s) { } #define wpa_supplicant_dbus_notify_state_change(w,n,o) do { } while (0) static inline void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, const struct wps_credential *cred) { } static inline void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s, int depth, const char *subject, const char *cert_hash, const struct wpabuf *cert) { } static inline int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) { return 0; } static inline int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) { return 0; } #endif /* CONFIG_CTRL_IFACE_DBUS */ #endif /* CTRL_IFACE_DBUS_H */ wpa_supplicant-2.2/wpa_supplicant/dbus/dbus-wpa_supplicant.conf0000664000175000017500000000232012343617166023035 0ustar jmjm wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_old_handlers.h0000664000175000017500000000662612343617166022043 0ustar jmjm/* * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef CTRL_IFACE_DBUS_HANDLERS_H #define CTRL_IFACE_DBUS_HANDLERS_H struct wpa_bss; DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message); DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message); DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message, struct wpa_global *global); DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message, struct wpa_global *global); DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message, struct wpa_global *global); DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message, struct wpa_global *global); DBusMessage * wpas_dbus_iface_scan(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message, struct wpa_supplicant *wpa_s, struct wpa_bss *bss); DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message, struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message, struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_set_smartcard_modules( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_iface_flush(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message); DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message, const char *arg); #endif /* CTRL_IFACE_DBUS_HANDLERS_H */ wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_dict_helpers.h0000664000175000017500000001262612343617166022047 0ustar jmjm/* * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef DBUS_DICT_HELPERS_H #define DBUS_DICT_HELPERS_H #include "wpabuf.h" /* * Adding a dict to a DBusMessage */ dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter, DBusMessageIter *iter_dict); dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter, DBusMessageIter *iter_dict); const char * wpa_dbus_type_as_string(const int type); dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict, const char *key, const char *value); dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict, const char *key, const char value); dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict, const char *key, const dbus_bool_t value); dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict, const char *key, const dbus_int16_t value); dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict, const char *key, const dbus_uint16_t value); dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict, const char *key, const dbus_int32_t value); dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict, const char *key, const dbus_uint32_t value); dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict, const char *key, const dbus_int64_t value); dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict, const char *key, const dbus_uint64_t value); dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict, const char *key, const double value); dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict, const char *key, const char *value); dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict, const char *key, const char *value, const dbus_uint32_t value_len); /* Manual construction and addition of array elements */ dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict, const char *key, const char *type, DBusMessageIter *iter_dict_entry, DBusMessageIter *iter_dict_val, DBusMessageIter *iter_array); dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict, const char *key, DBusMessageIter *iter_dict_entry, DBusMessageIter *iter_dict_val, DBusMessageIter *iter_array); dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array, const char *elem); dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array, const u8 *value, size_t value_len); dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry, DBusMessageIter *iter_dict_val, DBusMessageIter *iter_array); static inline dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry, DBusMessageIter *iter_dict_val, DBusMessageIter *iter_array) { return wpa_dbus_dict_end_array(iter_dict, iter_dict_entry, iter_dict_val, iter_array); } /* Convenience function to add a whole string list */ dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict, const char *key, const char **items, const dbus_uint32_t num_items); dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict, const char *key, const struct wpabuf **items, const dbus_uint32_t num_items); /* * Reading a dict from a DBusMessage */ #define WPAS_DBUS_TYPE_BINARRAY (DBUS_NUMBER_OF_TYPES + 100) struct wpa_dbus_dict_entry { int type; /** the dbus type of the dict entry's value */ int array_type; /** the dbus type of the array elements if the dict entry value contains an array, or the special WPAS_DBUS_TYPE_BINARRAY */ const char *key; /** key of the dict entry */ /** Possible values of the property */ union { char *str_value; char byte_value; dbus_bool_t bool_value; dbus_int16_t int16_value; dbus_uint16_t uint16_value; dbus_int32_t int32_value; dbus_uint32_t uint32_value; dbus_int64_t int64_value; dbus_uint64_t uint64_value; double double_value; char *bytearray_value; char **strarray_value; struct wpabuf **binarray_value; }; dbus_uint32_t array_len; /** length of the array if the dict entry's value contains an array */ }; dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter, DBusMessageIter *iter_dict, DBusError *error); dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict, struct wpa_dbus_dict_entry *entry); dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict); void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry); #endif /* DBUS_DICT_HELPERS_H */ wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_common.c0000664000175000017500000002207712343617166020666 0ustar jmjm/* * wpa_supplicant D-Bus control interface - common functionality * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * Copyright (c) 2009, Witold Sowa * Copyright (c) 2009, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "utils/includes.h" #include #include "utils/common.h" #include "utils/eloop.h" #include "dbus_common.h" #include "dbus_common_i.h" #include "dbus_new.h" #include "dbus_old.h" #include "../wpa_supplicant_i.h" #ifndef SIGPOLL #ifdef SIGIO /* * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for * FreeBSD. */ #define SIGPOLL SIGIO #endif #endif static void dispatch_data(DBusConnection *con) { while (dbus_connection_get_dispatch_status(con) == DBUS_DISPATCH_DATA_REMAINS) dbus_connection_dispatch(con); } /** * dispatch_initial_dbus_messages - Dispatch initial dbus messages after * claiming bus name * @eloop_ctx: the DBusConnection to dispatch on * @timeout_ctx: unused * * If clients are quick to notice that service claimed its bus name, * there may have been messages that came in before initialization was * all finished. Dispatch those here. */ static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx) { DBusConnection *con = eloop_ctx; dispatch_data(con); } static void process_watch(struct wpas_dbus_priv *priv, DBusWatch *watch, eloop_event_type type) { dbus_connection_ref(priv->con); priv->should_dispatch = 0; if (type == EVENT_TYPE_READ) dbus_watch_handle(watch, DBUS_WATCH_READABLE); else if (type == EVENT_TYPE_WRITE) dbus_watch_handle(watch, DBUS_WATCH_WRITABLE); else if (type == EVENT_TYPE_EXCEPTION) dbus_watch_handle(watch, DBUS_WATCH_ERROR); if (priv->should_dispatch) { dispatch_data(priv->con); priv->should_dispatch = 0; } dbus_connection_unref(priv->con); } static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx) { process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION); } static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx) { process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ); } static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx) { process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE); } static dbus_bool_t add_watch(DBusWatch *watch, void *data) { struct wpas_dbus_priv *priv = data; unsigned int flags; int fd; if (!dbus_watch_get_enabled(watch)) return TRUE; flags = dbus_watch_get_flags(watch); fd = dbus_watch_get_unix_fd(watch); eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception, priv, watch); if (flags & DBUS_WATCH_READABLE) { eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read, priv, watch); } if (flags & DBUS_WATCH_WRITABLE) { eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write, priv, watch); } dbus_watch_set_data(watch, priv, NULL); return TRUE; } static void remove_watch(DBusWatch *watch, void *data) { unsigned int flags; int fd; flags = dbus_watch_get_flags(watch); fd = dbus_watch_get_unix_fd(watch); eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION); if (flags & DBUS_WATCH_READABLE) eloop_unregister_sock(fd, EVENT_TYPE_READ); if (flags & DBUS_WATCH_WRITABLE) eloop_unregister_sock(fd, EVENT_TYPE_WRITE); dbus_watch_set_data(watch, NULL, NULL); } static void watch_toggled(DBusWatch *watch, void *data) { if (dbus_watch_get_enabled(watch)) add_watch(watch, data); else remove_watch(watch, data); } static void process_timeout(void *eloop_ctx, void *sock_ctx) { DBusTimeout *timeout = sock_ctx; dbus_timeout_handle(timeout); } static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) { struct wpas_dbus_priv *priv = data; if (!dbus_timeout_get_enabled(timeout)) return TRUE; eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000, process_timeout, priv, timeout); dbus_timeout_set_data(timeout, priv, NULL); return TRUE; } static void remove_timeout(DBusTimeout *timeout, void *data) { struct wpas_dbus_priv *priv = data; eloop_cancel_timeout(process_timeout, priv, timeout); dbus_timeout_set_data(timeout, NULL, NULL); } static void timeout_toggled(DBusTimeout *timeout, void *data) { if (dbus_timeout_get_enabled(timeout)) add_timeout(timeout, data); else remove_timeout(timeout, data); } static void process_wakeup_main(int sig, void *signal_ctx) { struct wpas_dbus_priv *priv = signal_ctx; if (sig != SIGPOLL || !priv->con) return; if (dbus_connection_get_dispatch_status(priv->con) != DBUS_DISPATCH_DATA_REMAINS) return; /* Only dispatch once - we do not want to starve other events */ dbus_connection_ref(priv->con); dbus_connection_dispatch(priv->con); dbus_connection_unref(priv->con); } /** * wakeup_main - Attempt to wake our mainloop up * @data: dbus control interface private data * * Try to wake up the main eloop so it will process * dbus events that may have happened. */ static void wakeup_main(void *data) { struct wpas_dbus_priv *priv = data; /* Use SIGPOLL to break out of the eloop select() */ raise(SIGPOLL); priv->should_dispatch = 1; } /** * integrate_with_eloop - Register our mainloop integration with dbus * @connection: connection to the system message bus * @priv: a dbus control interface data structure * Returns: 0 on success, -1 on failure */ static int integrate_with_eloop(struct wpas_dbus_priv *priv) { if (!dbus_connection_set_watch_functions(priv->con, add_watch, remove_watch, watch_toggled, priv, NULL) || !dbus_connection_set_timeout_functions(priv->con, add_timeout, remove_timeout, timeout_toggled, priv, NULL)) { wpa_printf(MSG_ERROR, "dbus: Failed to set callback " "functions"); return -1; } if (eloop_register_signal(SIGPOLL, process_wakeup_main, priv)) return -1; dbus_connection_set_wakeup_main_function(priv->con, wakeup_main, priv, NULL); return 0; } static DBusHandlerResult disconnect_filter(DBusConnection *conn, DBusMessage *message, void *data) { struct wpas_dbus_priv *priv = data; if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { wpa_printf(MSG_DEBUG, "dbus: bus disconnected, terminating"); dbus_connection_set_exit_on_disconnect(conn, FALSE); wpa_supplicant_terminate_proc(priv->global); return DBUS_HANDLER_RESULT_HANDLED; } else return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static int wpas_dbus_init_common(struct wpas_dbus_priv *priv) { DBusError error; int ret = 0; /* Get a reference to the system bus */ dbus_error_init(&error); priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error); if (priv->con) { dbus_connection_add_filter(priv->con, disconnect_filter, priv, NULL); } else { wpa_printf(MSG_ERROR, "dbus: Could not acquire the system " "bus: %s - %s", error.name, error.message); ret = -1; } dbus_error_free(&error); return ret; } static int wpas_dbus_init_common_finish(struct wpas_dbus_priv *priv) { /* Tell dbus about our mainloop integration functions */ integrate_with_eloop(priv); /* * Dispatch initial DBus messages that may have come in since the bus * name was claimed above. Happens when clients are quick to notice the * service. * * FIXME: is there a better solution to this problem? */ eloop_register_timeout(0, 50, dispatch_initial_dbus_messages, priv->con, NULL); return 0; } static void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv) { if (priv->con) { eloop_cancel_timeout(dispatch_initial_dbus_messages, priv->con, NULL); eloop_cancel_timeout(process_timeout, priv, ELOOP_ALL_CTX); dbus_connection_set_watch_functions(priv->con, NULL, NULL, NULL, NULL, NULL); dbus_connection_set_timeout_functions(priv->con, NULL, NULL, NULL, NULL, NULL); dbus_connection_remove_filter(priv->con, disconnect_filter, priv); dbus_connection_unref(priv->con); } os_free(priv); } struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global) { struct wpas_dbus_priv *priv; priv = os_zalloc(sizeof(*priv)); if (priv == NULL) return NULL; priv->global = global; if (wpas_dbus_init_common(priv) < 0) { wpas_dbus_deinit(priv); return NULL; } #ifdef CONFIG_CTRL_IFACE_DBUS_NEW if (wpas_dbus_ctrl_iface_init(priv) < 0) { wpas_dbus_deinit(priv); return NULL; } #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ #ifdef CONFIG_CTRL_IFACE_DBUS if (wpa_supplicant_dbus_ctrl_iface_init(priv) < 0) { wpas_dbus_deinit(priv); return NULL; } #endif /* CONFIG_CTRL_IFACE_DBUS */ if (wpas_dbus_init_common_finish(priv) < 0) { wpas_dbus_deinit(priv); return NULL; } return priv; } void wpas_dbus_deinit(struct wpas_dbus_priv *priv) { if (priv == NULL) return; #ifdef CONFIG_CTRL_IFACE_DBUS_NEW wpas_dbus_ctrl_iface_deinit(priv); #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ #ifdef CONFIG_CTRL_IFACE_DBUS /* TODO: is any deinit needed? */ #endif /* CONFIG_CTRL_IFACE_DBUS */ wpas_dbus_deinit_common(priv); } wpa_supplicant-2.2/wpa_supplicant/dbus/.gitignore0000664000175000017500000000001512343617166020171 0ustar jmjmlibwpadbus.a wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_common_i.h0000664000175000017500000000134612343617166021177 0ustar jmjm/* * wpa_supplicant D-Bus control interface - internal definitions * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * Copyright (c) 2009, Witold Sowa * Copyright (c) 2009, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef DBUS_COMMON_I_H #define DBUS_COMMON_I_H #include struct wpas_dbus_priv { DBusConnection *con; int should_dispatch; struct wpa_global *global; u32 next_objid; int dbus_new_initialized; #if defined(CONFIG_CTRL_IFACE_DBUS_NEW) && defined(CONFIG_AP) int dbus_noc_refcnt; #endif /* CONFIG_CTRL_IFACE_DBUS_NEW && CONFIG_AP */ }; #endif /* DBUS_COMMON_I_H */ wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_new_handlers.c0000664000175000017500000034224612343617166022052 0ustar jmjm/* * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * Copyright (c) 2009-2010, Witold Sowa * Copyright (c) 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 "common/ieee802_11_defs.h" #include "eap_peer/eap_methods.h" #include "eapol_supp/eapol_supp_sm.h" #include "rsn_supp/wpa.h" #include "../config.h" #include "../wpa_supplicant_i.h" #include "../driver_i.h" #include "../notify.h" #include "../bss.h" #include "../scan.h" #include "../autoscan.h" #include "dbus_new_helpers.h" #include "dbus_new.h" #include "dbus_new_handlers.h" #include "dbus_dict_helpers.h" #include "dbus_common_i.h" static const char *debug_strings[] = { "excessive", "msgdump", "debug", "info", "warning", "error", NULL }; /** * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message * @message: Pointer to incoming dbus message this error refers to * @arg: Optional string appended to error message * Returns: a dbus error message * * Convenience function to create and return an UnknownError */ DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message, const char *arg) { /* * This function can be called as a result of a failure * within internal getter calls, which will call this function * with a NULL message parameter. However, dbus_message_new_error * looks very unkindly (i.e, abort()) on a NULL message, so * in this case, we should not call it. */ if (message == NULL) { wpa_printf(MSG_INFO, "dbus: wpas_dbus_error_unknown_error " "called with NULL message (arg=%s)", arg ? arg : "N/A"); return NULL; } return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR, arg); } /** * wpas_dbus_error_iface_unknown - Return a new invalid interface error message * @message: Pointer to incoming dbus message this error refers to * Returns: A dbus error message * * Convenience function to create and return an invalid interface error */ static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message) { return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN, "wpa_supplicant knows nothing about " "this interface."); } /** * wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message * @message: Pointer to incoming dbus message this error refers to * Returns: a dbus error message * * Convenience function to create and return an invalid network error */ static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message) { return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN, "There is no such a network in this " "interface."); } /** * wpas_dbus_error_invalid_args - Return a new InvalidArgs error message * @message: Pointer to incoming dbus message this error refers to * Returns: a dbus error message * * Convenience function to create and return an invalid options error */ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message, const char *arg) { DBusMessage *reply; reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_INVALID_ARGS, "Did not receive correct message " "arguments."); if (arg != NULL) dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID); return reply; } /** * wpas_dbus_error_scan_error - Return a new ScanError error message * @message: Pointer to incoming dbus message this error refers to * @error: Optional string to be used as the error message * Returns: a dbus error message * * Convenience function to create and return a scan error */ DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message, const char *error) { DBusMessage *reply; reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_SCAN_ERROR, error); return reply; } static const char *dont_quote[] = { "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap", "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path", "bssid", "scan_freq", "freq_list", NULL }; static dbus_bool_t should_quote_opt(const char *key) { int i = 0; while (dont_quote[i] != NULL) { if (os_strcmp(key, dont_quote[i]) == 0) return FALSE; i++; } return TRUE; } /** * get_iface_by_dbus_path - Get a new network interface * @global: Pointer to global data from wpa_supplicant_init() * @path: Pointer to a dbus object path representing an interface * Returns: Pointer to the interface or %NULL if not found */ static struct wpa_supplicant * get_iface_by_dbus_path( struct wpa_global *global, const char *path) { struct wpa_supplicant *wpa_s; for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { if (os_strcmp(wpa_s->dbus_new_path, path) == 0) return wpa_s; } return NULL; } /** * set_network_properties - Set properties of a configured network * @wpa_s: wpa_supplicant structure for a network interface * @ssid: wpa_ssid structure for a configured network * @iter: DBus message iterator containing dictionary of network * properties to set. * @error: On failure, an error describing the failure * Returns: TRUE if the request succeeds, FALSE if it failed * * Sets network configuration with parameters given id DBus dictionary */ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, DBusMessageIter *iter, DBusError *error) { struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; DBusMessageIter iter_dict; char *value = NULL; if (!wpa_dbus_dict_open_read(iter, &iter_dict, error)) return FALSE; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { size_t size = 50; int ret; if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; value = NULL; if (entry.type == DBUS_TYPE_ARRAY && entry.array_type == DBUS_TYPE_BYTE) { if (entry.array_len <= 0) goto error; size = entry.array_len * 2 + 1; value = os_zalloc(size); if (value == NULL) goto error; ret = wpa_snprintf_hex(value, size, (u8 *) entry.bytearray_value, entry.array_len); if (ret <= 0) goto error; } else if (entry.type == DBUS_TYPE_STRING) { if (should_quote_opt(entry.key)) { size = os_strlen(entry.str_value); if (size <= 0) goto error; size += 3; value = os_zalloc(size); if (value == NULL) goto error; ret = os_snprintf(value, size, "\"%s\"", entry.str_value); if (ret < 0 || (size_t) ret != (size - 1)) goto error; } else { value = os_strdup(entry.str_value); if (value == NULL) goto error; } } else if (entry.type == DBUS_TYPE_UINT32) { value = os_zalloc(size); if (value == NULL) goto error; ret = os_snprintf(value, size, "%u", entry.uint32_value); if (ret <= 0) goto error; } else if (entry.type == DBUS_TYPE_INT32) { value = os_zalloc(size); if (value == NULL) goto error; ret = os_snprintf(value, size, "%d", entry.int32_value); if (ret <= 0) goto error; } else goto error; if (wpa_config_set(ssid, entry.key, value, 0) < 0) goto error; if ((os_strcmp(entry.key, "psk") == 0 && value[0] == '"' && ssid->ssid_len) || (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) wpa_config_update_psk(ssid); else if (os_strcmp(entry.key, "priority") == 0) wpa_config_update_prio_list(wpa_s->conf); os_free(value); wpa_dbus_dict_entry_clear(&entry); } return TRUE; error: os_free(value); wpa_dbus_dict_entry_clear(&entry); dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, "invalid message format"); return FALSE; } /** * wpas_dbus_simple_property_getter - Get basic type property * @iter: Message iter to use when appending arguments * @type: DBus type of property (must be basic type) * @val: pointer to place holding property value * @error: On failure an error describing the failure * Returns: TRUE if the request was successful, FALSE if it failed * * Generic getter for basic type properties. Type is required to be basic. */ dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter, const int type, const void *val, DBusError *error) { DBusMessageIter variant_iter; if (!dbus_type_is_basic(type)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: given type is not basic", __func__); return FALSE; } if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, wpa_dbus_type_as_string(type), &variant_iter)) goto error; if (!dbus_message_iter_append_basic(&variant_iter, type, val)) goto error; if (!dbus_message_iter_close_container(iter, &variant_iter)) goto error; return TRUE; error: dbus_set_error(error, DBUS_ERROR_FAILED, "%s: error constructing reply", __func__); return FALSE; } /** * wpas_dbus_simple_property_setter - Set basic type property * @message: Pointer to incoming dbus message * @type: DBus type of property (must be basic type) * @val: pointer to place where value being set will be stored * Returns: TRUE if the request was successful, FALSE if it failed * * Generic setter for basic type properties. Type is required to be basic. */ dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter, DBusError *error, const int type, void *val) { DBusMessageIter variant_iter; if (!dbus_type_is_basic(type)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: given type is not basic", __func__); return FALSE; } /* Look at the new value */ dbus_message_iter_recurse(iter, &variant_iter); if (dbus_message_iter_get_arg_type(&variant_iter) != type) { dbus_set_error_const(error, DBUS_ERROR_FAILED, "wrong property type"); return FALSE; } dbus_message_iter_get_basic(&variant_iter, val); return TRUE; } /** * wpas_dbus_simple_array_property_getter - Get array type property * @iter: Pointer to incoming dbus message iterator * @type: DBus type of property array elements (must be basic type) * @array: pointer to array of elements to put into response message * @array_len: length of above array * @error: a pointer to an error to fill on failure * Returns: TRUE if the request succeeded, FALSE if it failed * * Generic getter for array type properties. Array elements type is * required to be basic. */ dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter, const int type, const void *array, size_t array_len, DBusError *error) { DBusMessageIter variant_iter, array_iter; char type_str[] = "a?"; /* ? will be replaced with subtype letter; */ const char *sub_type_str; size_t element_size, i; if (!dbus_type_is_basic(type)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: given type is not basic", __func__); return FALSE; } sub_type_str = wpa_dbus_type_as_string(type); type_str[1] = sub_type_str[0]; if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, type_str, &variant_iter)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to construct message 1", __func__); return FALSE; } if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, sub_type_str, &array_iter)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to construct message 2", __func__); return FALSE; } switch(type) { case DBUS_TYPE_BYTE: case DBUS_TYPE_BOOLEAN: element_size = 1; break; case DBUS_TYPE_INT16: case DBUS_TYPE_UINT16: element_size = sizeof(uint16_t); break; case DBUS_TYPE_INT32: case DBUS_TYPE_UINT32: element_size = sizeof(uint32_t); break; case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: element_size = sizeof(uint64_t); break; case DBUS_TYPE_DOUBLE: element_size = sizeof(double); break; case DBUS_TYPE_STRING: case DBUS_TYPE_OBJECT_PATH: element_size = sizeof(char *); break; default: dbus_set_error(error, DBUS_ERROR_FAILED, "%s: unknown element type %d", __func__, type); return FALSE; } for (i = 0; i < array_len; i++) { dbus_message_iter_append_basic(&array_iter, type, array + i * element_size); } if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to construct message 3", __func__); return FALSE; } if (!dbus_message_iter_close_container(iter, &variant_iter)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to construct message 4", __func__); return FALSE; } return TRUE; } /** * wpas_dbus_simple_array_array_property_getter - Get array array type property * @iter: Pointer to incoming dbus message iterator * @type: DBus type of property array elements (must be basic type) * @array: pointer to array of elements to put into response message * @array_len: length of above array * @error: a pointer to an error to fill on failure * Returns: TRUE if the request succeeded, FALSE if it failed * * Generic getter for array type properties. Array elements type is * required to be basic. */ dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter, const int type, struct wpabuf **array, size_t array_len, DBusError *error) { DBusMessageIter variant_iter, array_iter; char type_str[] = "aa?"; char inner_type_str[] = "a?"; const char *sub_type_str; size_t i; if (!dbus_type_is_basic(type)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: given type is not basic", __func__); return FALSE; } sub_type_str = wpa_dbus_type_as_string(type); type_str[2] = sub_type_str[0]; inner_type_str[1] = sub_type_str[0]; if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, type_str, &variant_iter)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to construct message 1", __func__); return FALSE; } if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, inner_type_str, &array_iter)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to construct message 2", __func__); return FALSE; } for (i = 0; i < array_len; i++) { wpa_dbus_dict_bin_array_add_element(&array_iter, wpabuf_head(array[i]), wpabuf_len(array[i])); } if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to close message 2", __func__); return FALSE; } if (!dbus_message_iter_close_container(iter, &variant_iter)) { dbus_set_error(error, DBUS_ERROR_FAILED, "%s: failed to close message 1", __func__); return FALSE; } return TRUE; } /** * wpas_dbus_handler_create_interface - Request registration of a network iface * @message: Pointer to incoming dbus message * @global: %wpa_supplicant global data structure * Returns: The object path of the new interface object, * or a dbus error message with more information * * Handler function for "CreateInterface" method call. Handles requests * by dbus clients to register a network interface that wpa_supplicant * will manage. */ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, struct wpa_global *global) { DBusMessageIter iter_dict; DBusMessage *reply = NULL; DBusMessageIter iter; struct wpa_dbus_dict_entry entry; char *driver = NULL; char *ifname = NULL; char *confname = NULL; char *bridge_ifname = NULL; dbus_message_iter_init(message, &iter); if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) goto error; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) goto error; if (!os_strcmp(entry.key, "Driver") && (entry.type == DBUS_TYPE_STRING)) { driver = os_strdup(entry.str_value); wpa_dbus_dict_entry_clear(&entry); if (driver == NULL) goto error; } else if (!os_strcmp(entry.key, "Ifname") && (entry.type == DBUS_TYPE_STRING)) { ifname = os_strdup(entry.str_value); wpa_dbus_dict_entry_clear(&entry); if (ifname == NULL) goto error; } else if (!os_strcmp(entry.key, "ConfigFile") && (entry.type == DBUS_TYPE_STRING)) { confname = os_strdup(entry.str_value); wpa_dbus_dict_entry_clear(&entry); if (confname == NULL) goto error; } else if (!os_strcmp(entry.key, "BridgeIfname") && (entry.type == DBUS_TYPE_STRING)) { bridge_ifname = os_strdup(entry.str_value); wpa_dbus_dict_entry_clear(&entry); if (bridge_ifname == NULL) goto error; } else { wpa_dbus_dict_entry_clear(&entry); goto error; } } if (ifname == NULL) goto error; /* Required Ifname argument missing */ /* * Try to get the wpa_supplicant record for this iface, return * an error if we already control it. */ if (wpa_supplicant_get_iface(global, ifname) != NULL) { reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_EXISTS, "wpa_supplicant already " "controls this interface."); } else { struct wpa_supplicant *wpa_s; struct wpa_interface iface; os_memset(&iface, 0, sizeof(iface)); iface.driver = driver; iface.ifname = ifname; iface.confname = confname; iface.bridge_ifname = bridge_ifname; /* Otherwise, have wpa_supplicant attach to it. */ if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) { const char *path = wpa_s->dbus_new_path; reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); } else { reply = wpas_dbus_error_unknown_error( message, "wpa_supplicant couldn't grab this " "interface."); } } out: os_free(driver); os_free(ifname); os_free(confname); os_free(bridge_ifname); return reply; error: reply = wpas_dbus_error_invalid_args(message, NULL); goto out; } /** * wpas_dbus_handler_remove_interface - Request deregistration of an interface * @message: Pointer to incoming dbus message * @global: wpa_supplicant global data structure * Returns: a dbus message containing a UINT32 indicating success (1) or * failure (0), or returns a dbus error message with more information * * Handler function for "removeInterface" method call. Handles requests * by dbus clients to deregister a network interface that wpa_supplicant * currently manages. */ DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message, struct wpa_global *global) { struct wpa_supplicant *wpa_s; char *path; DBusMessage *reply = NULL; dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); wpa_s = get_iface_by_dbus_path(global, path); if (wpa_s == NULL) reply = wpas_dbus_error_iface_unknown(message); else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) { reply = wpas_dbus_error_unknown_error( message, "wpa_supplicant couldn't remove this " "interface."); } return reply; } /** * wpas_dbus_handler_get_interface - Get the object path for an interface name * @message: Pointer to incoming dbus message * @global: %wpa_supplicant global data structure * Returns: The object path of the interface object, * or a dbus error message with more information * * Handler function for "getInterface" method call. */ DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message, struct wpa_global *global) { DBusMessage *reply = NULL; const char *ifname; const char *path; struct wpa_supplicant *wpa_s; dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname, DBUS_TYPE_INVALID); wpa_s = wpa_supplicant_get_iface(global, ifname); if (wpa_s == NULL) return wpas_dbus_error_iface_unknown(message); path = wpa_s->dbus_new_path; reply = dbus_message_new_method_return(message); if (reply == NULL) return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { dbus_message_unref(reply); return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); } return reply; } /** * wpas_dbus_getter_debug_level - Get debug level * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "DebugLevel" property. */ dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter, DBusError *error, void *user_data) { const char *str; int idx = wpa_debug_level; if (idx < 0) idx = 0; if (idx > 5) idx = 5; str = debug_strings[idx]; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str, error); } /** * wpas_dbus_getter_debug_timestamp - Get debug timestamp * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "DebugTimestamp" property. */ dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter, DBusError *error, void *user_data) { return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, &wpa_debug_timestamp, error); } /** * wpas_dbus_getter_debug_show_keys - Get debug show keys * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "DebugShowKeys" property. */ dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter, DBusError *error, void *user_data) { return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, &wpa_debug_show_keys, error); } /** * wpas_dbus_setter_debug_level - Set debug level * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Setter for "DebugLevel" property. */ dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_global *global = user_data; const char *str = NULL; int i, val = -1; if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, &str)) return FALSE; for (i = 0; debug_strings[i]; i++) if (os_strcmp(debug_strings[i], str) == 0) { val = i; break; } if (val < 0 || wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp, wpa_debug_show_keys)) { dbus_set_error_const(error, DBUS_ERROR_FAILED, "wrong debug " "level value"); return FALSE; } return TRUE; } /** * wpas_dbus_setter_debug_timestamp - Set debug timestamp * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Setter for "DebugTimestamp" property. */ dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_global *global = user_data; dbus_bool_t val; if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, &val)) return FALSE; wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0, wpa_debug_show_keys); return TRUE; } /** * wpas_dbus_setter_debug_show_keys - Set debug show keys * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Setter for "DebugShowKeys" property. */ dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_global *global = user_data; dbus_bool_t val; if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, &val)) return FALSE; wpa_supplicant_set_debug_params(global, wpa_debug_level, wpa_debug_timestamp, val ? 1 : 0); return TRUE; } /** * wpas_dbus_getter_interfaces - Request registered interfaces list * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "Interfaces" property. Handles requests * by dbus clients to return list of registered interfaces objects * paths */ dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_global *global = user_data; struct wpa_supplicant *wpa_s; const char **paths; unsigned int i = 0, num = 0; dbus_bool_t success; for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) num++; paths = os_calloc(num, sizeof(char *)); if (!paths) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) paths[i++] = wpa_s->dbus_new_path; success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_OBJECT_PATH, paths, num, error); os_free(paths); return success; } /** * wpas_dbus_getter_eap_methods - Request supported EAP methods list * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "EapMethods" property. Handles requests * by dbus clients to return list of strings with supported EAP methods */ dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter, DBusError *error, void *user_data) { char **eap_methods; size_t num_items = 0; dbus_bool_t success; eap_methods = eap_get_names_as_string_array(&num_items); if (!eap_methods) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_STRING, eap_methods, num_items, error); while (num_items) os_free(eap_methods[--num_items]); os_free(eap_methods); return success; } /** * wpas_dbus_getter_global_capabilities - Request supported global capabilities * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "Capabilities" property. Handles requests by dbus clients to * return a list of strings with supported capabilities like AP, RSN IBSS, * and P2P that are determined at compile time. */ dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter, DBusError *error, void *user_data) { const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL }; size_t num_items = 0; #ifdef CONFIG_AP capabilities[num_items++] = "ap"; #endif /* CONFIG_AP */ #ifdef CONFIG_IBSS_RSN capabilities[num_items++] = "ibss-rsn"; #endif /* CONFIG_IBSS_RSN */ #ifdef CONFIG_P2P capabilities[num_items++] = "p2p"; #endif /* CONFIG_P2P */ #ifdef CONFIG_INTERWORKING capabilities[num_items++] = "interworking"; #endif /* CONFIG_INTERWORKING */ return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_STRING, capabilities, num_items, error); } static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var, char **type, DBusMessage **reply) { if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "Type must be a string"); *reply = wpas_dbus_error_invalid_args( message, "Wrong Type value type. String required"); return -1; } dbus_message_iter_get_basic(var, type); return 0; } static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var, struct wpa_driver_scan_params *params, DBusMessage **reply) { struct wpa_driver_scan_ssid *ssids = params->ssids; size_t ssids_num = 0; u8 *ssid; DBusMessageIter array_iter, sub_array_iter; char *val; int len; if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids " "must be an array of arrays of bytes"); *reply = wpas_dbus_error_invalid_args( message, "Wrong SSIDs value type. Array of arrays of " "bytes required"); return -1; } dbus_message_iter_recurse(var, &array_iter); if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids " "must be an array of arrays of bytes"); *reply = wpas_dbus_error_invalid_args( message, "Wrong SSIDs value type. Array of arrays of " "bytes required"); return -1; } while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) { if (ssids_num >= WPAS_MAX_SCAN_SSIDS) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "Too many ssids specified on scan dbus " "call"); *reply = wpas_dbus_error_invalid_args( message, "Too many ssids specified. Specify " "at most four"); return -1; } dbus_message_iter_recurse(&array_iter, &sub_array_iter); dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len); if (len > MAX_SSID_LEN) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "SSID too long (len=%d max_len=%d)", len, MAX_SSID_LEN); *reply = wpas_dbus_error_invalid_args( message, "Invalid SSID: too long"); return -1; } if (len != 0) { ssid = os_malloc(len); if (ssid == NULL) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "out of memory. Cannot allocate " "memory for SSID"); *reply = dbus_message_new_error( message, DBUS_ERROR_NO_MEMORY, NULL); return -1; } os_memcpy(ssid, val, len); } else { /* Allow zero-length SSIDs */ ssid = NULL; } ssids[ssids_num].ssid = ssid; ssids[ssids_num].ssid_len = len; dbus_message_iter_next(&array_iter); ssids_num++; } params->num_ssids = ssids_num; return 0; } static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var, struct wpa_driver_scan_params *params, DBusMessage **reply) { u8 *ies = NULL, *nies; int ies_len = 0; DBusMessageIter array_iter, sub_array_iter; char *val; int len; if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must " "be an array of arrays of bytes"); *reply = wpas_dbus_error_invalid_args( message, "Wrong IEs value type. Array of arrays of " "bytes required"); return -1; } dbus_message_iter_recurse(var, &array_iter); if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must " "be an array of arrays of bytes"); *reply = wpas_dbus_error_invalid_args( message, "Wrong IEs value type. Array required"); return -1; } while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) { dbus_message_iter_recurse(&array_iter, &sub_array_iter); dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len); if (len == 0) { dbus_message_iter_next(&array_iter); continue; } nies = os_realloc(ies, ies_len + len); if (nies == NULL) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "out of memory. Cannot allocate memory for " "IE"); os_free(ies); *reply = dbus_message_new_error( message, DBUS_ERROR_NO_MEMORY, NULL); return -1; } ies = nies; os_memcpy(ies + ies_len, val, len); ies_len += len; dbus_message_iter_next(&array_iter); } params->extra_ies = ies; params->extra_ies_len = ies_len; return 0; } static int wpas_dbus_get_scan_channels(DBusMessage *message, DBusMessageIter *var, struct wpa_driver_scan_params *params, DBusMessage **reply) { DBusMessageIter array_iter, sub_array_iter; int *freqs = NULL, *nfreqs; int freqs_num = 0; if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "Channels must be an array of structs"); *reply = wpas_dbus_error_invalid_args( message, "Wrong Channels value type. Array of structs " "required"); return -1; } dbus_message_iter_recurse(var, &array_iter); if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: Channels must be an " "array of structs"); *reply = wpas_dbus_error_invalid_args( message, "Wrong Channels value type. Array of structs " "required"); return -1; } while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT) { int freq, width; dbus_message_iter_recurse(&array_iter, &sub_array_iter); if (dbus_message_iter_get_arg_type(&sub_array_iter) != DBUS_TYPE_UINT32) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "Channel must by specified by struct of " "two UINT32s %c", dbus_message_iter_get_arg_type( &sub_array_iter)); *reply = wpas_dbus_error_invalid_args( message, "Wrong Channel struct. Two UINT32s " "required"); os_free(freqs); return -1; } dbus_message_iter_get_basic(&sub_array_iter, &freq); if (!dbus_message_iter_next(&sub_array_iter) || dbus_message_iter_get_arg_type(&sub_array_iter) != DBUS_TYPE_UINT32) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "Channel must by specified by struct of " "two UINT32s"); *reply = wpas_dbus_error_invalid_args( message, "Wrong Channel struct. Two UINT32s required"); os_free(freqs); return -1; } dbus_message_iter_get_basic(&sub_array_iter, &width); #define FREQS_ALLOC_CHUNK 32 if (freqs_num % FREQS_ALLOC_CHUNK == 0) { nfreqs = os_realloc_array( freqs, freqs_num + FREQS_ALLOC_CHUNK, sizeof(int)); if (nfreqs == NULL) os_free(freqs); freqs = nfreqs; } if (freqs == NULL) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "out of memory. can't allocate memory for " "freqs"); *reply = dbus_message_new_error( message, DBUS_ERROR_NO_MEMORY, NULL); return -1; } freqs[freqs_num] = freq; freqs_num++; dbus_message_iter_next(&array_iter); } nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int)); if (nfreqs == NULL) os_free(freqs); freqs = nfreqs; if (freqs == NULL) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "out of memory. Can't allocate memory for freqs"); *reply = dbus_message_new_error( message, DBUS_ERROR_NO_MEMORY, NULL); return -1; } freqs[freqs_num] = 0; params->freqs = freqs; return 0; } static int wpas_dbus_get_scan_allow_roam(DBusMessage *message, DBusMessageIter *var, dbus_bool_t *allow, DBusMessage **reply) { if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "Type must be a boolean"); *reply = wpas_dbus_error_invalid_args( message, "Wrong Type value type. Boolean required"); return -1; } dbus_message_iter_get_basic(var, allow); return 0; } /** * wpas_dbus_handler_scan - Request a wireless scan on an interface * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NULL indicating success or DBus error message on failure * * Handler function for "Scan" method call of a network device. Requests * that wpa_supplicant perform a wireless scan as soon as possible * on a particular wireless interface. */ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; DBusMessageIter iter, dict_iter, entry_iter, variant_iter; char *key = NULL, *type = NULL; struct wpa_driver_scan_params params; size_t i; dbus_bool_t allow_roam = 1; os_memset(¶ms, 0, sizeof(params)); dbus_message_iter_init(message, &iter); dbus_message_iter_recurse(&iter, &dict_iter); while (dbus_message_iter_get_arg_type(&dict_iter) == DBUS_TYPE_DICT_ENTRY) { dbus_message_iter_recurse(&dict_iter, &entry_iter); dbus_message_iter_get_basic(&entry_iter, &key); dbus_message_iter_next(&entry_iter); dbus_message_iter_recurse(&entry_iter, &variant_iter); if (os_strcmp(key, "Type") == 0) { if (wpas_dbus_get_scan_type(message, &variant_iter, &type, &reply) < 0) goto out; } else if (os_strcmp(key, "SSIDs") == 0) { if (wpas_dbus_get_scan_ssids(message, &variant_iter, ¶ms, &reply) < 0) goto out; } else if (os_strcmp(key, "IEs") == 0) { if (wpas_dbus_get_scan_ies(message, &variant_iter, ¶ms, &reply) < 0) goto out; } else if (os_strcmp(key, "Channels") == 0) { if (wpas_dbus_get_scan_channels(message, &variant_iter, ¶ms, &reply) < 0) goto out; } else if (os_strcmp(key, "AllowRoam") == 0) { if (wpas_dbus_get_scan_allow_roam(message, &variant_iter, &allow_roam, &reply) < 0) goto out; } else { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "Unknown argument %s", key); reply = wpas_dbus_error_invalid_args(message, key); goto out; } dbus_message_iter_next(&dict_iter); } if (!type) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "Scan type not specified"); reply = wpas_dbus_error_invalid_args(message, key); goto out; } if (!os_strcmp(type, "passive")) { if (params.num_ssids || params.extra_ies_len) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "SSIDs or IEs specified for passive scan."); reply = wpas_dbus_error_invalid_args( message, "You can specify only Channels in " "passive scan"); goto out; } else if (params.freqs && params.freqs[0]) { if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) { reply = wpas_dbus_error_scan_error( message, "Scan request rejected"); } } else { wpa_s->scan_req = MANUAL_SCAN_REQ; wpa_supplicant_req_scan(wpa_s, 0, 0); } } else if (!os_strcmp(type, "active")) { if (!params.num_ssids) { /* Add wildcard ssid */ params.num_ssids++; } #ifdef CONFIG_AUTOSCAN autoscan_deinit(wpa_s); #endif /* CONFIG_AUTOSCAN */ if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) { reply = wpas_dbus_error_scan_error( message, "Scan request rejected"); } } else { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " "Unknown scan type: %s", type); reply = wpas_dbus_error_invalid_args(message, "Wrong scan type"); goto out; } if (!allow_roam) wpa_s->scan_res_handler = scan_only_handler; out: for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++) os_free((u8 *) params.ssids[i].ssid); os_free((u8 *) params.extra_ies); os_free(params.freqs); return reply; } /* * wpas_dbus_handler_disconnect - Terminate the current connection * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NotConnected DBus error message if already not connected * or NULL otherwise. * * Handler function for "Disconnect" method call of network interface. */ DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message, struct wpa_supplicant *wpa_s) { if (wpa_s->current_ssid != NULL) { wpa_s->disconnected = 1; wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); return NULL; } return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED, "This interface is not connected"); } /** * wpas_dbus_new_iface_add_network - Add a new configured network * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A dbus message containing the object path of the new network * * Handler function for "AddNetwork" method call of a network interface. */ DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; DBusMessageIter iter; struct wpa_ssid *ssid = NULL; char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; DBusError error; dbus_message_iter_init(message, &iter); ssid = wpa_config_add_network(wpa_s->conf); if (ssid == NULL) { wpa_printf(MSG_ERROR, "wpas_dbus_handler_add_network[dbus]: " "can't add new interface."); reply = wpas_dbus_error_unknown_error( message, "wpa_supplicant could not add " "a network on this interface."); goto err; } wpas_notify_network_added(wpa_s, ssid); ssid->disabled = 1; wpa_config_set_network_defaults(ssid); dbus_error_init(&error); if (!set_network_properties(wpa_s, ssid, &iter, &error)) { wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:" "control interface couldn't set network " "properties"); reply = wpas_dbus_reply_new_from_error(message, &error, DBUS_ERROR_INVALID_ARGS, "Failed to add network"); dbus_error_free(&error); goto err; } /* Construct the object path for this network. */ os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", wpa_s->dbus_new_path, ssid->id); reply = dbus_message_new_method_return(message); if (reply == NULL) { reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); goto err; } if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { dbus_message_unref(reply); reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); goto err; } return reply; err: if (ssid) { wpas_notify_network_removed(wpa_s, ssid); wpa_config_remove_network(wpa_s->conf, ssid->id); } return reply; } /** * wpas_dbus_handler_reassociate - Reassociate * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: InterfaceDisabled DBus error message if disabled * or NULL otherwise. * * Handler function for "Reassociate" method call of network interface. */ DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message, struct wpa_supplicant *wpa_s) { if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) { wpas_request_connection(wpa_s); return NULL; } return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_DISABLED, "This interface is disabled"); } /** * wpas_dbus_handler_reattach - Reattach to current AP * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NotConnected DBus error message if not connected * or NULL otherwise. * * Handler function for "Reattach" method call of network interface. */ DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message, struct wpa_supplicant *wpa_s) { if (wpa_s->current_ssid != NULL) { wpa_s->reattach = 1; wpas_request_connection(wpa_s); return NULL; } return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED, "This interface is not connected"); } /** * wpas_dbus_handler_remove_network - Remove a configured network * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NULL on success or dbus error on failure * * Handler function for "RemoveNetwork" method call of a network interface. */ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; const char *op; char *iface = NULL, *net_id = NULL; int id; struct wpa_ssid *ssid; int was_disabled; dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, DBUS_TYPE_INVALID); /* Extract the network ID and ensure the network */ /* is actually a child of this interface */ iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL); if (iface == NULL || net_id == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { reply = wpas_dbus_error_invalid_args(message, op); goto out; } errno = 0; id = strtoul(net_id, NULL, 10); if (errno != 0) { reply = wpas_dbus_error_invalid_args(message, op); goto out; } ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { reply = wpas_dbus_error_network_unknown(message); goto out; } was_disabled = ssid->disabled; wpas_notify_network_removed(wpa_s, ssid); if (ssid == wpa_s->current_ssid) wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); else if (!was_disabled && wpa_s->sched_scanning) { wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove " "network from filters"); wpa_supplicant_cancel_sched_scan(wpa_s); wpa_supplicant_req_scan(wpa_s, 0, 0); } if (wpa_config_remove_network(wpa_s->conf, id) < 0) { wpa_printf(MSG_ERROR, "wpas_dbus_handler_remove_network[dbus]: " "error occurred when removing network %d", id); reply = wpas_dbus_error_unknown_error( message, "error removing the specified network on " "this interface."); goto out; } out: os_free(iface); os_free(net_id); return reply; } static void remove_network(void *arg, struct wpa_ssid *ssid) { struct wpa_supplicant *wpa_s = arg; wpas_notify_network_removed(wpa_s, ssid); if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) { wpa_printf(MSG_ERROR, "wpas_dbus_handler_remove_all_networks[dbus]: " "error occurred when removing network %d", ssid->id); return; } if (ssid == wpa_s->current_ssid) wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); } /** * wpas_dbus_handler_remove_all_networks - Remove all configured networks * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NULL on success or dbus error on failure * * Handler function for "RemoveAllNetworks" method call of a network interface. */ DBusMessage * wpas_dbus_handler_remove_all_networks( DBusMessage *message, struct wpa_supplicant *wpa_s) { if (wpa_s->sched_scanning) wpa_supplicant_cancel_sched_scan(wpa_s); /* NB: could check for failure and return an error */ wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s); return NULL; } /** * wpas_dbus_handler_select_network - Attempt association with a network * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NULL on success or dbus error on failure * * Handler function for "SelectNetwork" method call of network interface. */ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; const char *op; char *iface = NULL, *net_id = NULL; int id; struct wpa_ssid *ssid; dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, DBUS_TYPE_INVALID); /* Extract the network ID and ensure the network */ /* is actually a child of this interface */ iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL); if (iface == NULL || net_id == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { reply = wpas_dbus_error_invalid_args(message, op); goto out; } errno = 0; id = strtoul(net_id, NULL, 10); if (errno != 0) { reply = wpas_dbus_error_invalid_args(message, op); goto out; } ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { reply = wpas_dbus_error_network_unknown(message); goto out; } /* Finally, associate with the network */ wpa_supplicant_select_network(wpa_s, ssid); out: os_free(iface); os_free(net_id); return reply; } /** * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NULL on success or dbus error on failure * * Handler function for "NetworkReply" method call of network interface. */ DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message, struct wpa_supplicant *wpa_s) { #ifdef IEEE8021X_EAPOL DBusMessage *reply = NULL; const char *op, *field, *value; char *iface = NULL, *net_id = NULL; int id; struct wpa_ssid *ssid; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, DBUS_TYPE_STRING, &field, DBUS_TYPE_STRING, &value, DBUS_TYPE_INVALID)) return wpas_dbus_error_invalid_args(message, NULL); /* Extract the network ID and ensure the network */ /* is actually a child of this interface */ iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL); if (iface == NULL || net_id == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { reply = wpas_dbus_error_invalid_args(message, op); goto out; } errno = 0; id = strtoul(net_id, NULL, 10); if (errno != 0) { reply = wpas_dbus_error_invalid_args(message, net_id); goto out; } ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) { reply = wpas_dbus_error_network_unknown(message); goto out; } if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, field, value) < 0) reply = wpas_dbus_error_invalid_args(message, field); else { /* Tell EAP to retry immediately */ eapol_sm_notify_ctrl_response(wpa_s->eapol); } out: os_free(iface); os_free(net_id); return reply; #else /* IEEE8021X_EAPOL */ wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included"); return wpas_dbus_error_unknown_error(message, "802.1X not included"); #endif /* IEEE8021X_EAPOL */ } #ifndef CONFIG_NO_CONFIG_BLOBS /** * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates) * @message: Pointer to incoming dbus message * @wpa_s: %wpa_supplicant data structure * Returns: A dbus message containing an error on failure or NULL on success * * Asks wpa_supplicant to internally store a binary blobs. */ DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; DBusMessageIter iter, array_iter; char *blob_name; u8 *blob_data; int blob_len; struct wpa_config_blob *blob = NULL; dbus_message_iter_init(message, &iter); dbus_message_iter_get_basic(&iter, &blob_name); if (wpa_config_get_blob(wpa_s->conf, blob_name)) { return dbus_message_new_error(message, WPAS_DBUS_ERROR_BLOB_EXISTS, NULL); } dbus_message_iter_next(&iter); dbus_message_iter_recurse(&iter, &array_iter); dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len); blob = os_zalloc(sizeof(*blob)); if (!blob) { reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); goto err; } blob->data = os_malloc(blob_len); if (!blob->data) { reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); goto err; } os_memcpy(blob->data, blob_data, blob_len); blob->len = blob_len; blob->name = os_strdup(blob_name); if (!blob->name) { reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); goto err; } wpa_config_set_blob(wpa_s->conf, blob); wpas_notify_blob_added(wpa_s, blob->name); return reply; err: if (blob) { os_free(blob->name); os_free(blob->data); os_free(blob); } return reply; } /** * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates) * @message: Pointer to incoming dbus message * @wpa_s: %wpa_supplicant data structure * Returns: A dbus message containing array of bytes (blob) * * Gets one wpa_supplicant's binary blobs. */ DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; DBusMessageIter iter, array_iter; char *blob_name; const struct wpa_config_blob *blob; dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name, DBUS_TYPE_INVALID); blob = wpa_config_get_blob(wpa_s->conf, blob_name); if (!blob) { return dbus_message_new_error(message, WPAS_DBUS_ERROR_BLOB_UNKNOWN, "Blob id not set"); } reply = dbus_message_new_method_return(message); if (!reply) { reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); goto out; } dbus_message_iter_init_append(reply, &iter); if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &array_iter)) { dbus_message_unref(reply); reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); goto out; } if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, &(blob->data), blob->len)) { dbus_message_unref(reply); reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); goto out; } if (!dbus_message_iter_close_container(&iter, &array_iter)) { dbus_message_unref(reply); reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); goto out; } out: return reply; } /** * wpas_remove_handler_remove_blob - Remove named binary blob * @message: Pointer to incoming dbus message * @wpa_s: %wpa_supplicant data structure * Returns: NULL on success or dbus error * * Asks wpa_supplicant to internally remove a binary blobs. */ DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; char *blob_name; dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name, DBUS_TYPE_INVALID); if (wpa_config_remove_blob(wpa_s->conf, blob_name)) { return dbus_message_new_error(message, WPAS_DBUS_ERROR_BLOB_UNKNOWN, "Blob id not set"); } wpas_notify_blob_removed(wpa_s, blob_name); return reply; } #endif /* CONFIG_NO_CONFIG_BLOBS */ /* * wpas_dbus_handler_flush_bss - Flush the BSS cache * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NULL * * Handler function for "FlushBSS" method call of network interface. */ DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message, struct wpa_supplicant *wpa_s) { dbus_uint32_t age; dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age, DBUS_TYPE_INVALID); if (age == 0) wpa_bss_flush(wpa_s); else wpa_bss_flush_by_age(wpa_s, age); return NULL; } #ifdef CONFIG_AUTOSCAN /** * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NULL * * Handler function for "AutoScan" method call of network interface. */ DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; enum wpa_states state = wpa_s->wpa_state; char *arg; dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID); if (arg != NULL && os_strlen(arg) > 0) { char *tmp; tmp = os_strdup(arg); if (tmp == NULL) { reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); } else { os_free(wpa_s->conf->autoscan); wpa_s->conf->autoscan = tmp; if (state == WPA_DISCONNECTED || state == WPA_INACTIVE) autoscan_init(wpa_s, 1); else if (state == WPA_SCANNING) wpa_supplicant_reinit_autoscan(wpa_s); } } else if (arg != NULL && os_strlen(arg) == 0) { os_free(wpa_s->conf->autoscan); wpa_s->conf->autoscan = NULL; autoscan_deinit(wpa_s); } else reply = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, NULL); return reply; } #endif /* CONFIG_AUTOSCAN */ /* * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NULL * * Handler function for "EAPLogoff" method call of network interface. */ DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message, struct wpa_supplicant *wpa_s) { eapol_sm_notify_logoff(wpa_s->eapol, TRUE); return NULL; } /* * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NULL * * Handler function for "EAPLogin" method call of network interface. */ DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message, struct wpa_supplicant *wpa_s) { eapol_sm_notify_logoff(wpa_s->eapol, FALSE); return NULL; } #ifdef CONFIG_TDLS static int get_peer_hwaddr_helper(DBusMessage *message, const char *func_name, u8 *peer_address, DBusMessage **error) { const char *peer_string; *error = NULL; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &peer_string, DBUS_TYPE_INVALID)) { *error = wpas_dbus_error_invalid_args(message, NULL); return -1; } if (hwaddr_aton(peer_string, peer_address)) { wpa_printf(MSG_DEBUG, "%s: invalid address '%s'", func_name, peer_string); *error = wpas_dbus_error_invalid_args( message, "Invalid hardware address format"); return -1; } return 0; } /* * wpas_dbus_handler_tdls_discover - Discover TDLS peer * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NULL indicating success or DBus error message on failure * * Handler function for "TDLSDiscover" method call of network interface. */ DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message, struct wpa_supplicant *wpa_s) { u8 peer[ETH_ALEN]; DBusMessage *error_reply; int ret; if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0) return error_reply; wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer)); if (wpa_tdls_is_external_setup(wpa_s->wpa)) ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer); else ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer); if (ret) { return wpas_dbus_error_unknown_error( message, "error performing TDLS discovery"); } return NULL; } /* * wpas_dbus_handler_tdls_setup - Setup TDLS session * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NULL indicating success or DBus error message on failure * * Handler function for "TDLSSetup" method call of network interface. */ DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message, struct wpa_supplicant *wpa_s) { u8 peer[ETH_ALEN]; DBusMessage *error_reply; int ret; if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0) return error_reply; wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer)); wpa_tdls_remove(wpa_s->wpa, peer); if (wpa_tdls_is_external_setup(wpa_s->wpa)) ret = wpa_tdls_start(wpa_s->wpa, peer); else ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer); if (ret) { return wpas_dbus_error_unknown_error( message, "error performing TDLS setup"); } return NULL; } /* * wpas_dbus_handler_tdls_status - Return TDLS session status * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: A string representing the state of the link to this TDLS peer * * Handler function for "TDLSStatus" method call of network interface. */ DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message, struct wpa_supplicant *wpa_s) { u8 peer[ETH_ALEN]; DBusMessage *reply; const char *tdls_status; if (get_peer_hwaddr_helper(message, __func__, peer, &reply) < 0) return reply; wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer)); tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer); reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_STRING, &tdls_status, DBUS_TYPE_INVALID); return reply; } /* * wpas_dbus_handler_tdls_teardown - Teardown TDLS session * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * Returns: NULL indicating success or DBus error message on failure * * Handler function for "TDLSTeardown" method call of network interface. */ DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message, struct wpa_supplicant *wpa_s) { u8 peer[ETH_ALEN]; DBusMessage *error_reply; int ret; if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0) return error_reply; wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer)); if (wpa_tdls_is_external_setup(wpa_s->wpa)) ret = wpa_tdls_teardown_link( wpa_s->wpa, peer, WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); else ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer); if (ret) { return wpas_dbus_error_unknown_error( message, "error performing TDLS teardown"); } return NULL; } #endif /* CONFIG_TDLS */ /** * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path * @message: Pointer to incoming dbus message * @wpa_s: %wpa_supplicant data structure * Returns: A dbus message containing an error on failure or NULL on success * * Sets the PKCS #11 engine and module path. */ DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path( DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessageIter iter; char *value = NULL; char *pkcs11_engine_path = NULL; char *pkcs11_module_path = NULL; dbus_message_iter_init(message, &iter); dbus_message_iter_get_basic(&iter, &value); if (value == NULL) { return dbus_message_new_error( message, DBUS_ERROR_INVALID_ARGS, "Invalid pkcs11_engine_path argument"); } /* Empty path defaults to NULL */ if (os_strlen(value)) pkcs11_engine_path = value; dbus_message_iter_next(&iter); dbus_message_iter_get_basic(&iter, &value); if (value == NULL) { os_free(pkcs11_engine_path); return dbus_message_new_error( message, DBUS_ERROR_INVALID_ARGS, "Invalid pkcs11_module_path argument"); } /* Empty path defaults to NULL */ if (os_strlen(value)) pkcs11_module_path = value; if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path, pkcs11_module_path)) return dbus_message_new_error( message, DBUS_ERROR_FAILED, "Reinit of the EAPOL state machine with the new PKCS " "#11 engine and module path failed."); wpa_dbus_mark_property_changed( wpa_s->global->dbus, wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath"); wpa_dbus_mark_property_changed( wpa_s->global->dbus, wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath"); return NULL; } /** * wpas_dbus_getter_capabilities - Return interface capabilities * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "Capabilities" property of an interface. */ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; struct wpa_driver_capa capa; int res; DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array, variant_iter; const char *scans[] = { "active", "passive", "ssid" }; if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}", &variant_iter)) goto nomem; if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) goto nomem; res = wpa_drv_get_capa(wpa_s, &capa); /***** pairwise cipher */ if (res < 0) { const char *args[] = {"ccmp", "tkip", "none"}; if (!wpa_dbus_dict_append_string_array( &iter_dict, "Pairwise", args, ARRAY_SIZE(args))) goto nomem; } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise", &iter_dict_entry, &iter_dict_val, &iter_array)) goto nomem; if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "ccmp-256")) goto nomem; } if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "gcmp-256")) goto nomem; } if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "ccmp")) goto nomem; } if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "gcmp")) goto nomem; } if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "tkip")) goto nomem; } if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "none")) goto nomem; } if (!wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) goto nomem; } /***** group cipher */ if (res < 0) { const char *args[] = { "ccmp", "tkip", "wep104", "wep40" }; if (!wpa_dbus_dict_append_string_array( &iter_dict, "Group", args, ARRAY_SIZE(args))) goto nomem; } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group", &iter_dict_entry, &iter_dict_val, &iter_array)) goto nomem; if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "ccmp-256")) goto nomem; } if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "gcmp-256")) goto nomem; } if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "ccmp")) goto nomem; } if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "gcmp")) goto nomem; } if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "tkip")) goto nomem; } if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "wep104")) goto nomem; } if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "wep40")) goto nomem; } if (!wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) goto nomem; } /***** key management */ if (res < 0) { const char *args[] = { "wpa-psk", "wpa-eap", "ieee8021x", "wpa-none", #ifdef CONFIG_WPS "wps", #endif /* CONFIG_WPS */ "none" }; if (!wpa_dbus_dict_append_string_array( &iter_dict, "KeyMgmt", args, ARRAY_SIZE(args))) goto nomem; } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt", &iter_dict_entry, &iter_dict_val, &iter_array)) goto nomem; if (!wpa_dbus_dict_string_array_add_element(&iter_array, "none")) goto nomem; if (!wpa_dbus_dict_string_array_add_element(&iter_array, "ieee8021x")) goto nomem; if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "wpa-eap")) goto nomem; if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) if (!wpa_dbus_dict_string_array_add_element( &iter_array, "wpa-ft-eap")) goto nomem; /* TODO: Ensure that driver actually supports sha256 encryption. */ #ifdef CONFIG_IEEE80211W if (!wpa_dbus_dict_string_array_add_element( &iter_array, "wpa-eap-sha256")) goto nomem; #endif /* CONFIG_IEEE80211W */ } if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "wpa-psk")) goto nomem; if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) if (!wpa_dbus_dict_string_array_add_element( &iter_array, "wpa-ft-psk")) goto nomem; /* TODO: Ensure that driver actually supports sha256 encryption. */ #ifdef CONFIG_IEEE80211W if (!wpa_dbus_dict_string_array_add_element( &iter_array, "wpa-psk-sha256")) goto nomem; #endif /* CONFIG_IEEE80211W */ } if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "wpa-none")) goto nomem; } #ifdef CONFIG_WPS if (!wpa_dbus_dict_string_array_add_element(&iter_array, "wps")) goto nomem; #endif /* CONFIG_WPS */ if (!wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) goto nomem; } /***** WPA protocol */ if (res < 0) { const char *args[] = { "rsn", "wpa" }; if (!wpa_dbus_dict_append_string_array( &iter_dict, "Protocol", args, ARRAY_SIZE(args))) goto nomem; } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol", &iter_dict_entry, &iter_dict_val, &iter_array)) goto nomem; if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "rsn")) goto nomem; } if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "wpa")) goto nomem; } if (!wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) goto nomem; } /***** auth alg */ if (res < 0) { const char *args[] = { "open", "shared", "leap" }; if (!wpa_dbus_dict_append_string_array( &iter_dict, "AuthAlg", args, ARRAY_SIZE(args))) goto nomem; } else { if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg", &iter_dict_entry, &iter_dict_val, &iter_array)) goto nomem; if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "open")) goto nomem; } if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "shared")) goto nomem; } if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "leap")) goto nomem; } if (!wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) goto nomem; } /***** Scan */ if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans, ARRAY_SIZE(scans))) goto nomem; /***** Modes */ if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes", &iter_dict_entry, &iter_dict_val, &iter_array)) goto nomem; if (!wpa_dbus_dict_string_array_add_element( &iter_array, "infrastructure")) goto nomem; if (!wpa_dbus_dict_string_array_add_element( &iter_array, "ad-hoc")) goto nomem; if (res >= 0) { if (capa.flags & (WPA_DRIVER_FLAGS_AP)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "ap")) goto nomem; } if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "p2p")) goto nomem; } } if (!wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, &iter_array)) goto nomem; /***** Modes end */ if (res >= 0) { dbus_int32_t max_scan_ssid = capa.max_scan_ssids; if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID", max_scan_ssid)) goto nomem; } if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict)) goto nomem; if (!dbus_message_iter_close_container(iter, &variant_iter)) goto nomem; return TRUE; nomem: dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } /** * wpas_dbus_getter_state - Get interface state * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "State" property. */ dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *str_state; char *state_ls, *tmp; dbus_bool_t success = FALSE; str_state = wpa_supplicant_state_txt(wpa_s->wpa_state); /* make state string lowercase to fit new DBus API convention */ state_ls = tmp = os_strdup(str_state); if (!tmp) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } while (*tmp) { *tmp = tolower(*tmp); tmp++; } success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &state_ls, error); os_free(state_ls); return success; } /** * wpas_dbus_new_iface_get_scanning - Get interface scanning state * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "scanning" property. */ dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, &scanning, error); } /** * wpas_dbus_getter_ap_scan - Control roaming mode * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter function for "ApScan" property. */ dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; dbus_uint32_t ap_scan = wpa_s->conf->ap_scan; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &ap_scan, error); } /** * wpas_dbus_setter_ap_scan - Control roaming mode * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Setter function for "ApScan" property. */ dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; dbus_uint32_t ap_scan; if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, &ap_scan)) return FALSE; if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) { dbus_set_error_const(error, DBUS_ERROR_FAILED, "ap_scan must be 0, 1, or 2"); return FALSE; } return TRUE; } /** * wpas_dbus_getter_fast_reauth - Control fast * reauthentication (TLS session resumption) * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter function for "FastReauth" property. */ dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, &fast_reauth, error); } /** * wpas_dbus_setter_fast_reauth - Control fast * reauthentication (TLS session resumption) * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Setter function for "FastReauth" property. */ dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; dbus_bool_t fast_reauth; if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, &fast_reauth)) return FALSE; wpa_s->conf->fast_reauth = fast_reauth; return TRUE; } /** * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "DisconnectReason" property. The reason is negative if it is * locally generated. */ dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; dbus_int32_t reason = wpa_s->disconnect_reason; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, &reason, error); } /** * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter function for "BSSExpireAge" property. */ dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &expire_age, error); } /** * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Setter function for "BSSExpireAge" property. */ dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; dbus_uint32_t expire_age; if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, &expire_age)) return FALSE; if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) { dbus_set_error_const(error, DBUS_ERROR_FAILED, "BSSExpireAge must be >= 10"); return FALSE; } return TRUE; } /** * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter function for "BSSExpireCount" property. */ dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &expire_count, error); } /** * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Setter function for "BSSExpireCount" property. */ dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; dbus_uint32_t expire_count; if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, &expire_count)) return FALSE; if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) { dbus_set_error_const(error, DBUS_ERROR_FAILED, "BSSExpireCount must be > 0"); return FALSE; } return TRUE; } /** * wpas_dbus_getter_country - Control country code * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter function for "Country" property. */ dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char country[3]; char *str = country; country[0] = wpa_s->conf->country[0]; country[1] = wpa_s->conf->country[1]; country[2] = '\0'; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str, error); } /** * wpas_dbus_setter_country - Control country code * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Setter function for "Country" property. */ dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *country; if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, &country)) return FALSE; if (!country[0] || !country[1]) { dbus_set_error_const(error, DBUS_ERROR_FAILED, "invalid country code"); return FALSE; } if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) { wpa_printf(MSG_DEBUG, "Failed to set country"); dbus_set_error_const(error, DBUS_ERROR_FAILED, "failed to set country code"); return FALSE; } wpa_s->conf->country[0] = country[0]; wpa_s->conf->country[1] = country[1]; return TRUE; } /** * wpas_dbus_getter_scan_interval - Get scan interval * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter function for "ScanInterval" property. */ dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; dbus_int32_t scan_interval = wpa_s->scan_interval; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, &scan_interval, error); } /** * wpas_dbus_setter_scan_interval - Control scan interval * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Setter function for "ScanInterval" property. */ dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; dbus_int32_t scan_interval; if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32, &scan_interval)) return FALSE; if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) { dbus_set_error_const(error, DBUS_ERROR_FAILED, "scan_interval must be >= 0"); return FALSE; } return TRUE; } /** * wpas_dbus_getter_ifname - Get interface name * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "Ifname" property. */ dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *ifname = wpa_s->ifname; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &ifname, error); } /** * wpas_dbus_getter_driver - Get interface name * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "Driver" property. */ dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *driver; if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) { wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: " "wpa_s has no driver set"); dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set", __func__); return FALSE; } driver = wpa_s->driver->name; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &driver, error); } /** * wpas_dbus_getter_current_bss - Get current bss object path * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "CurrentBSS" property. */ dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf; if (wpa_s->current_bss) os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", wpa_s->dbus_new_path, wpa_s->current_bss->id); else os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, &bss_obj_path, error); } /** * wpas_dbus_getter_current_network - Get current network object path * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "CurrentNetwork" property. */ dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf; if (wpa_s->current_ssid) os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", wpa_s->dbus_new_path, wpa_s->current_ssid->id); else os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, &net_obj_path, error); } /** * wpas_dbus_getter_current_auth_mode - Get current authentication type * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "CurrentAuthMode" property. */ dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *eap_mode; const char *auth_mode; char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX]; if (wpa_s->wpa_state != WPA_COMPLETED) { auth_mode = "INACTIVE"; } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { eap_mode = wpa_supplicant_get_eap_mode(wpa_s); os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX, "EAP-%s", eap_mode); auth_mode = eap_mode_buf; } else { auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt, wpa_s->current_ssid->proto); } return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &auth_mode, error); } /** * wpas_dbus_getter_bridge_ifname - Get interface name * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "BridgeIfname" property. */ dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *bridge_ifname = wpa_s->bridge_ifname; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &bridge_ifname, error); } /** * wpas_dbus_getter_bsss - Get array of BSSs objects * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "BSSs" property. */ dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; struct wpa_bss *bss; char **paths; unsigned int i = 0; dbus_bool_t success = FALSE; paths = os_calloc(wpa_s->num_bss, sizeof(char *)); if (!paths) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } /* Loop through scan results and append each result's object path */ dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); if (paths[i] == NULL) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); goto out; } /* Construct the object path for this BSS. */ os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", wpa_s->dbus_new_path, bss->id); } success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_OBJECT_PATH, paths, wpa_s->num_bss, error); out: while (i) os_free(paths[--i]); os_free(paths); return success; } /** * wpas_dbus_getter_networks - Get array of networks objects * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "Networks" property. */ dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; struct wpa_ssid *ssid; char **paths; unsigned int i = 0, num = 0; dbus_bool_t success = FALSE; if (wpa_s->conf == NULL) { wpa_printf(MSG_ERROR, "%s[dbus]: An error occurred getting " "networks list.", __func__); dbus_set_error(error, DBUS_ERROR_FAILED, "%s: an error " "occurred getting the networks list", __func__); return FALSE; } for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) if (!network_is_persistent_group(ssid)) num++; paths = os_calloc(num, sizeof(char *)); if (!paths) { dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } /* Loop through configured networks and append object path of each */ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (network_is_persistent_group(ssid)) continue; paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); if (paths[i] == NULL) { dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory"); goto out; } /* Construct the object path for this network. */ os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", wpa_s->dbus_new_path, ssid->id); } success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_OBJECT_PATH, paths, num, error); out: while (i) os_free(paths[--i]); os_free(paths); return success; } /** * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: A dbus message containing the PKCS #11 engine path * * Getter for "PKCS11EnginePath" property. */ dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *pkcs11_engine_path; if (wpa_s->conf == NULL) { wpa_printf(MSG_ERROR, "wpas_dbus_getter_pkcs11_engine_path[dbus]: An " "error occurred getting the PKCS #11 engine path."); dbus_set_error_const( error, DBUS_ERROR_FAILED, "An error occured getting the PKCS #11 engine path."); return FALSE; } if (wpa_s->conf->pkcs11_engine_path == NULL) pkcs11_engine_path = ""; else pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &pkcs11_engine_path, error); } /** * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: A dbus message containing the PKCS #11 module path * * Getter for "PKCS11ModulePath" property. */ dbus_bool_t wpas_dbus_getter_pkcs11_module_path(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; const char *pkcs11_module_path; if (wpa_s->conf == NULL) { wpa_printf(MSG_ERROR, "wpas_dbus_getter_pkcs11_module_path[dbus]: An " "error occurred getting the PKCS #11 module path."); dbus_set_error_const( error, DBUS_ERROR_FAILED, "An error occured getting the PKCS #11 module path."); return FALSE; } if (wpa_s->conf->pkcs11_module_path == NULL) pkcs11_module_path = ""; else pkcs11_module_path = wpa_s->conf->pkcs11_module_path; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &pkcs11_module_path, error); } /** * wpas_dbus_getter_blobs - Get all blobs defined for this interface * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "Blobs" property. */ dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error, void *user_data) { struct wpa_supplicant *wpa_s = user_data; DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter; struct wpa_config_blob *blob; if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{say}", &variant_iter) || !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, "{say}", &dict_iter)) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } blob = wpa_s->conf->blobs; while (blob) { if (!dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry_iter) || !dbus_message_iter_append_basic(&entry_iter, DBUS_TYPE_STRING, &(blob->name)) || !dbus_message_iter_open_container(&entry_iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &array_iter) || !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, &(blob->data), blob->len) || !dbus_message_iter_close_container(&entry_iter, &array_iter) || !dbus_message_iter_close_container(&dict_iter, &entry_iter)) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } blob = blob->next; } if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) || !dbus_message_iter_close_container(iter, &variant_iter)) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } return TRUE; } static struct wpa_bss * get_bss_helper(struct bss_handler_args *args, DBusError *error, const char *func_name) { struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id); if (!res) { wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found", func_name, args->id); dbus_set_error(error, DBUS_ERROR_FAILED, "%s: BSS %d not found", func_name, args->id); } return res; } /** * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "BSSID" property. */ dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; res = get_bss_helper(args, error, __func__); if (!res) return FALSE; return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, res->bssid, ETH_ALEN, error); } /** * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "SSID" property. */ dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; res = get_bss_helper(args, error, __func__); if (!res) return FALSE; return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, res->ssid, res->ssid_len, error); } /** * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "Privacy" property. */ dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; dbus_bool_t privacy; res = get_bss_helper(args, error, __func__); if (!res) return FALSE; privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, &privacy, error); } /** * wpas_dbus_getter_bss_mode - Return the mode of a BSS * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "Mode" property. */ dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; const char *mode; res = get_bss_helper(args, error, __func__); if (!res) return FALSE; if (bss_is_dmg(res)) { switch (res->caps & IEEE80211_CAP_DMG_MASK) { case IEEE80211_CAP_DMG_PBSS: case IEEE80211_CAP_DMG_IBSS: mode = "ad-hoc"; break; case IEEE80211_CAP_DMG_AP: mode = "infrastructure"; break; } } else { if (res->caps & IEEE80211_CAP_IBSS) mode = "ad-hoc"; else mode = "infrastructure"; } return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &mode, error); } /** * wpas_dbus_getter_bss_level - Return the signal strength of a BSS * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "Level" property. */ dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; s16 level; res = get_bss_helper(args, error, __func__); if (!res) return FALSE; level = (s16) res->level; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16, &level, error); } /** * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "Frequency" property. */ dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; u16 freq; res = get_bss_helper(args, error, __func__); if (!res) return FALSE; freq = (u16) res->freq; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, &freq, error); } static int cmp_u8s_desc(const void *a, const void *b) { return (*(u8 *) b - *(u8 *) a); } /** * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "Rates" property. */ dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; u8 *ie_rates = NULL; u32 *real_rates; int rates_num, i; dbus_bool_t success = FALSE; res = get_bss_helper(args, error, __func__); if (!res) return FALSE; rates_num = wpa_bss_get_bit_rates(res, &ie_rates); if (rates_num < 0) return FALSE; qsort(ie_rates, rates_num, 1, cmp_u8s_desc); real_rates = os_malloc(sizeof(u32) * rates_num); if (!real_rates) { os_free(ie_rates); dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } for (i = 0; i < rates_num; i++) real_rates[i] = ie_rates[i] * 500000; success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32, real_rates, rates_num, error); os_free(ie_rates); os_free(real_rates); return success; } static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, struct wpa_ie_data *ie_data, DBusError *error) { DBusMessageIter iter_dict, variant_iter; const char *group; const char *pairwise[5]; /* max 5 pairwise ciphers is supported */ const char *key_mgmt[7]; /* max 7 key managements may be supported */ int n; if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}", &variant_iter)) goto nomem; if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) goto nomem; /* KeyMgmt */ n = 0; if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK) key_mgmt[n++] = "wpa-psk"; if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK) key_mgmt[n++] = "wpa-ft-psk"; if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) key_mgmt[n++] = "wpa-psk-sha256"; if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X) key_mgmt[n++] = "wpa-eap"; if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) key_mgmt[n++] = "wpa-ft-eap"; if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) key_mgmt[n++] = "wpa-eap-sha256"; if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE) key_mgmt[n++] = "wpa-none"; if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt", key_mgmt, n)) goto nomem; /* Group */ switch (ie_data->group_cipher) { case WPA_CIPHER_WEP40: group = "wep40"; break; case WPA_CIPHER_TKIP: group = "tkip"; break; case WPA_CIPHER_CCMP: group = "ccmp"; break; case WPA_CIPHER_GCMP: group = "gcmp"; break; case WPA_CIPHER_WEP104: group = "wep104"; break; case WPA_CIPHER_CCMP_256: group = "ccmp-256"; break; case WPA_CIPHER_GCMP_256: group = "gcmp-256"; break; default: group = ""; break; } if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group)) goto nomem; /* Pairwise */ n = 0; if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP) pairwise[n++] = "tkip"; if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP) pairwise[n++] = "ccmp"; if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP) pairwise[n++] = "gcmp"; if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256) pairwise[n++] = "ccmp-256"; if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256) pairwise[n++] = "gcmp-256"; if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise", pairwise, n)) goto nomem; /* Management group (RSN only) */ if (ie_data->proto == WPA_PROTO_RSN) { switch (ie_data->mgmt_group_cipher) { #ifdef CONFIG_IEEE80211W case WPA_CIPHER_AES_128_CMAC: group = "aes128cmac"; break; #endif /* CONFIG_IEEE80211W */ default: group = ""; break; } if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup", group)) goto nomem; } if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict)) goto nomem; if (!dbus_message_iter_close_container(iter, &variant_iter)) goto nomem; return TRUE; nomem: dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } /** * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "WPA" property. */ dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; struct wpa_ie_data wpa_data; const u8 *ie; res = get_bss_helper(args, error, __func__); if (!res) return FALSE; os_memset(&wpa_data, 0, sizeof(wpa_data)); ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE); if (ie) { if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) { dbus_set_error_const(error, DBUS_ERROR_FAILED, "failed to parse WPA IE"); return FALSE; } } return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error); } /** * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "RSN" property. */ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; struct wpa_ie_data wpa_data; const u8 *ie; res = get_bss_helper(args, error, __func__); if (!res) return FALSE; os_memset(&wpa_data, 0, sizeof(wpa_data)); ie = wpa_bss_get_ie(res, WLAN_EID_RSN); if (ie) { if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) { dbus_set_error_const(error, DBUS_ERROR_FAILED, "failed to parse RSN IE"); return FALSE; } } return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error); } /** * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "WPS" property. */ dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; #ifdef CONFIG_WPS struct wpabuf *wps_ie; #endif /* CONFIG_WPS */ DBusMessageIter iter_dict, variant_iter; const char *type = ""; res = get_bss_helper(args, error, __func__); if (!res) return FALSE; if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}", &variant_iter)) goto nomem; if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) goto nomem; #ifdef CONFIG_WPS wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE); if (wps_ie) { if (wps_is_selected_pbc_registrar(wps_ie)) type = "pbc"; else if (wps_is_selected_pin_registrar(wps_ie)) type = "pin"; } #endif /* CONFIG_WPS */ if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type)) goto nomem; if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict)) goto nomem; if (!dbus_message_iter_close_container(iter, &variant_iter)) goto nomem; return TRUE; nomem: dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } /** * wpas_dbus_getter_bss_ies - Return all IEs of a BSS * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "IEs" property. */ dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error, void *user_data) { struct bss_handler_args *args = user_data; struct wpa_bss *res; res = get_bss_helper(args, error, __func__); if (!res) return FALSE; return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, res + 1, res->ie_len, error); } /** * wpas_dbus_getter_enabled - Check whether network is enabled or disabled * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "enabled" property of a configured network. */ dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error, void *user_data) { struct network_handler_args *net = user_data; dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE; return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, &enabled, error); } /** * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Setter for "Enabled" property of a configured network. */ dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error, void *user_data) { struct network_handler_args *net = user_data; struct wpa_supplicant *wpa_s; struct wpa_ssid *ssid; dbus_bool_t enable; if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, &enable)) return FALSE; wpa_s = net->wpa_s; ssid = net->ssid; if (enable) wpa_supplicant_enable_network(wpa_s, ssid); else wpa_supplicant_disable_network(wpa_s, ssid); return TRUE; } /** * wpas_dbus_getter_network_properties - Get options for a configured network * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Getter for "Properties" property of a configured network. */ dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter, DBusError *error, void *user_data) { struct network_handler_args *net = user_data; DBusMessageIter variant_iter, dict_iter; char **iterator; char **props = wpa_config_get_all(net->ssid, 1); dbus_bool_t success = FALSE; if (!props) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); return FALSE; } if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}", &variant_iter) || !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); goto out; } iterator = props; while (*iterator) { if (!wpa_dbus_dict_append_string(&dict_iter, *iterator, *(iterator + 1))) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); goto out; } iterator += 2; } if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) || !dbus_message_iter_close_container(iter, &variant_iter)) { dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); goto out; } success = TRUE; out: iterator = props; while (*iterator) { os_free(*iterator); iterator++; } os_free(props); return success; } /** * wpas_dbus_setter_network_properties - Set options for a configured network * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure * @user_data: Function specific data * Returns: TRUE on success, FALSE on failure * * Setter for "Properties" property of a configured network. */ dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter, DBusError *error, void *user_data) { struct network_handler_args *net = user_data; struct wpa_ssid *ssid = net->ssid; DBusMessageIter variant_iter; dbus_message_iter_recurse(iter, &variant_iter); return set_network_properties(net->wpa_s, ssid, &variant_iter, error); } #ifdef CONFIG_AP DBusMessage * wpas_dbus_handler_subscribe_preq( DBusMessage *message, struct wpa_supplicant *wpa_s) { struct wpas_dbus_priv *priv = wpa_s->global->dbus; char *name; if (wpa_s->preq_notify_peer != NULL) { if (os_strcmp(dbus_message_get_sender(message), wpa_s->preq_notify_peer) == 0) return NULL; return dbus_message_new_error(message, WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE, "Another application is already subscribed"); } name = os_strdup(dbus_message_get_sender(message)); if (!name) return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, "out of memory"); wpa_s->preq_notify_peer = name; /* Subscribe to clean up if application closes socket */ wpas_dbus_subscribe_noc(priv); /* * Double-check it's still alive to make sure that we didn't * miss the NameOwnerChanged signal, e.g. while strdup'ing. */ if (!dbus_bus_name_has_owner(priv->con, name, NULL)) { /* * Application no longer exists, clean up. * The return value is irrelevant now. * * Need to check if the NameOwnerChanged handling * already cleaned up because we have processed * DBus messages while checking if the name still * has an owner. */ if (!wpa_s->preq_notify_peer) return NULL; os_free(wpa_s->preq_notify_peer); wpa_s->preq_notify_peer = NULL; wpas_dbus_unsubscribe_noc(priv); } return NULL; } DBusMessage * wpas_dbus_handler_unsubscribe_preq( DBusMessage *message, struct wpa_supplicant *wpa_s) { struct wpas_dbus_priv *priv = wpa_s->global->dbus; if (!wpa_s->preq_notify_peer) return dbus_message_new_error(message, WPAS_DBUS_ERROR_NO_SUBSCRIPTION, "Not subscribed"); if (os_strcmp(wpa_s->preq_notify_peer, dbus_message_get_sender(message))) return dbus_message_new_error(message, WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM, "Can't unsubscribe others"); os_free(wpa_s->preq_notify_peer); wpa_s->preq_notify_peer = NULL; wpas_dbus_unsubscribe_noc(priv); return NULL; } void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *dst, const u8 *bssid, const u8 *ie, size_t ie_len, u32 ssi_signal) { DBusMessage *msg; DBusMessageIter iter, dict_iter; struct wpas_dbus_priv *priv = wpa_s->global->dbus; /* Do nothing if the control interface is not turned on */ if (priv == NULL) return; if (wpa_s->preq_notify_peer == NULL) return; msg = dbus_message_new_signal(wpa_s->dbus_new_path, WPAS_DBUS_NEW_IFACE_INTERFACE, "ProbeRequest"); if (msg == NULL) return; dbus_message_set_destination(msg, wpa_s->preq_notify_peer); dbus_message_iter_init_append(msg, &iter); if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) goto fail; if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr", (const char *) addr, ETH_ALEN)) goto fail; if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst", (const char *) dst, ETH_ALEN)) goto fail; if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid", (const char *) bssid, ETH_ALEN)) goto fail; if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies", (const char *) ie, ie_len)) goto fail; if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal", ssi_signal)) goto fail; if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) goto fail; dbus_connection_send(priv->con, msg, NULL); goto out; fail: wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); out: dbus_message_unref(msg); } #endif /* CONFIG_AP */ wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_common.h0000664000175000017500000000111712343617166020663 0ustar jmjm/* * wpa_supplicant D-Bus control interface - common definitions * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * Copyright (c) 2009, Witold Sowa * Copyright (c) 2009, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef DBUS_COMMON_H #define DBUS_COMMON_H struct wpas_dbus_priv; struct wpa_global; struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global); void wpas_dbus_deinit(struct wpas_dbus_priv *priv); #endif /* DBUS_COMMON_H */ wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_new_helpers.h0000664000175000017500000001026412343617166021711 0ustar jmjm/* * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * Copyright (c) 2009, Witold Sowa * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef WPA_DBUS_CTRL_H #define WPA_DBUS_CTRL_H #include typedef DBusMessage * (* WPADBusMethodHandler)(DBusMessage *message, void *user_data); typedef void (* WPADBusArgumentFreeFunction)(void *handler_arg); typedef dbus_bool_t (* WPADBusPropertyAccessor)(DBusMessageIter *iter, DBusError *error, void *user_data); struct wpa_dbus_object_desc { DBusConnection *connection; char *path; /* list of methods, properties and signals registered with object */ const struct wpa_dbus_method_desc *methods; const struct wpa_dbus_signal_desc *signals; const struct wpa_dbus_property_desc *properties; /* property changed flags */ u8 *prop_changed_flags; /* argument for method handlers and properties * getter and setter functions */ void *user_data; /* function used to free above argument */ WPADBusArgumentFreeFunction user_data_free_func; }; enum dbus_arg_direction { ARG_IN, ARG_OUT }; struct wpa_dbus_argument { char *name; char *type; enum dbus_arg_direction dir; }; #define END_ARGS { NULL, NULL, ARG_IN } /** * struct wpa_dbus_method_desc - DBus method description */ struct wpa_dbus_method_desc { /* method name */ const char *dbus_method; /* method interface */ const char *dbus_interface; /* method handling function */ WPADBusMethodHandler method_handler; /* array of arguments */ struct wpa_dbus_argument args[4]; }; /** * struct wpa_dbus_signal_desc - DBus signal description */ struct wpa_dbus_signal_desc { /* signal name */ const char *dbus_signal; /* signal interface */ const char *dbus_interface; /* array of arguments */ struct wpa_dbus_argument args[4]; }; /** * struct wpa_dbus_property_desc - DBus property description */ struct wpa_dbus_property_desc { /* property name */ const char *dbus_property; /* property interface */ const char *dbus_interface; /* property type signature in DBus type notation */ const char *type; /* property getter function */ WPADBusPropertyAccessor getter; /* property setter function */ WPADBusPropertyAccessor setter; }; #define WPAS_DBUS_OBJECT_PATH_MAX 150 #define WPAS_DBUS_INTERFACE_MAX 150 #define WPAS_DBUS_METHOD_SIGNAL_PROP_MAX 50 #define WPAS_DBUS_AUTH_MODE_MAX 64 #define WPA_DBUS_INTROSPECTION_INTERFACE "org.freedesktop.DBus.Introspectable" #define WPA_DBUS_INTROSPECTION_METHOD "Introspect" #define WPA_DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties" #define WPA_DBUS_PROPERTIES_GET "Get" #define WPA_DBUS_PROPERTIES_SET "Set" #define WPA_DBUS_PROPERTIES_GETALL "GetAll" void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc); int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface, char *dbus_path, char *dbus_service, struct wpa_dbus_object_desc *obj_desc); int wpa_dbus_register_object_per_iface( struct wpas_dbus_priv *ctrl_iface, const char *path, const char *ifname, struct wpa_dbus_object_desc *obj_desc); int wpa_dbus_unregister_object_per_iface( struct wpas_dbus_priv *ctrl_iface, const char *path); dbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface, const char *path, const char *interface, DBusMessageIter *iter); void wpa_dbus_flush_all_changed_properties(DBusConnection *con); void wpa_dbus_flush_object_changed_properties(DBusConnection *con, const char *path); void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface, const char *path, const char *interface, const char *property); DBusMessage * wpa_dbus_introspect(DBusMessage *message, struct wpa_dbus_object_desc *obj_dsc); char *wpas_dbus_new_decompose_object_path(const char *path, int p2p_persistent_group, char **network, char **bssid); DBusMessage *wpas_dbus_reply_new_from_error(DBusMessage *message, DBusError *error, const char *fallback_name, const char *fallback_string); #endif /* WPA_DBUS_CTRL_H */ wpa_supplicant-2.2/wpa_supplicant/dbus/dbus_old_handlers_wps.c0000664000175000017500000001025612343617166022721 0ustar jmjm/* * WPA Supplicant / dbus-based control interface (WPS) * Copyright (c) 2006, Dan Williams and Red Hat, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include #include "common.h" #include "../config.h" #include "../wpa_supplicant_i.h" #include "../wps_supplicant.h" #include "dbus_old.h" #include "dbus_old_handlers.h" /** * wpas_dbus_iface_wps_pbc - Request credentials using WPS PBC method * @message: Pointer to incoming dbus message * @wpa_s: %wpa_supplicant data structure * Returns: A dbus message containing a UINT32 indicating success (1) or * failure (0) * * Handler function for "wpsPbc" method call */ DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message, struct wpa_supplicant *wpa_s) { char *arg_bssid = NULL; u8 bssid[ETH_ALEN]; int ret = 0; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid, DBUS_TYPE_INVALID)) return wpas_dbus_new_invalid_opts_error(message, NULL); if (!os_strcmp(arg_bssid, "any")) ret = wpas_wps_start_pbc(wpa_s, NULL, 0); else if (!hwaddr_aton(arg_bssid, bssid)) ret = wpas_wps_start_pbc(wpa_s, bssid, 0); else { return wpas_dbus_new_invalid_opts_error(message, "Invalid BSSID"); } if (ret < 0) { return dbus_message_new_error(message, WPAS_ERROR_WPS_PBC_ERROR, "Could not start PBC " "negotiation"); } return wpas_dbus_new_success_reply(message); } /** * wpas_dbus_iface_wps_pin - Establish the PIN number of the enrollee * @message: Pointer to incoming dbus message * @wpa_s: %wpa_supplicant data structure * Returns: A dbus message containing a UINT32 indicating success (1) or * failure (0) * * Handler function for "wpsPin" method call */ DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message, struct wpa_supplicant *wpa_s) { DBusMessage *reply = NULL; char *arg_bssid; char *pin = NULL; u8 bssid[ETH_ALEN], *_bssid = NULL; int ret = 0; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid, DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID)) return wpas_dbus_new_invalid_opts_error(message, NULL); if (!os_strcmp(arg_bssid, "any")) _bssid = NULL; else if (!hwaddr_aton(arg_bssid, bssid)) _bssid = bssid; else { return wpas_dbus_new_invalid_opts_error(message, "Invalid BSSID"); } if (os_strlen(pin) > 0) ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0, DEV_PW_DEFAULT); else ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT); if (ret < 0) { return dbus_message_new_error(message, WPAS_ERROR_WPS_PIN_ERROR, "Could not init PIN"); } reply = dbus_message_new_method_return(message); if (reply == NULL) return NULL; if (ret == 0) { dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID); } else { char npin[9]; os_snprintf(npin, sizeof(npin), "%08d", ret); dbus_message_append_args(reply, DBUS_TYPE_STRING, &npin, DBUS_TYPE_INVALID); } return reply; } /** * wpas_dbus_iface_wps_reg - Request credentials using the PIN of the AP * @message: Pointer to incoming dbus message * @wpa_s: %wpa_supplicant data structure * Returns: A dbus message containing a UINT32 indicating success (1) or * failure (0) * * Handler function for "wpsReg" method call */ DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message, struct wpa_supplicant *wpa_s) { char *arg_bssid; char *pin = NULL; u8 bssid[ETH_ALEN]; int ret = 0; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid, DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID)) return wpas_dbus_new_invalid_opts_error(message, NULL); if (!os_strcmp(arg_bssid, "any")) ret = wpas_wps_start_reg(wpa_s, NULL, pin, NULL); else if (!hwaddr_aton(arg_bssid, bssid)) ret = wpas_wps_start_reg(wpa_s, bssid, pin, NULL); else { return wpas_dbus_new_invalid_opts_error(message, "Invalid BSSID"); } if (ret < 0) { return dbus_message_new_error(message, WPAS_ERROR_WPS_PBC_ERROR, "Could not request credentials"); } return wpas_dbus_new_success_reply(message); } wpa_supplicant-2.2/wpa_supplicant/scan.c0000664000175000017500000015207112343617166016346 0ustar jmjm/* * WPA Supplicant - Scanning * Copyright (c) 2003-2014, 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/wpa_ctrl.h" #include "config.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "wps_supplicant.h" #include "p2p_supplicant.h" #include "p2p/p2p.h" #include "hs20_supplicant.h" #include "notify.h" #include "bss.h" #include "scan.h" static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid; union wpa_event_data data; ssid = wpa_supplicant_get_ssid(wpa_s); if (ssid == NULL) return; if (wpa_s->current_ssid == NULL) { wpa_s->current_ssid = ssid; if (wpa_s->current_ssid != NULL) wpas_notify_network_changed(wpa_s); } wpa_supplicant_initiate_eapol(wpa_s); wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured " "network - generating associated event"); os_memset(&data, 0, sizeof(data)); wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data); } #ifdef CONFIG_WPS static int wpas_wps_in_use(struct wpa_supplicant *wpa_s, enum wps_request_type *req_type) { struct wpa_ssid *ssid; int wps = 0; for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) continue; wps = 1; *req_type = wpas_wps_get_req_type(ssid); if (!ssid->eap.phase1) continue; if (os_strstr(ssid->eap.phase1, "pbc=1")) return 2; } #ifdef CONFIG_P2P if (!wpa_s->global->p2p_disabled && wpa_s->global->p2p && !wpa_s->conf->p2p_disabled) { wpa_s->wps->dev.p2p = 1; if (!wps) { wps = 1; *req_type = WPS_REQ_ENROLLEE_INFO; } } #endif /* CONFIG_P2P */ return wps; } #endif /* CONFIG_WPS */ /** * wpa_supplicant_enabled_networks - Check whether there are enabled networks * @wpa_s: Pointer to wpa_supplicant data * Returns: 0 if no networks are enabled, >0 if networks are enabled * * This function is used to figure out whether any networks (or Interworking * with enabled credentials and auto_interworking) are present in the current * configuration. */ int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid = wpa_s->conf->ssid; int count = 0, disabled = 0; while (ssid) { if (!wpas_network_disabled(wpa_s, ssid)) count++; else disabled++; ssid = ssid->next; } if (wpa_s->conf->cred && wpa_s->conf->interworking && wpa_s->conf->auto_interworking) count++; if (count == 0 && disabled > 0) { wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks (%d disabled " "networks)", disabled); } return count; } static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { while (ssid) { if (!wpas_network_disabled(wpa_s, ssid)) break; ssid = ssid->next; } /* ap_scan=2 mode - try to associate with each SSID. */ if (ssid == NULL) { wpa_dbg(wpa_s, MSG_DEBUG, "wpa_supplicant_assoc_try: Reached " "end of scan list - go back to beginning"); wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; wpa_supplicant_req_scan(wpa_s, 0, 0); return; } if (ssid->next) { /* Continue from the next SSID on the next attempt. */ wpa_s->prev_scan_ssid = ssid; } else { /* Start from the beginning of the SSID list. */ wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; } wpa_supplicant_associate(wpa_s, NULL, ssid); } static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit) { struct wpa_supplicant *wpa_s = work->wpa_s; struct wpa_driver_scan_params *params = work->ctx; int ret; if (deinit) { if (!work->started) { wpa_scan_free_params(params); return; } wpa_supplicant_notify_scanning(wpa_s, 0); wpas_notify_scan_done(wpa_s, 0); wpa_s->scan_work = NULL; return; } wpa_supplicant_notify_scanning(wpa_s, 1); if (wpa_s->clear_driver_scan_cache) params->only_new_results = 1; ret = wpa_drv_scan(wpa_s, params); wpa_scan_free_params(params); work->ctx = NULL; if (ret) { wpa_supplicant_notify_scanning(wpa_s, 0); wpas_notify_scan_done(wpa_s, 0); radio_work_done(work); return; } os_get_reltime(&wpa_s->scan_trigger_time); wpa_s->scan_runs++; wpa_s->normal_scans++; wpa_s->own_scan_requested = 1; wpa_s->clear_driver_scan_cache = 0; wpa_s->scan_work = work; } /** * wpa_supplicant_trigger_scan - Request driver to start a scan * @wpa_s: Pointer to wpa_supplicant data * @params: Scan parameters * Returns: 0 on success, -1 on failure */ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params) { struct wpa_driver_scan_params *ctx; if (wpa_s->scan_work) { wpa_dbg(wpa_s, MSG_INFO, "Reject scan trigger since one is already pending"); return -1; } ctx = wpa_scan_clone_params(params); if (ctx == NULL) return -1; if (radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0) { wpa_scan_free_params(ctx); return -1; } return 0; } static void wpa_supplicant_delayed_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; wpa_dbg(wpa_s, MSG_DEBUG, "Starting delayed sched scan"); if (wpa_supplicant_req_sched_scan(wpa_s)) wpa_supplicant_req_scan(wpa_s, 0, 0); } static void wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; wpa_dbg(wpa_s, MSG_DEBUG, "Sched scan timeout - stopping it"); wpa_s->sched_scan_timed_out = 1; wpa_supplicant_cancel_sched_scan(wpa_s); } int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params, int interval) { int ret; wpa_supplicant_notify_scanning(wpa_s, 1); ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000); if (ret) wpa_supplicant_notify_scanning(wpa_s, 0); else wpa_s->sched_scanning = 1; return ret; } int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s) { int ret; ret = wpa_drv_stop_sched_scan(wpa_s); if (ret) { wpa_dbg(wpa_s, MSG_DEBUG, "stopping sched_scan failed!"); /* TODO: what to do if stopping fails? */ return -1; } return ret; } static struct wpa_driver_scan_filter * wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids) { struct wpa_driver_scan_filter *ssids; struct wpa_ssid *ssid; size_t count; *num_ssids = 0; if (!conf->filter_ssids) return NULL; for (count = 0, ssid = conf->ssid; ssid; ssid = ssid->next) { if (ssid->ssid && ssid->ssid_len) count++; } if (count == 0) return NULL; ssids = os_zalloc(count * sizeof(struct wpa_driver_scan_filter)); if (ssids == NULL) return NULL; for (ssid = conf->ssid; ssid; ssid = ssid->next) { if (!ssid->ssid || !ssid->ssid_len) continue; os_memcpy(ssids[*num_ssids].ssid, ssid->ssid, ssid->ssid_len); ssids[*num_ssids].ssid_len = ssid->ssid_len; (*num_ssids)++; } return ssids; } static void wpa_supplicant_optimize_freqs( struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params) { #ifdef CONFIG_P2P if (params->freqs == NULL && wpa_s->p2p_in_provisioning && wpa_s->go_params) { /* Optimize provisioning state scan based on GO information */ if (wpa_s->p2p_in_provisioning < 5 && wpa_s->go_params->freq > 0) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO " "preferred frequency %d MHz", wpa_s->go_params->freq); params->freqs = os_zalloc(2 * sizeof(int)); if (params->freqs) params->freqs[0] = wpa_s->go_params->freq; } else if (wpa_s->p2p_in_provisioning < 8 && wpa_s->go_params->freq_list[0]) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common " "channels"); int_array_concat(¶ms->freqs, wpa_s->go_params->freq_list); if (params->freqs) int_array_sort_unique(params->freqs); } wpa_s->p2p_in_provisioning++; } if (params->freqs == NULL && wpa_s->p2p_in_invitation) { /* * Optimize scan based on GO information during persistent * group reinvocation */ if (wpa_s->p2p_in_invitation < 5 && wpa_s->p2p_invite_go_freq > 0) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO preferred frequency %d MHz during invitation", wpa_s->p2p_invite_go_freq); params->freqs = os_zalloc(2 * sizeof(int)); if (params->freqs) params->freqs[0] = wpa_s->p2p_invite_go_freq; } wpa_s->p2p_in_invitation++; if (wpa_s->p2p_in_invitation > 20) { /* * This should not really happen since the variable is * cleared on group removal, but if it does happen, make * sure we do not get stuck in special invitation scan * mode. */ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Clear p2p_in_invitation"); wpa_s->p2p_in_invitation = 0; } } #endif /* CONFIG_P2P */ #ifdef CONFIG_WPS if (params->freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) { /* * Optimize post-provisioning scan based on channel used * during provisioning. */ wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz " "that was used during provisioning", wpa_s->wps_freq); params->freqs = os_zalloc(2 * sizeof(int)); if (params->freqs) params->freqs[0] = wpa_s->wps_freq; wpa_s->after_wps--; } else if (wpa_s->after_wps) wpa_s->after_wps--; if (params->freqs == NULL && wpa_s->known_wps_freq && wpa_s->wps_freq) { /* Optimize provisioning scan based on already known channel */ wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz", wpa_s->wps_freq); params->freqs = os_zalloc(2 * sizeof(int)); if (params->freqs) params->freqs[0] = wpa_s->wps_freq; wpa_s->known_wps_freq = 0; /* only do this once */ } #endif /* CONFIG_WPS */ } #ifdef CONFIG_INTERWORKING static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s, struct wpabuf *buf) { if (wpa_s->conf->interworking == 0) return; wpabuf_put_u8(buf, WLAN_EID_EXT_CAPAB); wpabuf_put_u8(buf, 6); wpabuf_put_u8(buf, 0x00); wpabuf_put_u8(buf, 0x00); wpabuf_put_u8(buf, 0x00); wpabuf_put_u8(buf, 0x80); /* Bit 31 - Interworking */ wpabuf_put_u8(buf, 0x00); #ifdef CONFIG_HS20 wpabuf_put_u8(buf, 0x40); /* Bit 46 - WNM-Notification */ #else /* CONFIG_HS20 */ wpabuf_put_u8(buf, 0x00); #endif /* CONFIG_HS20 */ wpabuf_put_u8(buf, WLAN_EID_INTERWORKING); wpabuf_put_u8(buf, is_zero_ether_addr(wpa_s->conf->hessid) ? 1 : 1 + ETH_ALEN); wpabuf_put_u8(buf, wpa_s->conf->access_network_type); /* No Venue Info */ if (!is_zero_ether_addr(wpa_s->conf->hessid)) wpabuf_put_data(buf, wpa_s->conf->hessid, ETH_ALEN); } #endif /* CONFIG_INTERWORKING */ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) { struct wpabuf *extra_ie = NULL; #ifdef CONFIG_WPS int wps = 0; enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; #endif /* CONFIG_WPS */ #ifdef CONFIG_INTERWORKING if (wpa_s->conf->interworking && wpabuf_resize(&extra_ie, 100) == 0) wpas_add_interworking_elements(wpa_s, extra_ie); #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_WPS wps = wpas_wps_in_use(wpa_s, &req_type); if (wps) { struct wpabuf *wps_ie; wps_ie = wps_build_probe_req_ie(wps == 2 ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT, &wpa_s->wps->dev, wpa_s->wps->uuid, req_type, 0, NULL); if (wps_ie) { if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0) wpabuf_put_buf(extra_ie, wps_ie); wpabuf_free(wps_ie); } } #ifdef CONFIG_P2P if (wps) { size_t ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); if (wpabuf_resize(&extra_ie, ielen) == 0) wpas_p2p_scan_ie(wpa_s, extra_ie); } #endif /* CONFIG_P2P */ #endif /* CONFIG_WPS */ #ifdef CONFIG_HS20 if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0) wpas_hs20_add_indication(extra_ie, -1); #endif /* CONFIG_HS20 */ return extra_ie; } #ifdef CONFIG_P2P /* * Check whether there are any enabled networks or credentials that could be * used for a non-P2P connection. */ static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid; for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (wpas_network_disabled(wpa_s, ssid)) continue; if (!ssid->p2p_group) return 1; } if (wpa_s->conf->cred && wpa_s->conf->interworking && wpa_s->conf->auto_interworking) return 1; return 0; } #endif /* CONFIG_P2P */ static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, u16 num_modes, enum hostapd_hw_mode mode) { u16 i; for (i = 0; i < num_modes; i++) { if (modes[i].mode == mode) return &modes[i]; } return NULL; } static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s, enum hostapd_hw_mode band, struct wpa_driver_scan_params *params) { /* Include only supported channels for the specified band */ struct hostapd_hw_modes *mode; int count, i; mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band); if (mode == NULL) { /* No channels supported in this band - use empty list */ params->freqs = os_zalloc(sizeof(int)); return; } params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int)); if (params->freqs == NULL) return; for (count = 0, i = 0; i < mode->num_channels; i++) { if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED) continue; params->freqs[count++] = mode->channels[i].freq; } } static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params) { if (wpa_s->hw.modes == NULL) return; /* unknown what channels the driver supports */ if (params->freqs) return; /* already using a limited channel set */ if (wpa_s->setband == WPA_SETBAND_5G) wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params); else if (wpa_s->setband == WPA_SETBAND_2G) wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params); } static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; struct wpa_ssid *ssid; int ret; struct wpabuf *extra_ie = NULL; struct wpa_driver_scan_params params; struct wpa_driver_scan_params *scan_params; size_t max_ssids; enum wpa_states prev_state; if (wpa_s->pno || wpa_s->pno_sched_pending) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - PNO is in progress"); return; } if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled"); return; } if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) { wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan"); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); return; } if (wpa_s->scanning) { /* * If we are already in scanning state, we shall reschedule the * the incoming scan request. */ wpa_dbg(wpa_s, MSG_DEBUG, "Already scanning - Reschedule the incoming scan req"); wpa_supplicant_req_scan(wpa_s, 1, 0); return; } if (!wpa_supplicant_enabled_networks(wpa_s) && wpa_s->scan_req == NORMAL_SCAN_REQ) { wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan"); wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); return; } if (wpa_s->conf->ap_scan != 0 && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) { wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - " "overriding ap_scan configuration"); wpa_s->conf->ap_scan = 0; wpas_notify_ap_scan_changed(wpa_s); } if (wpa_s->conf->ap_scan == 0) { wpa_supplicant_gen_assoc_event(wpa_s); return; } #ifdef CONFIG_P2P if (wpas_p2p_in_progress(wpa_s)) { wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress"); wpa_supplicant_req_scan(wpa_s, 5, 0); return; } #endif /* CONFIG_P2P */ if (wpa_s->conf->ap_scan == 2) max_ssids = 1; else { max_ssids = wpa_s->max_scan_ssids; if (max_ssids > WPAS_MAX_SCAN_SSIDS) max_ssids = WPAS_MAX_SCAN_SSIDS; } wpa_s->last_scan_req = wpa_s->scan_req; wpa_s->scan_req = NORMAL_SCAN_REQ; os_memset(¶ms, 0, sizeof(params)); prev_state = wpa_s->wpa_state; if (wpa_s->wpa_state == WPA_DISCONNECTED || wpa_s->wpa_state == WPA_INACTIVE) wpa_supplicant_set_state(wpa_s, WPA_SCANNING); /* * If autoscan has set its own scanning parameters */ if (wpa_s->autoscan_params != NULL) { scan_params = wpa_s->autoscan_params; goto scan; } if (wpa_s->last_scan_req != MANUAL_SCAN_REQ && wpa_s->connect_without_scan) { for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (ssid == wpa_s->connect_without_scan) break; } wpa_s->connect_without_scan = NULL; if (ssid) { wpa_printf(MSG_DEBUG, "Start a pre-selected network " "without scan step"); wpa_supplicant_associate(wpa_s, NULL, ssid); return; } } #ifdef CONFIG_P2P if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) && wpa_s->go_params) { wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)", wpa_s->p2p_in_provisioning, wpa_s->show_group_started); params.ssids[0].ssid = wpa_s->go_params->ssid; params.ssids[0].ssid_len = wpa_s->go_params->ssid_len; params.num_ssids = 1; goto ssid_list_set; } if (wpa_s->p2p_in_invitation) { if (wpa_s->current_ssid) { wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during invitation"); params.ssids[0].ssid = wpa_s->current_ssid->ssid; params.ssids[0].ssid_len = wpa_s->current_ssid->ssid_len; params.num_ssids = 1; } else { wpa_printf(MSG_DEBUG, "P2P: No specific SSID known for scan during invitation"); } goto ssid_list_set; } #endif /* CONFIG_P2P */ /* Find the starting point from which to continue scanning */ ssid = wpa_s->conf->ssid; if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) { while (ssid) { if (ssid == wpa_s->prev_scan_ssid) { ssid = ssid->next; break; } ssid = ssid->next; } } if (wpa_s->last_scan_req != MANUAL_SCAN_REQ && wpa_s->conf->ap_scan == 2) { wpa_s->connect_without_scan = NULL; wpa_s->prev_scan_wildcard = 0; wpa_supplicant_assoc_try(wpa_s, ssid); return; } else if (wpa_s->conf->ap_scan == 2) { /* * User-initiated scan request in ap_scan == 2; scan with * wildcard SSID. */ ssid = NULL; } else if (wpa_s->reattach && wpa_s->current_ssid != NULL) { /* * Perform single-channel single-SSID scan for * reassociate-to-same-BSS operation. */ /* Setup SSID */ ssid = wpa_s->current_ssid; wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", ssid->ssid, ssid->ssid_len); params.ssids[0].ssid = ssid->ssid; params.ssids[0].ssid_len = ssid->ssid_len; params.num_ssids = 1; /* * Allocate memory for frequency array, allocate one extra * slot for the zero-terminator. */ params.freqs = os_malloc(sizeof(int) * 2); if (params.freqs == NULL) { wpa_dbg(wpa_s, MSG_ERROR, "Memory allocation failed"); return; } params.freqs[0] = wpa_s->assoc_freq; params.freqs[1] = 0; /* * Reset the reattach flag so that we fall back to full scan if * this scan fails. */ wpa_s->reattach = 0; } else { struct wpa_ssid *start = ssid, *tssid; int freqs_set = 0; if (ssid == NULL && max_ssids > 1) ssid = wpa_s->conf->ssid; while (ssid) { if (!wpas_network_disabled(wpa_s, ssid) && ssid->scan_ssid) { wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", ssid->ssid, ssid->ssid_len); params.ssids[params.num_ssids].ssid = ssid->ssid; params.ssids[params.num_ssids].ssid_len = ssid->ssid_len; params.num_ssids++; if (params.num_ssids + 1 >= max_ssids) break; } ssid = ssid->next; if (ssid == start) break; if (ssid == NULL && max_ssids > 1 && start != wpa_s->conf->ssid) ssid = wpa_s->conf->ssid; } for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) { if (wpas_network_disabled(wpa_s, tssid)) continue; if ((params.freqs || !freqs_set) && tssid->scan_freq) { int_array_concat(¶ms.freqs, tssid->scan_freq); } else { os_free(params.freqs); params.freqs = NULL; } freqs_set = 1; } int_array_sort_unique(params.freqs); } if (ssid && max_ssids == 1) { /* * If the driver is limited to 1 SSID at a time interleave * wildcard SSID scans with specific SSID scans to avoid * waiting a long time for a wildcard scan. */ if (!wpa_s->prev_scan_wildcard) { params.ssids[0].ssid = NULL; params.ssids[0].ssid_len = 0; wpa_s->prev_scan_wildcard = 1; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for " "wildcard SSID (Interleave with specific)"); } else { wpa_s->prev_scan_ssid = ssid; wpa_s->prev_scan_wildcard = 0; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for specific SSID: %s", wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); } } else if (ssid) { /* max_ssids > 1 */ wpa_s->prev_scan_ssid = ssid; wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in " "the scan request"); params.num_ssids++; } else if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && wpa_s->manual_scan_passive && params.num_ssids == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on manual request"); } else { wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; params.num_ssids++; wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard " "SSID"); } #ifdef CONFIG_P2P ssid_list_set: #endif /* CONFIG_P2P */ wpa_supplicant_optimize_freqs(wpa_s, ¶ms); extra_ie = wpa_supplicant_extra_ies(wpa_s); if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && wpa_s->manual_scan_only_new) params.only_new_results = 1; if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL && wpa_s->manual_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Limit manual scan to specified channels"); params.freqs = wpa_s->manual_scan_freqs; wpa_s->manual_scan_freqs = NULL; } if (params.freqs == NULL && wpa_s->next_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously " "generated frequency list"); params.freqs = wpa_s->next_scan_freqs; } else os_free(wpa_s->next_scan_freqs); wpa_s->next_scan_freqs = NULL; wpa_setband_scan_freqs(wpa_s, ¶ms); /* See if user specified frequencies. If so, scan only those. */ if (wpa_s->conf->freq_list && !params.freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on conf->freq_list"); int_array_concat(¶ms.freqs, wpa_s->conf->freq_list); } /* Use current associated channel? */ if (wpa_s->conf->scan_cur_freq && !params.freqs) { unsigned int num = wpa_s->num_multichan_concurrent; params.freqs = os_calloc(num + 1, sizeof(int)); if (params.freqs) { num = get_shared_radio_freqs(wpa_s, params.freqs, num); if (num > 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the " "current operating channels since " "scan_cur_freq is enabled"); } else { os_free(params.freqs); params.freqs = NULL; } } } params.filter_ssids = wpa_supplicant_build_filter_ssids( wpa_s->conf, ¶ms.num_filter_ssids); if (extra_ie) { params.extra_ies = wpabuf_head(extra_ie); params.extra_ies_len = wpabuf_len(extra_ie); } #ifdef CONFIG_P2P if (wpa_s->p2p_in_provisioning || wpa_s->p2p_in_invitation || (wpa_s->show_group_started && wpa_s->go_params)) { /* * The interface may not yet be in P2P mode, so we have to * explicitly request P2P probe to disable CCK rates. */ params.p2p_probe = 1; } #endif /* CONFIG_P2P */ scan_params = ¶ms; scan: #ifdef CONFIG_P2P /* * If the driver does not support multi-channel concurrency and a * virtual interface that shares the same radio with the wpa_s interface * is operating there may not be need to scan other channels apart from * the current operating channel on the other virtual interface. Filter * out other channels in case we are trying to find a connection for a * station interface when we are not configured to prefer station * connection and a concurrent operation is already in process. */ if (wpa_s->scan_for_connection && wpa_s->last_scan_req == NORMAL_SCAN_REQ && !scan_params->freqs && !params.freqs && wpas_is_p2p_prioritized(wpa_s) && wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE && non_p2p_network_enabled(wpa_s)) { unsigned int num = wpa_s->num_multichan_concurrent; params.freqs = os_calloc(num + 1, sizeof(int)); if (params.freqs) { num = get_shared_radio_freqs(wpa_s, params.freqs, num); if (num > 0 && num == wpa_s->num_multichan_concurrent) { wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current operating channels since all channels are already used"); } else { os_free(params.freqs); params.freqs = NULL; } } } #endif /* CONFIG_P2P */ ret = wpa_supplicant_trigger_scan(wpa_s, scan_params); if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs && !wpa_s->manual_scan_freqs) { /* Restore manual_scan_freqs for the next attempt */ wpa_s->manual_scan_freqs = params.freqs; params.freqs = NULL; } wpabuf_free(extra_ie); os_free(params.freqs); os_free(params.filter_ssids); if (ret) { wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan"); if (prev_state != wpa_s->wpa_state) wpa_supplicant_set_state(wpa_s, prev_state); /* Restore scan_req since we will try to scan again */ wpa_s->scan_req = wpa_s->last_scan_req; wpa_supplicant_req_scan(wpa_s, 1, 0); } else { wpa_s->scan_for_connection = 0; } } void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec) { struct os_reltime remaining, new_int; int cancelled; cancelled = eloop_cancel_timeout_one(wpa_supplicant_scan, wpa_s, NULL, &remaining); new_int.sec = sec; new_int.usec = 0; if (cancelled && os_reltime_before(&remaining, &new_int)) { new_int.sec = remaining.sec; new_int.usec = remaining.usec; } if (cancelled) { eloop_register_timeout(new_int.sec, new_int.usec, wpa_supplicant_scan, wpa_s, NULL); } wpa_s->scan_interval = sec; } /** * wpa_supplicant_req_scan - Schedule a scan for neighboring access points * @wpa_s: Pointer to wpa_supplicant data * @sec: Number of seconds after which to scan * @usec: Number of microseconds after which to scan * * This function is used to schedule a scan for neighboring access points after * the specified time. */ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) { int res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); if (res == 1) { wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec", sec, usec); } else if (res == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Ignore new scan request for %d.%06d sec since an earlier request is scheduled to trigger sooner", sec, usec); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d.%06d sec", sec, usec); eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); } } /** * wpa_supplicant_delayed_sched_scan - Request a delayed scheduled scan * @wpa_s: Pointer to wpa_supplicant data * @sec: Number of seconds after which to scan * @usec: Number of microseconds after which to scan * Returns: 0 on success or -1 otherwise * * This function is used to schedule periodic scans for neighboring * access points after the specified time. */ int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s, int sec, int usec) { if (!wpa_s->sched_scan_supported) return -1; eloop_register_timeout(sec, usec, wpa_supplicant_delayed_sched_scan_timeout, wpa_s, NULL); return 0; } /** * wpa_supplicant_req_sched_scan - Start a periodic scheduled scan * @wpa_s: Pointer to wpa_supplicant data * Returns: 0 is sched_scan was started or -1 otherwise * * This function is used to schedule periodic scans for neighboring * access points repeating the scan continuously. */ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) { struct wpa_driver_scan_params params; struct wpa_driver_scan_params *scan_params; enum wpa_states prev_state; struct wpa_ssid *ssid = NULL; struct wpabuf *extra_ie = NULL; int ret; unsigned int max_sched_scan_ssids; int wildcard = 0; int need_ssids; if (!wpa_s->sched_scan_supported) return -1; if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS) max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS; else max_sched_scan_ssids = wpa_s->max_sched_scan_ssids; if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload) return -1; if (wpa_s->sched_scanning) { wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning"); return 0; } need_ssids = 0; for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (!wpas_network_disabled(wpa_s, ssid) && !ssid->scan_ssid) { /* Use wildcard SSID to find this network */ wildcard = 1; } else if (!wpas_network_disabled(wpa_s, ssid) && ssid->ssid_len) need_ssids++; #ifdef CONFIG_WPS if (!wpas_network_disabled(wpa_s, ssid) && ssid->key_mgmt == WPA_KEY_MGMT_WPS) { /* * Normal scan is more reliable and faster for WPS * operations and since these are for short periods of * time, the benefit of trying to use sched_scan would * be limited. */ wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of " "sched_scan for WPS"); return -1; } #endif /* CONFIG_WPS */ } if (wildcard) need_ssids++; if (wpa_s->normal_scans < 3 && (need_ssids <= wpa_s->max_scan_ssids || wpa_s->max_scan_ssids >= (int) max_sched_scan_ssids)) { /* * When normal scan can speed up operations, use that for the * first operations before starting the sched_scan to allow * user space sleep more. We do this only if the normal scan * has functionality that is suitable for this or if the * sched_scan does not have better support for multiple SSIDs. */ wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of " "sched_scan for initial scans (normal_scans=%d)", wpa_s->normal_scans); return -1; } os_memset(¶ms, 0, sizeof(params)); /* If we can't allocate space for the filters, we just don't filter */ params.filter_ssids = os_zalloc(wpa_s->max_match_sets * sizeof(struct wpa_driver_scan_filter)); prev_state = wpa_s->wpa_state; if (wpa_s->wpa_state == WPA_DISCONNECTED || wpa_s->wpa_state == WPA_INACTIVE) wpa_supplicant_set_state(wpa_s, WPA_SCANNING); if (wpa_s->autoscan_params != NULL) { scan_params = wpa_s->autoscan_params; goto scan; } /* Find the starting point from which to continue scanning */ ssid = wpa_s->conf->ssid; if (wpa_s->prev_sched_ssid) { while (ssid) { if (ssid == wpa_s->prev_sched_ssid) { ssid = ssid->next; break; } ssid = ssid->next; } } if (!ssid || !wpa_s->prev_sched_ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list"); if (wpa_s->conf->sched_scan_interval) wpa_s->sched_scan_interval = wpa_s->conf->sched_scan_interval; if (wpa_s->sched_scan_interval == 0) wpa_s->sched_scan_interval = 10; wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2; wpa_s->first_sched_scan = 1; ssid = wpa_s->conf->ssid; wpa_s->prev_sched_ssid = ssid; } if (wildcard) { wpa_dbg(wpa_s, MSG_DEBUG, "Add wildcard SSID to sched_scan"); params.num_ssids++; } while (ssid) { if (wpas_network_disabled(wpa_s, ssid)) goto next; if (params.num_filter_ssids < wpa_s->max_match_sets && params.filter_ssids && ssid->ssid && ssid->ssid_len) { wpa_dbg(wpa_s, MSG_DEBUG, "add to filter ssid: %s", wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); os_memcpy(params.filter_ssids[params.num_filter_ssids].ssid, ssid->ssid, ssid->ssid_len); params.filter_ssids[params.num_filter_ssids].ssid_len = ssid->ssid_len; params.num_filter_ssids++; } else if (params.filter_ssids && ssid->ssid && ssid->ssid_len) { wpa_dbg(wpa_s, MSG_DEBUG, "Not enough room for SSID " "filter for sched_scan - drop filter"); os_free(params.filter_ssids); params.filter_ssids = NULL; params.num_filter_ssids = 0; } if (ssid->scan_ssid && ssid->ssid && ssid->ssid_len) { if (params.num_ssids == max_sched_scan_ssids) break; /* only room for broadcast SSID */ wpa_dbg(wpa_s, MSG_DEBUG, "add to active scan ssid: %s", wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); params.ssids[params.num_ssids].ssid = ssid->ssid; params.ssids[params.num_ssids].ssid_len = ssid->ssid_len; params.num_ssids++; if (params.num_ssids >= max_sched_scan_ssids) { wpa_s->prev_sched_ssid = ssid; do { ssid = ssid->next; } while (ssid && (wpas_network_disabled(wpa_s, ssid) || !ssid->scan_ssid)); break; } } next: wpa_s->prev_sched_ssid = ssid; ssid = ssid->next; } if (params.num_filter_ssids == 0) { os_free(params.filter_ssids); params.filter_ssids = NULL; } extra_ie = wpa_supplicant_extra_ies(wpa_s); if (extra_ie) { params.extra_ies = wpabuf_head(extra_ie); params.extra_ies_len = wpabuf_len(extra_ie); } if (wpa_s->conf->filter_rssi) params.filter_rssi = wpa_s->conf->filter_rssi; scan_params = ¶ms; scan: if (ssid || !wpa_s->first_sched_scan) { wpa_dbg(wpa_s, MSG_DEBUG, "Starting sched scan: interval %d timeout %d", wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Starting sched scan: interval %d (no timeout)", wpa_s->sched_scan_interval); } wpa_setband_scan_freqs(wpa_s, scan_params); ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params, wpa_s->sched_scan_interval); wpabuf_free(extra_ie); os_free(params.filter_ssids); if (ret) { wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan"); if (prev_state != wpa_s->wpa_state) wpa_supplicant_set_state(wpa_s, prev_state); return ret; } /* If we have more SSIDs to scan, add a timeout so we scan them too */ if (ssid || !wpa_s->first_sched_scan) { wpa_s->sched_scan_timed_out = 0; eloop_register_timeout(wpa_s->sched_scan_timeout, 0, wpa_supplicant_sched_scan_timeout, wpa_s, NULL); wpa_s->first_sched_scan = 0; wpa_s->sched_scan_timeout /= 2; wpa_s->sched_scan_interval *= 2; if (wpa_s->sched_scan_timeout < wpa_s->sched_scan_interval) { wpa_s->sched_scan_interval = 10; wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2; } } /* If there is no more ssids, start next time from the beginning */ if (!ssid) wpa_s->prev_sched_ssid = NULL; return 0; } /** * wpa_supplicant_cancel_scan - Cancel a scheduled scan request * @wpa_s: Pointer to wpa_supplicant data * * This function is used to cancel a scan request scheduled with * wpa_supplicant_req_scan(). */ void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) { wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request"); eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); } /** * wpa_supplicant_cancel_delayed_sched_scan - Stop a delayed scheduled scan * @wpa_s: Pointer to wpa_supplicant data * * This function is used to stop a delayed scheduled scan. */ void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s) { if (!wpa_s->sched_scan_supported) return; wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling delayed sched scan"); eloop_cancel_timeout(wpa_supplicant_delayed_sched_scan_timeout, wpa_s, NULL); } /** * wpa_supplicant_cancel_sched_scan - Stop running scheduled scans * @wpa_s: Pointer to wpa_supplicant data * * This function is used to stop a periodic scheduled scan. */ void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s) { if (!wpa_s->sched_scanning) return; wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling sched scan"); eloop_cancel_timeout(wpa_supplicant_sched_scan_timeout, wpa_s, NULL); wpa_supplicant_stop_sched_scan(wpa_s); } /** * wpa_supplicant_notify_scanning - Indicate possible scan state change * @wpa_s: Pointer to wpa_supplicant data * @scanning: Whether scanning is currently in progress * * This function is to generate scanning notifycations. It is called whenever * there may have been a change in scanning (scan started, completed, stopped). * wpas_notify_scanning() is called whenever the scanning state changed from the * previously notified state. */ void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s, int scanning) { if (wpa_s->scanning != scanning) { wpa_s->scanning = scanning; wpas_notify_scanning(wpa_s); } } static int wpa_scan_get_max_rate(const struct wpa_scan_res *res) { int rate = 0; const u8 *ie; int i; ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES); for (i = 0; ie && i < ie[1]; i++) { if ((ie[i + 2] & 0x7f) > rate) rate = ie[i + 2] & 0x7f; } ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES); for (i = 0; ie && i < ie[1]; i++) { if ((ie[i + 2] & 0x7f) > rate) rate = ie[i + 2] & 0x7f; } return rate; } /** * wpa_scan_get_ie - Fetch a specified information element from a scan result * @res: Scan result entry * @ie: Information element identitifier (WLAN_EID_*) * Returns: Pointer to the information element (id field) or %NULL if not found * * This function returns the first matching information element in the scan * result. */ const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) { const u8 *end, *pos; pos = (const u8 *) (res + 1); end = pos + res->ie_len; while (pos + 1 < end) { if (pos + 2 + pos[1] > end) break; if (pos[0] == ie) return pos; pos += 2 + pos[1]; } return NULL; } /** * wpa_scan_get_vendor_ie - Fetch vendor information element from a scan result * @res: Scan result entry * @vendor_type: Vendor type (four octets starting the IE payload) * Returns: Pointer to the information element (id field) or %NULL if not found * * This function returns the first matching information element in the scan * result. */ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, u32 vendor_type) { const u8 *end, *pos; pos = (const u8 *) (res + 1); end = pos + res->ie_len; while (pos + 1 < end) { if (pos + 2 + pos[1] > end) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) return pos; pos += 2 + pos[1]; } return NULL; } /** * wpa_scan_get_vendor_ie_beacon - Fetch vendor information from a scan result * @res: Scan result entry * @vendor_type: Vendor type (four octets starting the IE payload) * Returns: Pointer to the information element (id field) or %NULL if not found * * This function returns the first matching information element in the scan * result. * * This function is like wpa_scan_get_vendor_ie(), but uses IE buffer only * from Beacon frames instead of either Beacon or Probe Response frames. */ const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res, u32 vendor_type) { const u8 *end, *pos; if (res->beacon_ie_len == 0) return NULL; pos = (const u8 *) (res + 1); pos += res->ie_len; end = pos + res->beacon_ie_len; while (pos + 1 < end) { if (pos + 2 + pos[1] > end) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) return pos; pos += 2 + pos[1]; } return NULL; } /** * wpa_scan_get_vendor_ie_multi - Fetch vendor IE data from a scan result * @res: Scan result entry * @vendor_type: Vendor type (four octets starting the IE payload) * Returns: Pointer to the information element payload or %NULL if not found * * This function returns concatenated payload of possibly fragmented vendor * specific information elements in the scan result. The caller is responsible * for freeing the returned buffer. */ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, u32 vendor_type) { struct wpabuf *buf; const u8 *end, *pos; buf = wpabuf_alloc(res->ie_len); if (buf == NULL) return NULL; pos = (const u8 *) (res + 1); end = pos + res->ie_len; while (pos + 1 < end) { if (pos + 2 + pos[1] > end) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4); pos += 2 + pos[1]; } if (wpabuf_len(buf) == 0) { wpabuf_free(buf); buf = NULL; } return buf; } /* * Channels with a great SNR can operate at full rate. What is a great SNR? * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general * rule of thumb is that any SNR above 20 is good." This one * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23 * recommends 25 as a minimum SNR for 54 Mbps data rate. 30 is chosen here as a * conservative value. */ #define GREAT_SNR 30 /* Compare function for sorting scan results. Return >0 if @b is considered * better. */ static int wpa_scan_result_compar(const void *a, const void *b) { #define IS_5GHZ(n) (n > 4000) #define MIN(a,b) a < b ? a : b struct wpa_scan_res **_wa = (void *) a; struct wpa_scan_res **_wb = (void *) b; struct wpa_scan_res *wa = *_wa; struct wpa_scan_res *wb = *_wb; int wpa_a, wpa_b, maxrate_a, maxrate_b; int snr_a, snr_b; /* WPA/WPA2 support preferred */ wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL || wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL; wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL || wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL; if (wpa_b && !wpa_a) return 1; if (!wpa_b && wpa_a) return -1; /* privacy support preferred */ if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 && (wb->caps & IEEE80211_CAP_PRIVACY)) return 1; if ((wa->caps & IEEE80211_CAP_PRIVACY) && (wb->caps & IEEE80211_CAP_PRIVACY) == 0) return -1; if ((wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) && !((wa->flags | wb->flags) & WPA_SCAN_NOISE_INVALID)) { snr_a = MIN(wa->level - wa->noise, GREAT_SNR); snr_b = MIN(wb->level - wb->noise, GREAT_SNR); } else { /* Not suitable information to calculate SNR, so use level */ snr_a = wa->level; snr_b = wb->level; } /* best/max rate preferred if SNR close enough */ if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) || (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) { maxrate_a = wpa_scan_get_max_rate(wa); maxrate_b = wpa_scan_get_max_rate(wb); if (maxrate_a != maxrate_b) return maxrate_b - maxrate_a; if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq)) return IS_5GHZ(wa->freq) ? -1 : 1; } /* use freq for channel preference */ /* all things being equal, use SNR; if SNRs are * identical, use quality values since some drivers may only report * that value and leave the signal level zero */ if (snr_b == snr_a) return wb->qual - wa->qual; return snr_b - snr_a; #undef MIN #undef IS_5GHZ } #ifdef CONFIG_WPS /* Compare function for sorting scan results when searching a WPS AP for * provisioning. Return >0 if @b is considered better. */ static int wpa_scan_result_wps_compar(const void *a, const void *b) { struct wpa_scan_res **_wa = (void *) a; struct wpa_scan_res **_wb = (void *) b; struct wpa_scan_res *wa = *_wa; struct wpa_scan_res *wb = *_wb; int uses_wps_a, uses_wps_b; struct wpabuf *wps_a, *wps_b; int res; /* Optimization - check WPS IE existence before allocated memory and * doing full reassembly. */ uses_wps_a = wpa_scan_get_vendor_ie(wa, WPS_IE_VENDOR_TYPE) != NULL; uses_wps_b = wpa_scan_get_vendor_ie(wb, WPS_IE_VENDOR_TYPE) != NULL; if (uses_wps_a && !uses_wps_b) return -1; if (!uses_wps_a && uses_wps_b) return 1; if (uses_wps_a && uses_wps_b) { wps_a = wpa_scan_get_vendor_ie_multi(wa, WPS_IE_VENDOR_TYPE); wps_b = wpa_scan_get_vendor_ie_multi(wb, WPS_IE_VENDOR_TYPE); res = wps_ap_priority_compar(wps_a, wps_b); wpabuf_free(wps_a); wpabuf_free(wps_b); if (res) return res; } /* * Do not use current AP security policy as a sorting criteria during * WPS provisioning step since the AP may get reconfigured at the * completion of provisioning. */ /* all things being equal, use signal level; if signal levels are * identical, use quality values since some drivers may only report * that value and leave the signal level zero */ if (wb->level == wa->level) return wb->qual - wa->qual; return wb->level - wa->level; } #endif /* CONFIG_WPS */ static void dump_scan_res(struct wpa_scan_results *scan_res) { #ifndef CONFIG_NO_STDOUT_DEBUG size_t i; if (scan_res->res == NULL || scan_res->num == 0) return; wpa_printf(MSG_EXCESSIVE, "Sorted scan results"); for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *r = scan_res->res[i]; u8 *pos; if ((r->flags & (WPA_SCAN_LEVEL_DBM | WPA_SCAN_NOISE_INVALID)) == WPA_SCAN_LEVEL_DBM) { int snr = r->level - r->noise; wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d " "noise=%d level=%d snr=%d%s flags=0x%x " "age=%u", MAC2STR(r->bssid), r->freq, r->qual, r->noise, r->level, snr, snr >= GREAT_SNR ? "*" : "", r->flags, r->age); } else { wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d " "noise=%d level=%d flags=0x%x age=%u", MAC2STR(r->bssid), r->freq, r->qual, r->noise, r->level, r->flags, r->age); } pos = (u8 *) (r + 1); if (r->ie_len) wpa_hexdump(MSG_EXCESSIVE, "IEs", pos, r->ie_len); pos += r->ie_len; if (r->beacon_ie_len) wpa_hexdump(MSG_EXCESSIVE, "Beacon IEs", pos, r->beacon_ie_len); } #endif /* CONFIG_NO_STDOUT_DEBUG */ } /** * wpa_supplicant_filter_bssid_match - Is the specified BSSID allowed * @wpa_s: Pointer to wpa_supplicant data * @bssid: BSSID to check * Returns: 0 if the BSSID is filtered or 1 if not * * This function is used to filter out specific BSSIDs from scan reslts mainly * for testing purposes (SET bssid_filter ctrl_iface command). */ int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s, const u8 *bssid) { size_t i; if (wpa_s->bssid_filter == NULL) return 1; for (i = 0; i < wpa_s->bssid_filter_count; i++) { if (os_memcmp(wpa_s->bssid_filter + i * ETH_ALEN, bssid, ETH_ALEN) == 0) return 1; } return 0; } static void filter_scan_res(struct wpa_supplicant *wpa_s, struct wpa_scan_results *res) { size_t i, j; if (wpa_s->bssid_filter == NULL) return; for (i = 0, j = 0; i < res->num; i++) { if (wpa_supplicant_filter_bssid_match(wpa_s, res->res[i]->bssid)) { res->res[j++] = res->res[i]; } else { os_free(res->res[i]); res->res[i] = NULL; } } if (res->num != j) { wpa_printf(MSG_DEBUG, "Filtered out %d scan results", (int) (res->num - j)); res->num = j; } } /** * wpa_supplicant_get_scan_results - Get scan results * @wpa_s: Pointer to wpa_supplicant data * @info: Information about what was scanned or %NULL if not available * @new_scan: Whether a new scan was performed * Returns: Scan results, %NULL on failure * * This function request the current scan results from the driver and updates * the local BSS list wpa_s->bss. The caller is responsible for freeing the * results with wpa_scan_results_free(). */ struct wpa_scan_results * wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, struct scan_info *info, int new_scan) { struct wpa_scan_results *scan_res; size_t i; int (*compar)(const void *, const void *) = wpa_scan_result_compar; scan_res = wpa_drv_get_scan_results2(wpa_s); if (scan_res == NULL) { wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results"); return NULL; } if (scan_res->fetch_time.sec == 0) { /* * Make sure we have a valid timestamp if the driver wrapper * does not set this. */ os_get_reltime(&scan_res->fetch_time); } filter_scan_res(wpa_s, scan_res); #ifdef CONFIG_WPS if (wpas_wps_searching(wpa_s)) { wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS " "provisioning rules"); compar = wpa_scan_result_wps_compar; } #endif /* CONFIG_WPS */ qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *), compar); dump_scan_res(scan_res); wpa_bss_update_start(wpa_s); for (i = 0; i < scan_res->num; i++) wpa_bss_update_scan_res(wpa_s, scan_res->res[i], &scan_res->fetch_time); wpa_bss_update_end(wpa_s, info, new_scan); return scan_res; } /** * wpa_supplicant_update_scan_results - Update scan results from the driver * @wpa_s: Pointer to wpa_supplicant data * Returns: 0 on success, -1 on failure * * This function updates the BSS table within wpa_supplicant based on the * currently available scan results from the driver without requesting a new * scan. This is used in cases where the driver indicates an association * (including roaming within ESS) and wpa_supplicant does not yet have the * needed information to complete the connection (e.g., to perform validation * steps in 4-way handshake). */ int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s) { struct wpa_scan_results *scan_res; scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0); if (scan_res == NULL) return -1; wpa_scan_results_free(scan_res); return 0; } /** * scan_only_handler - Reports scan results */ void scan_only_handler(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { wpa_dbg(wpa_s, MSG_DEBUG, "Scan-only results received"); if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && wpa_s->manual_scan_use_id && wpa_s->own_scan_running) { wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u", wpa_s->manual_scan_id); wpa_s->manual_scan_use_id = 0; } else { wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); } wpas_notify_scan_results(wpa_s); wpas_notify_scan_done(wpa_s, 1); if (wpa_s->scan_work) { struct wpa_radio_work *work = wpa_s->scan_work; wpa_s->scan_work = NULL; radio_work_done(work); } } int wpas_scan_scheduled(struct wpa_supplicant *wpa_s) { return eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL); } struct wpa_driver_scan_params * wpa_scan_clone_params(const struct wpa_driver_scan_params *src) { struct wpa_driver_scan_params *params; size_t i; u8 *n; params = os_zalloc(sizeof(*params)); if (params == NULL) return NULL; for (i = 0; i < src->num_ssids; i++) { if (src->ssids[i].ssid) { n = os_malloc(src->ssids[i].ssid_len); if (n == NULL) goto failed; os_memcpy(n, src->ssids[i].ssid, src->ssids[i].ssid_len); params->ssids[i].ssid = n; params->ssids[i].ssid_len = src->ssids[i].ssid_len; } } params->num_ssids = src->num_ssids; if (src->extra_ies) { n = os_malloc(src->extra_ies_len); if (n == NULL) goto failed; os_memcpy(n, src->extra_ies, src->extra_ies_len); params->extra_ies = n; params->extra_ies_len = src->extra_ies_len; } if (src->freqs) { int len = int_array_len(src->freqs); params->freqs = os_malloc((len + 1) * sizeof(int)); if (params->freqs == NULL) goto failed; os_memcpy(params->freqs, src->freqs, (len + 1) * sizeof(int)); } if (src->filter_ssids) { params->filter_ssids = os_malloc(sizeof(*params->filter_ssids) * src->num_filter_ssids); if (params->filter_ssids == NULL) goto failed; os_memcpy(params->filter_ssids, src->filter_ssids, sizeof(*params->filter_ssids) * src->num_filter_ssids); params->num_filter_ssids = src->num_filter_ssids; } params->filter_rssi = src->filter_rssi; params->p2p_probe = src->p2p_probe; params->only_new_results = src->only_new_results; return params; failed: wpa_scan_free_params(params); return NULL; } void wpa_scan_free_params(struct wpa_driver_scan_params *params) { size_t i; if (params == NULL) return; for (i = 0; i < params->num_ssids; i++) os_free((u8 *) params->ssids[i].ssid); os_free((u8 *) params->extra_ies); os_free(params->freqs); os_free(params->filter_ssids); os_free(params); } int wpas_start_pno(struct wpa_supplicant *wpa_s) { int ret, interval; size_t i, num_ssid; struct wpa_ssid *ssid; struct wpa_driver_scan_params params; if (!wpa_s->sched_scan_supported) return -1; if (wpa_s->pno || wpa_s->pno_sched_pending) return 0; if ((wpa_s->wpa_state > WPA_SCANNING) && (wpa_s->wpa_state <= WPA_COMPLETED)) { wpa_printf(MSG_ERROR, "PNO: In assoc process"); return -EAGAIN; } if (wpa_s->wpa_state == WPA_SCANNING) { wpa_supplicant_cancel_scan(wpa_s); if (wpa_s->sched_scanning) { wpa_printf(MSG_DEBUG, "Schedule PNO on completion of " "ongoing sched scan"); wpa_supplicant_cancel_sched_scan(wpa_s); wpa_s->pno_sched_pending = 1; return 0; } } os_memset(¶ms, 0, sizeof(params)); num_ssid = 0; ssid = wpa_s->conf->ssid; while (ssid) { if (!wpas_network_disabled(wpa_s, ssid)) num_ssid++; ssid = ssid->next; } if (num_ssid > WPAS_MAX_SCAN_SSIDS) { wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from " "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid); num_ssid = WPAS_MAX_SCAN_SSIDS; } if (num_ssid == 0) { wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs"); return -1; } params.filter_ssids = os_malloc(sizeof(struct wpa_driver_scan_filter) * num_ssid); if (params.filter_ssids == NULL) return -1; i = 0; ssid = wpa_s->conf->ssid; while (ssid) { if (!wpas_network_disabled(wpa_s, ssid)) { params.ssids[i].ssid = ssid->ssid; params.ssids[i].ssid_len = ssid->ssid_len; params.num_ssids++; os_memcpy(params.filter_ssids[i].ssid, ssid->ssid, ssid->ssid_len); params.filter_ssids[i].ssid_len = ssid->ssid_len; params.num_filter_ssids++; i++; if (i == num_ssid) break; } ssid = ssid->next; } if (wpa_s->conf->filter_rssi) params.filter_rssi = wpa_s->conf->filter_rssi; interval = wpa_s->conf->sched_scan_interval ? wpa_s->conf->sched_scan_interval : 10; if (params.freqs == NULL && wpa_s->manual_sched_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Limit sched scan to specified channels"); params.freqs = wpa_s->manual_sched_scan_freqs; } ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms, interval); os_free(params.filter_ssids); if (ret == 0) wpa_s->pno = 1; else wpa_msg(wpa_s, MSG_ERROR, "Failed to schedule PNO"); return ret; } int wpas_stop_pno(struct wpa_supplicant *wpa_s) { int ret = 0; if (!wpa_s->pno) return 0; ret = wpa_supplicant_stop_sched_scan(wpa_s); wpa_s->pno = 0; wpa_s->pno_sched_pending = 0; if (wpa_s->wpa_state == WPA_SCANNING) wpa_supplicant_req_scan(wpa_s, 0, 0); return ret; } wpa_supplicant-2.2/wpa_supplicant/README-WPS0000664000175000017500000003757512343617166016620 0ustar jmjmwpa_supplicant and Wi-Fi Protected Setup (WPS) ============================================== This document describes how the WPS implementation in wpa_supplicant can be configured and how an external component on the client (e.g., management GUI) is used to enable WPS enrollment and registrar registration. Introduction to WPS ------------------- Wi-Fi Protected Setup (WPS) is a mechanism for easy configuration of a wireless network. It allows automated generation of random keys (WPA passphrase/PSK) and configuration of an access point and client devices. WPS includes number of methods for setting up connections with PIN method and push-button configuration (PBC) being the most commonly deployed options. While WPS can enable more home networks to use encryption in the wireless network, it should be noted that the use of the PIN and especially PBC mechanisms for authenticating the initial key setup is not very secure. As such, use of WPS may not be suitable for environments that require secure network access without chance for allowing outsiders to gain access during the setup phase. WPS uses following terms to describe the entities participating in the network setup: - access point: the WLAN access point - Registrar: a device that control a network and can authorize addition of new devices); this may be either in the AP ("internal Registrar") or in an external device, e.g., a laptop, ("external Registrar") - Enrollee: a device that is being authorized to use the network It should also be noted that the AP and a client device may change roles (i.e., AP acts as an Enrollee and client device as a Registrar) when WPS is used to configure the access point. More information about WPS is available from Wi-Fi Alliance: http://www.wi-fi.org/wifi-protected-setup wpa_supplicant implementation ----------------------------- wpa_supplicant includes an optional WPS component that can be used as an Enrollee to enroll new network credential or as a Registrar to configure an AP. wpa_supplicant configuration ---------------------------- WPS is an optional component that needs to be enabled in wpa_supplicant build configuration (.config). Here is an example configuration that includes WPS support and Linux nl80211 -based driver interface: CONFIG_DRIVER_NL80211=y CONFIG_WPS=y If you want to enable WPS external registrar (ER) functionality, you will also need to add following line: CONFIG_WPS_ER=y Following parameter can be used to enable support for NFC config method: CONFIG_WPS_NFC=y WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for the device. This is configured in the runtime configuration for wpa_supplicant (if not set, UUID will be generated based on local MAC address): # example UUID for WPS uuid=12345678-9abc-def0-1234-56789abcdef0 The network configuration blocks needed for WPS are added automatically based on control interface commands, so they do not need to be added explicitly in the configuration file. WPS registration will generate new network blocks for the acquired credentials. If these are to be stored for future use (after restarting wpa_supplicant), wpa_supplicant will need to be configured to allow configuration file updates: update_config=1 External operations ------------------- WPS requires either a device PIN code (usually, 8-digit number) or a pushbutton event (for PBC) to allow a new WPS Enrollee to join the network. wpa_supplicant uses the control interface as an input channel for these events. The PIN value used in the commands must be processed by an UI to remove non-digit characters and potentially, to verify the checksum digit. "wpa_cli wps_check_pin " can be used to do such processing. It returns FAIL if the PIN is invalid, or FAIL-CHECKSUM if the checksum digit is incorrect, or the processed PIN (non-digit characters removed) if the PIN is valid. If the client device has a display, a random PIN has to be generated for each WPS registration session. wpa_supplicant can do this with a control interface request, e.g., by calling wpa_cli: wpa_cli wps_pin any This will return the generated 8-digit PIN which will then need to be entered at the Registrar to complete WPS registration. At that point, the client will be enrolled with credentials needed to connect to the AP to access the network. If the client device does not have a display that could show the random PIN, a hardcoded PIN that is printed on a label can be used. wpa_supplicant is notified this with a control interface request, e.g., by calling wpa_cli: wpa_cli wps_pin any 12345670 This starts the WPS negotiation in the same way as above with the generated PIN. When the wps_pin command is issued for an AP (including P2P GO) mode interface, an optional timeout parameter can be used to specify expiration timeout for the PIN in seconds. For example: wpa_cli wps_pin any 12345670 300 If a random PIN is needed for a user interface, "wpa_cli wps_pin get" can be used to generate a new PIN without starting WPS negotiation. This random PIN can then be passed as an argument to another wps_pin call when the actual operation should be started. If the client design wants to support optional WPS PBC mode, this can be enabled by either a physical button in the client device or a virtual button in the user interface. The PBC operation requires that a button is also pressed at the AP/Registrar at about the same time (2 minute window). wpa_supplicant is notified of the local button event over the control interface, e.g., by calling wpa_cli: wpa_cli wps_pbc At this point, the AP/Registrar has two minutes to complete WPS negotiation which will generate a new WPA PSK in the same way as the PIN method described above. If the client wants to operate in the Registrar role to learn the current AP configuration and optionally, to configure an AP, wpa_supplicant is notified over the control interface, e.g., with wpa_cli: wpa_cli wps_reg (example: wpa_cli wps_reg 02:34:56:78:9a:bc 12345670) This is used to fetch the current AP settings instead of actually changing them. The main difference with the wps_pin command is that wps_reg uses the AP PIN (e.g., from a label on the AP) instead of a PIN generated at the client. In order to change the AP configuration, the new configuration parameters are given to the wps_reg command: wpa_cli wps_reg examples: wpa_cli wps_reg 02:34:56:78:9a:bc 12345670 testing WPA2PSK CCMP 12345678 wpa_cli wps_reg 02:34:56:78:9a:bc 12345670 clear OPEN NONE "" must be one of the following: OPEN WPAPSK WPA2PSK must be one of the following: NONE WEP TKIP CCMP Scanning -------- Scan results ('wpa_cli scan_results' or 'wpa_cli bss ') include a flags field that is used to indicate whether the BSS support WPS. If the AP support WPS, but has not recently activated a Registrar, [WPS] flag will be included. If PIN method has been recently selected, [WPS-PIN] is shown instead. Similarly, [WPS-PBC] is shown if PBC mode is in progress. GUI programs can use these as triggers for suggesting a guided WPS configuration to the user. In addition, control interface monitor events WPS-AP-AVAILABLE{,-PBC,-PIN} can be used to find out if there are WPS enabled APs in scan results without having to go through all the details in the GUI. These notification could be used, e.g., to suggest possible WPS connection to the user. wpa_gui ------- wpa_gui-qt4 directory contains a sample GUI that shows an example of how WPS support can be integrated into the GUI. Its main window has a WPS tab that guides user through WPS registration with automatic AP selection. In addition, it shows how WPS can be started manually by selecting an AP from scan results. Credential processing --------------------- By default, wpa_supplicant processes received credentials and updates its configuration internally. However, it is possible to control these operations from external programs, if desired. This internal processing can be disabled with wps_cred_processing=1 option. When this is used, an external program is responsible for processing the credential attributes and updating wpa_supplicant configuration based on them. Following control interface messages are sent out for external programs: WPS-CRED-RECEIVED For example: <2>WPS-CRED-RECEIVED 100e006f10260001011045000c6a6b6d2d7770732d74657374100300020020100f000200081027004030653462303435366332363666653064333961643135353461316634626637313234333761636664623766333939653534663166316230323061643434386235102000060266a0ee1727 wpa_supplicant as WPS External Registrar (ER) --------------------------------------------- wpa_supplicant can be used as a WPS ER to configure an AP or enroll new Enrollee to join the network. This functionality uses UPnP and requires that a working IP connectivity is available with the AP (this can be either over a wired or wireless connection). Separate wpa_supplicant process can be started for WPS ER operations. A special "none" driver can be used in such a case to indicate that no local network interface is actually controlled. For example, following command could be used to start the ER: wpa_supplicant -Dnone -c er.conf -ieth0 Sample er.conf: ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin device_name=WPS External Registrar wpa_cli commands for ER functionality: wps_er_start [IP address] - start WPS ER functionality - the optional IP address parameter can be used to filter operations only to include a single AP - if run again while ER is active, the stored information (discovered APs and Enrollees) are shown again wps_er_stop - stop WPS ER functionality wps_er_learn - learn AP configuration wps_er_set_config - use AP configuration from a locally configured network (e.g., from wps_reg command); this does not change the AP's configuration, but only prepares a configuration to be used when enrolling a new device to the AP wps_er_config - examples: wps_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 testing WPA2PSK CCMP 12345678 wpa_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 clear OPEN NONE "" must be one of the following: OPEN WPAPSK WPA2PSK must be one of the following: NONE WEP TKIP CCMP wps_er_pbc - accept an Enrollee PBC using External Registrar wps_er_pin [Enrollee MAC address] - add an Enrollee PIN to External Registrar - if Enrollee UUID is not known, "any" can be used to add a wildcard PIN - if the MAC address of the enrollee is known, it should be configured to allow the AP to advertise list of authorized enrollees WPS ER events: WPS_EVENT_ER_AP_ADD - WPS ER discovered an AP WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1 |Very friendly name|Company|Long description of the model|WAP|http://w1.fi/|http://w1.fi/hostapd/ WPS_EVENT_ER_AP_REMOVE - WPS ER removed an AP entry WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002 WPS_EVENT_ER_ENROLLEE_ADD - WPS ER discovered a new Enrollee WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0 pri_dev_type=1-0050F204-1 |Wireless Client|Company|cmodel|123|12345| WPS_EVENT_ER_ENROLLEE_REMOVE - WPS ER removed an Enrollee entry WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333 02:66:a0:ee:17:27 WPS-ER-AP-SETTINGS - WPS ER learned AP settings WPS-ER-AP-SETTINGS uuid=fd91b4ec-e3fa-5891-a57d-8c59efeed1d2 ssid=test-wps auth_type=0x0020 encr_type=0x0008 key=12345678 WPS with NFC ------------ WPS can be used with NFC-based configuration method. An NFC tag containing a password token from the Enrollee can be used to authenticate the connection instead of the PIN. In addition, an NFC tag with a configuration token can be used to transfer AP settings without going through the WPS protocol. When the station acts as an Enrollee, a local NFC tag with a password token can be used by touching the NFC interface of a Registrar. "wps_nfc [BSSID]" command starts WPS protocol run with the local end as the Enrollee using the NFC password token that is either pre-configured in the configuration file (wps_nfc_dev_pw_id, wps_nfc_dh_pubkey, wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with "wps_nfc_token " command. The included nfc_pw_token tool (build with "make nfc_pw_token") can be used to generate NFC password tokens during manufacturing (each station needs to have its own random keys). The "wps_nfc_config_token " command can be used to build an NFC configuration token when wpa_supplicant is controlling an AP interface (AP or P2P GO). The output value from this command is a hexdump of the current AP configuration (WPS parameter requests this to include only the WPS attributes; NDEF parameter requests additional NDEF encapsulation to be included). This data needs to be written to an NFC tag with an external program. Once written, the NFC configuration token can be used to touch an NFC interface on a station to provision the credentials needed to access the network. The "wps_nfc_config_token " command can be used to build an NFC configuration token based on a locally configured network. If the station includes NFC interface and reads an NFC tag with a MIME media type "application/vnd.wfa.wsc", the NDEF message payload (with or without NDEF encapsulation) can be delivered to wpa_supplicant using the following wpa_cli command: wps_nfc_tag_read If the NFC tag contains a configuration token, the network is added to wpa_supplicant configuration. If the NFC tag contains a password token, the token is added to the WPS Registrar component. This information can then be used with wps_reg command (when the NFC password token was from an AP) using a special value "nfc-pw" in place of the PIN parameter. If the ER functionality has been started (wps_er_start), the NFC password token is used to enable enrollment of a new station (that was the source of the NFC password token). "nfc_get_handover_req " command can be used to build the WPS carrier record for a Handover Request Message for connection handover. The first argument selects the format of the output data and the second argument selects which type of connection handover is requested (WPS-CR = Wi-Fi handover as specified in WSC 2.0). "nfc_get_handover_sel [UUID|BSSID]" command can be used to build the contents of a Handover Select Message for connection handover when this does not depend on the contents of the Handover Request Message. The first argument selects the format of the output data and the second argument selects which type of connection handover is requested (WPS = Wi-Fi handover as specified in WSC 2.0). If the options UUID|BSSID argument is included, this is a request to build the handover message for the specified AP when wpa_supplicant is operating as a WPS ER. "nfc_report_handover WPS " can be used as an alternative way for reporting completed NFC connection handover. The first parameter indicates whether the local device initiated or responded to the connection handover and the carrier records are the selected carrier from the handover request and select messages as a hexdump. The "wps_er_nfc_config_token " command can be used to build an NFC configuration token for the specified AP when wpa_supplicant is operating as a WPS ER. The output value from this command is a hexdump of the selected AP configuration (WPS parameter requests this to include only the WPS attributes; NDEF parameter requests additional NDEF encapsulation to be included). This data needs to be written to an NFC tag with an external program. Once written, the NFC configuration token can be used to touch an NFC interface on a station to provision the credentials needed to access the network. wpa_supplicant-2.2/wpa_supplicant/eap_proxy_dummy.mk0000664000175000017500000000000012343617166021010 0ustar jmjmwpa_supplicant-2.2/wpa_supplicant/wpa_priv.c0000664000175000017500000005605612343617166017257 0ustar jmjm/* * WPA Supplicant / privileged helper program * 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" #ifdef __linux__ #include #endif /* __linux__ */ #include #include #include "common.h" #include "eloop.h" #include "common/version.h" #include "drivers/driver.h" #include "l2_packet/l2_packet.h" #include "common/privsep_commands.h" #include "common/ieee802_11_defs.h" struct wpa_priv_interface { struct wpa_priv_interface *next; char *driver_name; char *ifname; char *sock_name; int fd; struct wpa_driver_ops *driver; void *drv_priv; struct sockaddr_un drv_addr; int wpas_registered; /* TODO: add support for multiple l2 connections */ struct l2_packet_data *l2; struct sockaddr_un l2_addr; }; static void wpa_priv_cmd_register(struct wpa_priv_interface *iface, struct sockaddr_un *from) { if (iface->drv_priv) { wpa_printf(MSG_DEBUG, "Cleaning up forgotten driver instance"); if (iface->driver->deinit) iface->driver->deinit(iface->drv_priv); iface->drv_priv = NULL; iface->wpas_registered = 0; } if (iface->l2) { wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet " "instance"); l2_packet_deinit(iface->l2); iface->l2 = NULL; } if (iface->driver->init == NULL) return; iface->drv_priv = iface->driver->init(iface, iface->ifname); if (iface->drv_priv == NULL) { wpa_printf(MSG_DEBUG, "Failed to initialize driver wrapper"); return; } wpa_printf(MSG_DEBUG, "Driver wrapper '%s' initialized for interface " "'%s'", iface->driver_name, iface->ifname); os_memcpy(&iface->drv_addr, from, sizeof(iface->drv_addr)); iface->wpas_registered = 1; if (iface->driver->set_param && iface->driver->set_param(iface->drv_priv, NULL) < 0) { wpa_printf(MSG_ERROR, "Driver interface rejected param"); } } static void wpa_priv_cmd_unregister(struct wpa_priv_interface *iface, struct sockaddr_un *from) { if (iface->drv_priv) { if (iface->driver->deinit) iface->driver->deinit(iface->drv_priv); iface->drv_priv = NULL; iface->wpas_registered = 0; } } static void wpa_priv_cmd_scan(struct wpa_priv_interface *iface, char *buf, size_t len) { struct wpa_driver_scan_params params; if (iface->drv_priv == NULL) return; os_memset(¶ms, 0, sizeof(params)); if (len) { params.ssids[0].ssid = (u8 *) buf; params.ssids[0].ssid_len = len; params.num_ssids = 1; } if (iface->driver->scan2) iface->driver->scan2(iface->drv_priv, ¶ms); } static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface, struct sockaddr_un *from) { struct wpa_scan_results *res; u8 *buf = NULL, *pos, *end; int val; size_t i; res = iface->driver->get_scan_results2(iface->drv_priv); if (res == NULL) goto fail; buf = os_malloc(60000); if (buf == NULL) goto fail; pos = buf; end = buf + 60000; val = res->num; os_memcpy(pos, &val, sizeof(int)); pos += sizeof(int); for (i = 0; i < res->num; i++) { struct wpa_scan_res *r = res->res[i]; val = sizeof(*r) + r->ie_len; if (end - pos < (int) sizeof(int) + val) break; os_memcpy(pos, &val, sizeof(int)); pos += sizeof(int); os_memcpy(pos, r, val); pos += val; } sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from, sizeof(*from)); os_free(buf); wpa_scan_results_free(res); return; fail: os_free(buf); wpa_scan_results_free(res); sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); } static void wpa_priv_cmd_get_scan_results(struct wpa_priv_interface *iface, struct sockaddr_un *from) { if (iface->drv_priv == NULL) return; if (iface->driver->get_scan_results2) wpa_priv_get_scan_results2(iface, from); else sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); } static void wpa_priv_cmd_associate(struct wpa_priv_interface *iface, void *buf, size_t len) { struct wpa_driver_associate_params params; struct privsep_cmd_associate *assoc; u8 *bssid; int res; if (iface->drv_priv == NULL || iface->driver->associate == NULL) return; if (len < sizeof(*assoc)) { wpa_printf(MSG_DEBUG, "Invalid association request"); return; } assoc = buf; if (sizeof(*assoc) + assoc->wpa_ie_len > len) { wpa_printf(MSG_DEBUG, "Association request overflow"); return; } os_memset(¶ms, 0, sizeof(params)); bssid = assoc->bssid; if (bssid[0] | bssid[1] | bssid[2] | bssid[3] | bssid[4] | bssid[5]) params.bssid = bssid; params.ssid = assoc->ssid; if (assoc->ssid_len > 32) return; params.ssid_len = assoc->ssid_len; params.freq = assoc->freq; if (assoc->wpa_ie_len) { params.wpa_ie = (u8 *) (assoc + 1); params.wpa_ie_len = assoc->wpa_ie_len; } params.pairwise_suite = assoc->pairwise_suite; params.group_suite = assoc->group_suite; params.key_mgmt_suite = assoc->key_mgmt_suite; params.auth_alg = assoc->auth_alg; params.mode = assoc->mode; res = iface->driver->associate(iface->drv_priv, ¶ms); wpa_printf(MSG_DEBUG, "drv->associate: res=%d", res); } static void wpa_priv_cmd_get_bssid(struct wpa_priv_interface *iface, struct sockaddr_un *from) { u8 bssid[ETH_ALEN]; if (iface->drv_priv == NULL) goto fail; if (iface->driver->get_bssid == NULL || iface->driver->get_bssid(iface->drv_priv, bssid) < 0) goto fail; sendto(iface->fd, bssid, ETH_ALEN, 0, (struct sockaddr *) from, sizeof(*from)); return; fail: sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); } static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface, struct sockaddr_un *from) { u8 ssid[sizeof(int) + 32]; int res; if (iface->drv_priv == NULL) goto fail; if (iface->driver->get_ssid == NULL) goto fail; res = iface->driver->get_ssid(iface->drv_priv, &ssid[sizeof(int)]); if (res < 0 || res > 32) goto fail; os_memcpy(ssid, &res, sizeof(int)); sendto(iface->fd, ssid, sizeof(ssid), 0, (struct sockaddr *) from, sizeof(*from)); return; fail: sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); } static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface, void *buf, size_t len) { struct privsep_cmd_set_key *params; int res; if (iface->drv_priv == NULL || iface->driver->set_key == NULL) return; if (len != sizeof(*params)) { wpa_printf(MSG_DEBUG, "Invalid set_key request"); return; } params = buf; res = iface->driver->set_key(iface->ifname, iface->drv_priv, params->alg, params->addr, params->key_idx, params->set_tx, params->seq_len ? params->seq : NULL, params->seq_len, params->key_len ? params->key : NULL, params->key_len); wpa_printf(MSG_DEBUG, "drv->set_key: res=%d", res); } static void wpa_priv_cmd_get_capa(struct wpa_priv_interface *iface, struct sockaddr_un *from) { struct wpa_driver_capa capa; if (iface->drv_priv == NULL) goto fail; if (iface->driver->get_capa == NULL || iface->driver->get_capa(iface->drv_priv, &capa) < 0) goto fail; sendto(iface->fd, &capa, sizeof(capa), 0, (struct sockaddr *) from, sizeof(*from)); return; fail: sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); } static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { struct wpa_priv_interface *iface = ctx; struct msghdr msg; struct iovec io[2]; io[0].iov_base = (u8 *) src_addr; io[0].iov_len = ETH_ALEN; io[1].iov_base = (u8 *) buf; io[1].iov_len = len; os_memset(&msg, 0, sizeof(msg)); msg.msg_iov = io; msg.msg_iovlen = 2; msg.msg_name = &iface->l2_addr; msg.msg_namelen = sizeof(iface->l2_addr); if (sendmsg(iface->fd, &msg, 0) < 0) { perror("sendmsg(l2 rx)"); } } static void wpa_priv_cmd_l2_register(struct wpa_priv_interface *iface, struct sockaddr_un *from, void *buf, size_t len) { int *reg_cmd = buf; u8 own_addr[ETH_ALEN]; int res; u16 proto; if (len != 2 * sizeof(int)) { wpa_printf(MSG_DEBUG, "Invalid l2_register length %lu", (unsigned long) len); return; } proto = reg_cmd[0]; if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) { wpa_printf(MSG_DEBUG, "Refused l2_packet connection for " "ethertype 0x%x", proto); return; } if (iface->l2) { wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet " "instance"); l2_packet_deinit(iface->l2); iface->l2 = NULL; } os_memcpy(&iface->l2_addr, from, sizeof(iface->l2_addr)); iface->l2 = l2_packet_init(iface->ifname, NULL, proto, wpa_priv_l2_rx, iface, reg_cmd[1]); if (iface->l2 == NULL) { wpa_printf(MSG_DEBUG, "Failed to initialize l2_packet " "instance for protocol %d", proto); return; } if (l2_packet_get_own_addr(iface->l2, own_addr) < 0) { wpa_printf(MSG_DEBUG, "Failed to get own address from " "l2_packet"); l2_packet_deinit(iface->l2); iface->l2 = NULL; return; } res = sendto(iface->fd, own_addr, ETH_ALEN, 0, (struct sockaddr *) from, sizeof(*from)); wpa_printf(MSG_DEBUG, "L2 registration: res=%d", res); } static void wpa_priv_cmd_l2_unregister(struct wpa_priv_interface *iface, struct sockaddr_un *from) { if (iface->l2) { l2_packet_deinit(iface->l2); iface->l2 = NULL; } } static void wpa_priv_cmd_l2_notify_auth_start(struct wpa_priv_interface *iface, struct sockaddr_un *from) { if (iface->l2) l2_packet_notify_auth_start(iface->l2); } static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface, struct sockaddr_un *from, void *buf, size_t len) { u8 *dst_addr; u16 proto; int res; if (iface->l2 == NULL) return; if (len < ETH_ALEN + 2) { wpa_printf(MSG_DEBUG, "Too short L2 send packet (len=%lu)", (unsigned long) len); return; } dst_addr = buf; os_memcpy(&proto, buf + ETH_ALEN, 2); if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) { wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype " "0x%x", proto); return; } res = l2_packet_send(iface->l2, dst_addr, proto, buf + ETH_ALEN + 2, len - ETH_ALEN - 2); wpa_printf(MSG_DEBUG, "L2 send: res=%d", res); } static void wpa_priv_cmd_set_country(struct wpa_priv_interface *iface, char *buf) { if (iface->drv_priv == NULL || iface->driver->set_country == NULL || *buf == '\0') return; iface->driver->set_country(iface->drv_priv, buf); } static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx) { struct wpa_priv_interface *iface = eloop_ctx; char buf[2000], *pos; void *cmd_buf; size_t cmd_len; int res, cmd; struct sockaddr_un from; socklen_t fromlen = sizeof(from); res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from, &fromlen); if (res < 0) { perror("recvfrom"); return; } if (res < (int) sizeof(int)) { wpa_printf(MSG_DEBUG, "Too short command (len=%d)", res); return; } os_memcpy(&cmd, buf, sizeof(int)); wpa_printf(MSG_DEBUG, "Command %d for interface %s", cmd, iface->ifname); cmd_buf = &buf[sizeof(int)]; cmd_len = res - sizeof(int); switch (cmd) { case PRIVSEP_CMD_REGISTER: wpa_priv_cmd_register(iface, &from); break; case PRIVSEP_CMD_UNREGISTER: wpa_priv_cmd_unregister(iface, &from); break; case PRIVSEP_CMD_SCAN: wpa_priv_cmd_scan(iface, cmd_buf, cmd_len); break; case PRIVSEP_CMD_GET_SCAN_RESULTS: wpa_priv_cmd_get_scan_results(iface, &from); break; case PRIVSEP_CMD_ASSOCIATE: wpa_priv_cmd_associate(iface, cmd_buf, cmd_len); break; case PRIVSEP_CMD_GET_BSSID: wpa_priv_cmd_get_bssid(iface, &from); break; case PRIVSEP_CMD_GET_SSID: wpa_priv_cmd_get_ssid(iface, &from); break; case PRIVSEP_CMD_SET_KEY: wpa_priv_cmd_set_key(iface, cmd_buf, cmd_len); break; case PRIVSEP_CMD_GET_CAPA: wpa_priv_cmd_get_capa(iface, &from); break; case PRIVSEP_CMD_L2_REGISTER: wpa_priv_cmd_l2_register(iface, &from, cmd_buf, cmd_len); break; case PRIVSEP_CMD_L2_UNREGISTER: wpa_priv_cmd_l2_unregister(iface, &from); break; case PRIVSEP_CMD_L2_NOTIFY_AUTH_START: wpa_priv_cmd_l2_notify_auth_start(iface, &from); break; case PRIVSEP_CMD_L2_SEND: wpa_priv_cmd_l2_send(iface, &from, cmd_buf, cmd_len); break; case PRIVSEP_CMD_SET_COUNTRY: pos = cmd_buf; if (pos + cmd_len >= buf + sizeof(buf)) break; pos[cmd_len] = '\0'; wpa_priv_cmd_set_country(iface, pos); break; } } static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface) { if (iface->drv_priv && iface->driver->deinit) iface->driver->deinit(iface->drv_priv); if (iface->fd >= 0) { eloop_unregister_read_sock(iface->fd); close(iface->fd); unlink(iface->sock_name); } if (iface->l2) l2_packet_deinit(iface->l2); os_free(iface->ifname); os_free(iface->driver_name); os_free(iface->sock_name); os_free(iface); } static struct wpa_priv_interface * wpa_priv_interface_init(const char *dir, const char *params) { struct wpa_priv_interface *iface; char *pos; size_t len; struct sockaddr_un addr; int i; pos = os_strchr(params, ':'); if (pos == NULL) return NULL; iface = os_zalloc(sizeof(*iface)); if (iface == NULL) return NULL; iface->fd = -1; len = pos - params; iface->driver_name = dup_binstr(params, len); if (iface->driver_name == NULL) { wpa_priv_interface_deinit(iface); return NULL; } for (i = 0; wpa_drivers[i]; i++) { if (os_strcmp(iface->driver_name, wpa_drivers[i]->name) == 0) { iface->driver = wpa_drivers[i]; break; } } if (iface->driver == NULL) { wpa_printf(MSG_ERROR, "Unsupported driver '%s'", iface->driver_name); wpa_priv_interface_deinit(iface); return NULL; } pos++; iface->ifname = os_strdup(pos); if (iface->ifname == NULL) { wpa_priv_interface_deinit(iface); return NULL; } len = os_strlen(dir) + 1 + os_strlen(iface->ifname); iface->sock_name = os_malloc(len + 1); if (iface->sock_name == NULL) { wpa_priv_interface_deinit(iface); return NULL; } os_snprintf(iface->sock_name, len + 1, "%s/%s", dir, iface->ifname); if (os_strlen(iface->sock_name) >= sizeof(addr.sun_path)) { wpa_priv_interface_deinit(iface); return NULL; } iface->fd = socket(PF_UNIX, SOCK_DGRAM, 0); if (iface->fd < 0) { perror("socket(PF_UNIX)"); wpa_priv_interface_deinit(iface); return NULL; } os_memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; os_strlcpy(addr.sun_path, iface->sock_name, sizeof(addr.sun_path)); if (bind(iface->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { wpa_printf(MSG_DEBUG, "bind(PF_UNIX) failed: %s", strerror(errno)); if (connect(iface->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { wpa_printf(MSG_DEBUG, "Socket exists, but does not " "allow connections - assuming it was " "leftover from forced program termination"); if (unlink(iface->sock_name) < 0) { perror("unlink[ctrl_iface]"); wpa_printf(MSG_ERROR, "Could not unlink " "existing ctrl_iface socket '%s'", iface->sock_name); goto fail; } if (bind(iface->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("wpa-priv-iface-init: bind(PF_UNIX)"); goto fail; } wpa_printf(MSG_DEBUG, "Successfully replaced leftover " "socket '%s'", iface->sock_name); } else { wpa_printf(MSG_INFO, "Socket exists and seems to be " "in use - cannot override it"); wpa_printf(MSG_INFO, "Delete '%s' manually if it is " "not used anymore", iface->sock_name); goto fail; } } if (chmod(iface->sock_name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) { perror("chmod"); goto fail; } eloop_register_read_sock(iface->fd, wpa_priv_receive, iface, NULL); return iface; fail: wpa_priv_interface_deinit(iface); return NULL; } static int wpa_priv_send_event(struct wpa_priv_interface *iface, int event, const void *data, size_t data_len) { struct msghdr msg; struct iovec io[2]; io[0].iov_base = &event; io[0].iov_len = sizeof(event); io[1].iov_base = (u8 *) data; io[1].iov_len = data_len; os_memset(&msg, 0, sizeof(msg)); msg.msg_iov = io; msg.msg_iovlen = data ? 2 : 1; msg.msg_name = &iface->drv_addr; msg.msg_namelen = sizeof(iface->drv_addr); if (sendmsg(iface->fd, &msg, 0) < 0) { perror("sendmsg(wpas_socket)"); return -1; } return 0; } static void wpa_priv_send_assoc(struct wpa_priv_interface *iface, int event, union wpa_event_data *data) { size_t buflen = 3 * sizeof(int); u8 *buf, *pos; int len; if (data) { buflen += data->assoc_info.req_ies_len + data->assoc_info.resp_ies_len + data->assoc_info.beacon_ies_len; } buf = os_malloc(buflen); if (buf == NULL) return; pos = buf; if (data && data->assoc_info.req_ies) { len = data->assoc_info.req_ies_len; os_memcpy(pos, &len, sizeof(int)); pos += sizeof(int); os_memcpy(pos, data->assoc_info.req_ies, len); pos += len; } else { len = 0; os_memcpy(pos, &len, sizeof(int)); pos += sizeof(int); } if (data && data->assoc_info.resp_ies) { len = data->assoc_info.resp_ies_len; os_memcpy(pos, &len, sizeof(int)); pos += sizeof(int); os_memcpy(pos, data->assoc_info.resp_ies, len); pos += len; } else { len = 0; os_memcpy(pos, &len, sizeof(int)); pos += sizeof(int); } if (data && data->assoc_info.beacon_ies) { len = data->assoc_info.beacon_ies_len; os_memcpy(pos, &len, sizeof(int)); pos += sizeof(int); os_memcpy(pos, data->assoc_info.beacon_ies, len); pos += len; } else { len = 0; os_memcpy(pos, &len, sizeof(int)); pos += sizeof(int); } wpa_priv_send_event(iface, event, buf, buflen); os_free(buf); } static void wpa_priv_send_interface_status(struct wpa_priv_interface *iface, union wpa_event_data *data) { int ievent; size_t len, maxlen; u8 *buf; char *ifname; if (data == NULL) return; ievent = data->interface_status.ievent; maxlen = sizeof(data->interface_status.ifname); ifname = data->interface_status.ifname; for (len = 0; len < maxlen && ifname[len]; len++) ; buf = os_malloc(sizeof(int) + len); if (buf == NULL) return; os_memcpy(buf, &ievent, sizeof(int)); os_memcpy(buf + sizeof(int), ifname, len); wpa_priv_send_event(iface, PRIVSEP_EVENT_INTERFACE_STATUS, buf, sizeof(int) + len); os_free(buf); } static void wpa_priv_send_ft_response(struct wpa_priv_interface *iface, union wpa_event_data *data) { size_t len; u8 *buf, *pos; if (data == NULL || data->ft_ies.ies == NULL) return; len = sizeof(int) + ETH_ALEN + data->ft_ies.ies_len; buf = os_malloc(len); if (buf == NULL) return; pos = buf; os_memcpy(pos, &data->ft_ies.ft_action, sizeof(int)); pos += sizeof(int); os_memcpy(pos, data->ft_ies.target_ap, ETH_ALEN); pos += ETH_ALEN; os_memcpy(pos, data->ft_ies.ies, data->ft_ies.ies_len); wpa_priv_send_event(iface, PRIVSEP_EVENT_FT_RESPONSE, buf, len); os_free(buf); } void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { struct wpa_priv_interface *iface = ctx; wpa_printf(MSG_DEBUG, "%s - event=%d", __func__, event); if (!iface->wpas_registered) { wpa_printf(MSG_DEBUG, "Driver event received, but " "wpa_supplicant not registered"); return; } switch (event) { case EVENT_ASSOC: wpa_priv_send_assoc(iface, PRIVSEP_EVENT_ASSOC, data); break; case EVENT_DISASSOC: wpa_priv_send_event(iface, PRIVSEP_EVENT_DISASSOC, NULL, 0); break; case EVENT_ASSOCINFO: if (data == NULL) return; wpa_priv_send_assoc(iface, PRIVSEP_EVENT_ASSOCINFO, data); break; case EVENT_MICHAEL_MIC_FAILURE: if (data == NULL) return; wpa_priv_send_event(iface, PRIVSEP_EVENT_MICHAEL_MIC_FAILURE, &data->michael_mic_failure.unicast, sizeof(int)); break; case EVENT_SCAN_RESULTS: wpa_priv_send_event(iface, PRIVSEP_EVENT_SCAN_RESULTS, NULL, 0); break; case EVENT_INTERFACE_STATUS: wpa_priv_send_interface_status(iface, data); break; case EVENT_PMKID_CANDIDATE: if (data == NULL) return; wpa_priv_send_event(iface, PRIVSEP_EVENT_PMKID_CANDIDATE, &data->pmkid_candidate, sizeof(struct pmkid_candidate)); break; case EVENT_STKSTART: if (data == NULL) return; wpa_priv_send_event(iface, PRIVSEP_EVENT_STKSTART, &data->stkstart.peer, ETH_ALEN); break; case EVENT_FT_RESPONSE: wpa_priv_send_ft_response(iface, data); break; default: wpa_printf(MSG_DEBUG, "Unsupported driver event %d - TODO", event); break; } } void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { struct wpa_priv_interface *iface = ctx; struct msghdr msg; struct iovec io[3]; int event = PRIVSEP_EVENT_RX_EAPOL; wpa_printf(MSG_DEBUG, "RX EAPOL from driver"); io[0].iov_base = &event; io[0].iov_len = sizeof(event); io[1].iov_base = (u8 *) src_addr; io[1].iov_len = ETH_ALEN; io[2].iov_base = (u8 *) buf; io[2].iov_len = len; os_memset(&msg, 0, sizeof(msg)); msg.msg_iov = io; msg.msg_iovlen = 3; msg.msg_name = &iface->drv_addr; msg.msg_namelen = sizeof(iface->drv_addr); if (sendmsg(iface->fd, &msg, 0) < 0) perror("sendmsg(wpas_socket)"); } static void wpa_priv_terminate(int sig, void *signal_ctx) { wpa_printf(MSG_DEBUG, "wpa_priv termination requested"); eloop_terminate(); } static void wpa_priv_fd_workaround(void) { #ifdef __linux__ int s, i; /* When started from pcmcia-cs scripts, wpa_supplicant might start with * fd 0, 1, and 2 closed. This will cause some issues because many * places in wpa_supplicant are still printing out to stdout. As a * workaround, make sure that fd's 0, 1, and 2 are not used for other * sockets. */ for (i = 0; i < 3; i++) { s = open("/dev/null", O_RDWR); if (s > 2) { close(s); break; } } #endif /* __linux__ */ } static void usage(void) { printf("wpa_priv v" VERSION_STR "\n" "Copyright (c) 2007-2009, Jouni Malinen and " "contributors\n" "\n" "usage:\n" " wpa_priv [-Bdd] [-P] " "[driver:ifname ...]\n"); } int main(int argc, char *argv[]) { int c, i; int ret = -1; char *pid_file = NULL; int daemonize = 0; char *ctrl_dir = "/var/run/wpa_priv"; struct wpa_priv_interface *interfaces = NULL, *iface; if (os_program_init()) return -1; wpa_priv_fd_workaround(); for (;;) { c = getopt(argc, argv, "Bc:dP:"); if (c < 0) break; switch (c) { case 'B': daemonize++; break; case 'c': ctrl_dir = optarg; break; case 'd': wpa_debug_level--; break; case 'P': pid_file = os_rel2abs_path(optarg); break; default: usage(); goto out; } } if (optind >= argc) { usage(); goto out; } wpa_printf(MSG_DEBUG, "wpa_priv control directory: '%s'", ctrl_dir); if (eloop_init()) { wpa_printf(MSG_ERROR, "Failed to initialize event loop"); goto out; } for (i = optind; i < argc; i++) { wpa_printf(MSG_DEBUG, "Adding driver:interface %s", argv[i]); iface = wpa_priv_interface_init(ctrl_dir, argv[i]); if (iface == NULL) goto out; iface->next = interfaces; interfaces = iface; } if (daemonize && os_daemonize(pid_file)) goto out; eloop_register_signal_terminate(wpa_priv_terminate, NULL); eloop_run(); ret = 0; out: iface = interfaces; while (iface) { struct wpa_priv_interface *prev = iface; iface = iface->next; wpa_priv_interface_deinit(prev); } eloop_destroy(); os_daemonize_terminate(pid_file); os_free(pid_file); os_program_deinit(); return ret; } wpa_supplicant-2.2/wpa_supplicant/driver_i.h0000664000175000017500000005342412343617166017234 0ustar jmjm/* * wpa_supplicant - Internal driver interface wrappers * Copyright (c) 2003-2009, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef DRIVER_I_H #define DRIVER_I_H #include "drivers/driver.h" /* driver_ops */ static inline void * wpa_drv_init(struct wpa_supplicant *wpa_s, const char *ifname) { if (wpa_s->driver->init2) return wpa_s->driver->init2(wpa_s, ifname, wpa_s->global_drv_priv); if (wpa_s->driver->init) { return wpa_s->driver->init(wpa_s, ifname); } return NULL; } static inline void wpa_drv_deinit(struct wpa_supplicant *wpa_s) { if (wpa_s->driver->deinit) wpa_s->driver->deinit(wpa_s->drv_priv); } static inline int wpa_drv_set_param(struct wpa_supplicant *wpa_s, const char *param) { if (wpa_s->driver->set_param) return wpa_s->driver->set_param(wpa_s->drv_priv, param); return 0; } static inline int wpa_drv_set_countermeasures(struct wpa_supplicant *wpa_s, int enabled) { if (wpa_s->driver->set_countermeasures) { return wpa_s->driver->set_countermeasures(wpa_s->drv_priv, enabled); } return -1; } static inline int wpa_drv_authenticate(struct wpa_supplicant *wpa_s, struct wpa_driver_auth_params *params) { if (wpa_s->driver->authenticate) return wpa_s->driver->authenticate(wpa_s->drv_priv, params); return -1; } static inline int wpa_drv_associate(struct wpa_supplicant *wpa_s, struct wpa_driver_associate_params *params) { if (wpa_s->driver->associate) { return wpa_s->driver->associate(wpa_s->drv_priv, params); } return -1; } static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params) { if (wpa_s->driver->scan2) return wpa_s->driver->scan2(wpa_s->drv_priv, params); return -1; } static inline int wpa_drv_sched_scan(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params, u32 interval) { if (wpa_s->driver->sched_scan) return wpa_s->driver->sched_scan(wpa_s->drv_priv, params, interval); return -1; } static inline int wpa_drv_stop_sched_scan(struct wpa_supplicant *wpa_s) { if (wpa_s->driver->stop_sched_scan) return wpa_s->driver->stop_sched_scan(wpa_s->drv_priv); return -1; } static inline struct wpa_scan_results * wpa_drv_get_scan_results2( struct wpa_supplicant *wpa_s) { if (wpa_s->driver->get_scan_results2) return wpa_s->driver->get_scan_results2(wpa_s->drv_priv); return NULL; } static inline int wpa_drv_get_bssid(struct wpa_supplicant *wpa_s, u8 *bssid) { if (wpa_s->driver->get_bssid) { return wpa_s->driver->get_bssid(wpa_s->drv_priv, bssid); } return -1; } static inline int wpa_drv_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid) { if (wpa_s->driver->get_ssid) { return wpa_s->driver->get_ssid(wpa_s->drv_priv, ssid); } return -1; } static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, 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) { if (alg != WPA_ALG_NONE) { if (key_idx >= 0 && key_idx <= 6) wpa_s->keys_cleared &= ~BIT(key_idx); else wpa_s->keys_cleared = 0; } if (wpa_s->driver->set_key) { return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv, alg, addr, key_idx, set_tx, seq, seq_len, key, key_len); } return -1; } static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s, const u8 *addr, int reason_code) { if (wpa_s->driver->sta_deauth) { return wpa_s->driver->sta_deauth(wpa_s->drv_priv, wpa_s->own_addr, addr, reason_code); } return -1; } static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *addr, int reason_code) { if (wpa_s->driver->deauthenticate) { return wpa_s->driver->deauthenticate(wpa_s->drv_priv, addr, reason_code); } return -1; } static inline int wpa_drv_add_pmkid(struct wpa_supplicant *wpa_s, const u8 *bssid, const u8 *pmkid) { if (wpa_s->driver->add_pmkid) { return wpa_s->driver->add_pmkid(wpa_s->drv_priv, bssid, pmkid); } return -1; } static inline int wpa_drv_remove_pmkid(struct wpa_supplicant *wpa_s, const u8 *bssid, const u8 *pmkid) { if (wpa_s->driver->remove_pmkid) { return wpa_s->driver->remove_pmkid(wpa_s->drv_priv, bssid, pmkid); } return -1; } static inline int wpa_drv_flush_pmkid(struct wpa_supplicant *wpa_s) { if (wpa_s->driver->flush_pmkid) { return wpa_s->driver->flush_pmkid(wpa_s->drv_priv); } return -1; } static inline int wpa_drv_get_capa(struct wpa_supplicant *wpa_s, struct wpa_driver_capa *capa) { if (wpa_s->driver->get_capa) { return wpa_s->driver->get_capa(wpa_s->drv_priv, capa); } return -1; } static inline void wpa_drv_poll(struct wpa_supplicant *wpa_s) { if (wpa_s->driver->poll) { wpa_s->driver->poll(wpa_s->drv_priv); } } static inline const char * wpa_drv_get_ifname(struct wpa_supplicant *wpa_s) { if (wpa_s->driver->get_ifname) { return wpa_s->driver->get_ifname(wpa_s->drv_priv); } return NULL; } static inline const char * wpa_driver_get_radio_name(struct wpa_supplicant *wpa_s) { if (wpa_s->driver->get_radio_name) return wpa_s->driver->get_radio_name(wpa_s->drv_priv); return NULL; } static inline const u8 * wpa_drv_get_mac_addr(struct wpa_supplicant *wpa_s) { if (wpa_s->driver->get_mac_addr) { return wpa_s->driver->get_mac_addr(wpa_s->drv_priv); } return NULL; } static inline int wpa_drv_send_eapol(struct wpa_supplicant *wpa_s, const u8 *dst, u16 proto, const u8 *data, size_t data_len) { if (wpa_s->driver->send_eapol) return wpa_s->driver->send_eapol(wpa_s->drv_priv, dst, proto, data, data_len); return -1; } static inline int wpa_drv_set_operstate(struct wpa_supplicant *wpa_s, int state) { if (wpa_s->driver->set_operstate) return wpa_s->driver->set_operstate(wpa_s->drv_priv, state); return 0; } static inline int wpa_drv_mlme_setprotection(struct wpa_supplicant *wpa_s, const u8 *addr, int protect_type, int key_type) { if (wpa_s->driver->mlme_setprotection) return wpa_s->driver->mlme_setprotection(wpa_s->drv_priv, addr, protect_type, key_type); return 0; } static inline struct hostapd_hw_modes * wpa_drv_get_hw_feature_data(struct wpa_supplicant *wpa_s, u16 *num_modes, u16 *flags) { if (wpa_s->driver->get_hw_feature_data) return wpa_s->driver->get_hw_feature_data(wpa_s->drv_priv, num_modes, flags); return NULL; } static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s, const char *alpha2) { if (wpa_s->driver->set_country) return wpa_s->driver->set_country(wpa_s->drv_priv, alpha2); return 0; } static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s, const u8 *data, size_t data_len, int noack) { if (wpa_s->driver->send_mlme) return wpa_s->driver->send_mlme(wpa_s->drv_priv, data, data_len, noack); return -1; } static inline int wpa_drv_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, const u8 *ies, size_t ies_len) { if (wpa_s->driver->update_ft_ies) return wpa_s->driver->update_ft_ies(wpa_s->drv_priv, md, ies, ies_len); return -1; } static inline int wpa_drv_send_ft_action(struct wpa_supplicant *wpa_s, u8 action, const u8 *target_ap, const u8 *ies, size_t ies_len) { if (wpa_s->driver->send_ft_action) return wpa_s->driver->send_ft_action(wpa_s->drv_priv, action, target_ap, ies, ies_len); return -1; } static inline int wpa_drv_set_ap(struct wpa_supplicant *wpa_s, struct wpa_driver_ap_params *params) { if (wpa_s->driver->set_ap) return wpa_s->driver->set_ap(wpa_s->drv_priv, params); return -1; } static inline int wpa_drv_sta_add(struct wpa_supplicant *wpa_s, struct hostapd_sta_add_params *params) { if (wpa_s->driver->sta_add) return wpa_s->driver->sta_add(wpa_s->drv_priv, params); return -1; } static inline int wpa_drv_sta_remove(struct wpa_supplicant *wpa_s, const u8 *addr) { if (wpa_s->driver->sta_remove) return wpa_s->driver->sta_remove(wpa_s->drv_priv, addr); return -1; } static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *data, size_t data_len, int encrypt, const u8 *own_addr, u32 flags) { if (wpa_s->driver->hapd_send_eapol) return wpa_s->driver->hapd_send_eapol(wpa_s->drv_priv, addr, data, data_len, encrypt, own_addr, flags); return -1; } static inline int wpa_drv_sta_set_flags(struct wpa_supplicant *wpa_s, const u8 *addr, int total_flags, int flags_or, int flags_and) { if (wpa_s->driver->sta_set_flags) return wpa_s->driver->sta_set_flags(wpa_s->drv_priv, addr, total_flags, flags_or, flags_and); return -1; } static inline int wpa_drv_set_supp_port(struct wpa_supplicant *wpa_s, int authorized) { if (wpa_s->driver->set_supp_port) { return wpa_s->driver->set_supp_port(wpa_s->drv_priv, authorized); } return 0; } static inline int wpa_drv_send_action(struct wpa_supplicant *wpa_s, unsigned int freq, unsigned int wait, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *data, size_t data_len, int no_cck) { if (wpa_s->driver->send_action) return wpa_s->driver->send_action(wpa_s->drv_priv, freq, wait, dst, src, bssid, data, data_len, no_cck); return -1; } static inline void wpa_drv_send_action_cancel_wait(struct wpa_supplicant *wpa_s) { if (wpa_s->driver->send_action_cancel_wait) wpa_s->driver->send_action_cancel_wait(wpa_s->drv_priv); } static inline int wpa_drv_set_freq(struct wpa_supplicant *wpa_s, struct hostapd_freq_params *freq) { if (wpa_s->driver->set_freq) return wpa_s->driver->set_freq(wpa_s->drv_priv, freq); return -1; } static inline int wpa_drv_if_add(struct wpa_supplicant *wpa_s, enum wpa_driver_if_type type, const char *ifname, const u8 *addr, void *bss_ctx, char *force_ifname, u8 *if_addr, const char *bridge) { if (wpa_s->driver->if_add) return wpa_s->driver->if_add(wpa_s->drv_priv, type, ifname, addr, bss_ctx, NULL, force_ifname, if_addr, bridge, 0); return -1; } static inline int wpa_drv_if_remove(struct wpa_supplicant *wpa_s, enum wpa_driver_if_type type, const char *ifname) { if (wpa_s->driver->if_remove) return wpa_s->driver->if_remove(wpa_s->drv_priv, type, ifname); return -1; } static inline int wpa_drv_remain_on_channel(struct wpa_supplicant *wpa_s, unsigned int freq, unsigned int duration) { if (wpa_s->driver->remain_on_channel) return wpa_s->driver->remain_on_channel(wpa_s->drv_priv, freq, duration); return -1; } static inline int wpa_drv_cancel_remain_on_channel( struct wpa_supplicant *wpa_s) { if (wpa_s->driver->cancel_remain_on_channel) return wpa_s->driver->cancel_remain_on_channel( wpa_s->drv_priv); return -1; } static inline int wpa_drv_probe_req_report(struct wpa_supplicant *wpa_s, int report) { if (wpa_s->driver->probe_req_report) return wpa_s->driver->probe_req_report(wpa_s->drv_priv, report); return -1; } static inline int wpa_drv_deinit_ap(struct wpa_supplicant *wpa_s) { if (wpa_s->driver->deinit_ap) return wpa_s->driver->deinit_ap(wpa_s->drv_priv); return 0; } static inline int wpa_drv_deinit_p2p_cli(struct wpa_supplicant *wpa_s) { if (wpa_s->driver->deinit_p2p_cli) return wpa_s->driver->deinit_p2p_cli(wpa_s->drv_priv); return 0; } static inline void wpa_drv_suspend(struct wpa_supplicant *wpa_s) { if (wpa_s->driver->suspend) wpa_s->driver->suspend(wpa_s->drv_priv); } static inline void wpa_drv_resume(struct wpa_supplicant *wpa_s) { if (wpa_s->driver->resume) wpa_s->driver->resume(wpa_s->drv_priv); } static inline int wpa_drv_signal_monitor(struct wpa_supplicant *wpa_s, int threshold, int hysteresis) { if (wpa_s->driver->signal_monitor) return wpa_s->driver->signal_monitor(wpa_s->drv_priv, threshold, hysteresis); return -1; } static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s, struct wpa_signal_info *si) { if (wpa_s->driver->signal_poll) return wpa_s->driver->signal_poll(wpa_s->drv_priv, si); return -1; } static inline int wpa_drv_pktcnt_poll(struct wpa_supplicant *wpa_s, struct hostap_sta_driver_data *sta) { if (wpa_s->driver->read_sta_data) return wpa_s->driver->read_sta_data(wpa_s->drv_priv, sta, wpa_s->bssid); return -1; } static inline int wpa_drv_set_ap_wps_ie(struct wpa_supplicant *wpa_s, const struct wpabuf *beacon, const struct wpabuf *proberesp, const struct wpabuf *assocresp) { if (!wpa_s->driver->set_ap_wps_ie) return -1; return wpa_s->driver->set_ap_wps_ie(wpa_s->drv_priv, beacon, proberesp, assocresp); } static inline int wpa_drv_shared_freq(struct wpa_supplicant *wpa_s) { if (!wpa_s->driver->shared_freq) return -1; return wpa_s->driver->shared_freq(wpa_s->drv_priv); } static inline int wpa_drv_get_noa(struct wpa_supplicant *wpa_s, u8 *buf, size_t buf_len) { if (!wpa_s->driver->get_noa) return -1; return wpa_s->driver->get_noa(wpa_s->drv_priv, buf, buf_len); } static inline int wpa_drv_set_p2p_powersave(struct wpa_supplicant *wpa_s, int legacy_ps, int opp_ps, int ctwindow) { if (!wpa_s->driver->set_p2p_powersave) return -1; return wpa_s->driver->set_p2p_powersave(wpa_s->drv_priv, legacy_ps, opp_ps, ctwindow); } static inline int wpa_drv_ampdu(struct wpa_supplicant *wpa_s, int ampdu) { if (!wpa_s->driver->ampdu) return -1; return wpa_s->driver->ampdu(wpa_s->drv_priv, ampdu); } static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, const u8 *buf, size_t len) { if (wpa_s->driver->send_tdls_mgmt) { return wpa_s->driver->send_tdls_mgmt(wpa_s->drv_priv, dst, action_code, dialog_token, status_code, peer_capab, buf, len); } return -1; } static inline int wpa_drv_tdls_oper(struct wpa_supplicant *wpa_s, enum tdls_oper oper, const u8 *peer) { if (!wpa_s->driver->tdls_oper) return -1; return wpa_s->driver->tdls_oper(wpa_s->drv_priv, oper, peer); } #ifdef ANDROID static inline int wpa_drv_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buf_len) { if (!wpa_s->driver->driver_cmd) return -1; return wpa_s->driver->driver_cmd(wpa_s->drv_priv, cmd, buf, buf_len); } #endif /* ANDROID */ static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s, const u8 *kek, const u8 *kck, const u8 *replay_ctr) { if (!wpa_s->driver->set_rekey_info) return; wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr); } static inline int wpa_drv_radio_disable(struct wpa_supplicant *wpa_s, int disabled) { if (!wpa_s->driver->radio_disable) return -1; return wpa_s->driver->radio_disable(wpa_s->drv_priv, disabled); } static inline int wpa_drv_switch_channel(struct wpa_supplicant *wpa_s, struct csa_settings *settings) { if (!wpa_s->driver->switch_channel) return -1; return wpa_s->driver->switch_channel(wpa_s->drv_priv, settings); } static inline int wpa_drv_wnm_oper(struct wpa_supplicant *wpa_s, enum wnm_oper oper, const u8 *peer, u8 *buf, u16 *buf_len) { if (!wpa_s->driver->wnm_oper) return -1; return wpa_s->driver->wnm_oper(wpa_s->drv_priv, oper, peer, buf, buf_len); } static inline int wpa_drv_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { if (!wpa_s->driver->status) return -1; return wpa_s->driver->status(wpa_s->drv_priv, buf, buflen); } static inline int wpa_drv_set_qos_map(struct wpa_supplicant *wpa_s, const u8 *qos_map_set, u8 qos_map_set_len) { if (!wpa_s->driver->set_qos_map) return -1; return wpa_s->driver->set_qos_map(wpa_s->drv_priv, qos_map_set, qos_map_set_len); } static inline int wpa_drv_wowlan(struct wpa_supplicant *wpa_s, const struct wowlan_triggers *triggers) { if (!wpa_s->driver->set_wowlan) return -1; return wpa_s->driver->set_wowlan(wpa_s->drv_priv, triggers); } static inline int wpa_drv_vendor_cmd(struct wpa_supplicant *wpa_s, int vendor_id, int subcmd, const u8 *data, size_t data_len, struct wpabuf *buf) { if (!wpa_s->driver->vendor_cmd) return -1; return wpa_s->driver->vendor_cmd(wpa_s->drv_priv, vendor_id, subcmd, data, data_len, buf); } #ifdef CONFIG_MACSEC static inline int wpa_drv_macsec_init(struct wpa_supplicant *wpa_s, struct macsec_init_params *params) { if (!wpa_s->driver->macsec_init) return -1; return wpa_s->driver->macsec_init(wpa_s->drv_priv, params); } static inline int wpa_drv_macsec_deinit(struct wpa_supplicant *wpa_s) { if (!wpa_s->driver->macsec_deinit) return -1; return wpa_s->driver->macsec_deinit(wpa_s->drv_priv); } static inline int wpa_drv_enable_protect_frames(struct wpa_supplicant *wpa_s, Boolean enabled) { if (!wpa_s->driver->enable_protect_frames) return -1; return wpa_s->driver->enable_protect_frames(wpa_s->drv_priv, enabled); } static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s, Boolean enabled, u32 window) { if (!wpa_s->driver->set_replay_protect) return -1; return wpa_s->driver->set_replay_protect(wpa_s->drv_priv, enabled, window); } static inline int wpa_drv_set_current_cipher_suite(struct wpa_supplicant *wpa_s, const u8 *cs, size_t cs_len) { if (!wpa_s->driver->set_current_cipher_suite) return -1; return wpa_s->driver->set_current_cipher_suite(wpa_s->drv_priv, cs, cs_len); } static inline int wpa_drv_enable_controlled_port(struct wpa_supplicant *wpa_s, Boolean enabled) { if (!wpa_s->driver->enable_controlled_port) return -1; return wpa_s->driver->enable_controlled_port(wpa_s->drv_priv, enabled); } static inline int wpa_drv_get_receive_lowest_pn(struct wpa_supplicant *wpa_s, u32 channel, u8 an, u32 *lowest_pn) { if (!wpa_s->driver->get_receive_lowest_pn) return -1; return wpa_s->driver->get_receive_lowest_pn(wpa_s->drv_priv, channel, an, lowest_pn); } static inline int wpa_drv_get_transmit_next_pn(struct wpa_supplicant *wpa_s, u32 channel, u8 an, u32 *next_pn) { if (!wpa_s->driver->get_transmit_next_pn) return -1; return wpa_s->driver->get_transmit_next_pn(wpa_s->drv_priv, channel, an, next_pn); } static inline int wpa_drv_set_transmit_next_pn(struct wpa_supplicant *wpa_s, u32 channel, u8 an, u32 next_pn) { if (!wpa_s->driver->set_transmit_next_pn) return -1; return wpa_s->driver->set_transmit_next_pn(wpa_s->drv_priv, channel, an, next_pn); } static inline int wpa_drv_get_available_receive_sc(struct wpa_supplicant *wpa_s, u32 *channel) { if (!wpa_s->driver->get_available_receive_sc) return -1; return wpa_s->driver->get_available_receive_sc(wpa_s->drv_priv, channel); } static inline int wpa_drv_create_receive_sc(struct wpa_supplicant *wpa_s, u32 channel, const u8 *sci_addr, u16 sci_port, unsigned int conf_offset, int validation) { if (!wpa_s->driver->create_receive_sc) return -1; return wpa_s->driver->create_receive_sc(wpa_s->drv_priv, channel, sci_addr, sci_port, conf_offset, validation); } static inline int wpa_drv_delete_receive_sc(struct wpa_supplicant *wpa_s, u32 channel) { if (!wpa_s->driver->delete_receive_sc) return -1; return wpa_s->driver->delete_receive_sc(wpa_s->drv_priv, channel); } static inline int wpa_drv_create_receive_sa(struct wpa_supplicant *wpa_s, u32 channel, u8 an, u32 lowest_pn, const u8 *sak) { if (!wpa_s->driver->create_receive_sa) return -1; return wpa_s->driver->create_receive_sa(wpa_s->drv_priv, channel, an, lowest_pn, sak); } static inline int wpa_drv_enable_receive_sa(struct wpa_supplicant *wpa_s, u32 channel, u8 an) { if (!wpa_s->driver->enable_receive_sa) return -1; return wpa_s->driver->enable_receive_sa(wpa_s->drv_priv, channel, an); } static inline int wpa_drv_disable_receive_sa(struct wpa_supplicant *wpa_s, u32 channel, u8 an) { if (!wpa_s->driver->disable_receive_sa) return -1; return wpa_s->driver->disable_receive_sa(wpa_s->drv_priv, channel, an); } static inline int wpa_drv_get_available_transmit_sc(struct wpa_supplicant *wpa_s, u32 *channel) { if (!wpa_s->driver->get_available_transmit_sc) return -1; return wpa_s->driver->get_available_transmit_sc(wpa_s->drv_priv, channel); } static inline int wpa_drv_create_transmit_sc(struct wpa_supplicant *wpa_s, u32 channel, const u8 *sci_addr, u16 sci_port, unsigned int conf_offset) { if (!wpa_s->driver->create_transmit_sc) return -1; return wpa_s->driver->create_transmit_sc(wpa_s->drv_priv, channel, sci_addr, sci_port, conf_offset); } static inline int wpa_drv_delete_transmit_sc(struct wpa_supplicant *wpa_s, u32 channel) { if (!wpa_s->driver->delete_transmit_sc) return -1; return wpa_s->driver->delete_transmit_sc(wpa_s->drv_priv, channel); } static inline int wpa_drv_create_transmit_sa(struct wpa_supplicant *wpa_s, u32 channel, u8 an, u32 next_pn, Boolean confidentiality, const u8 *sak) { if (!wpa_s->driver->create_transmit_sa) return -1; return wpa_s->driver->create_transmit_sa(wpa_s->drv_priv, channel, an, next_pn, confidentiality, sak); } static inline int wpa_drv_enable_transmit_sa(struct wpa_supplicant *wpa_s, u32 channel, u8 an) { if (!wpa_s->driver->enable_transmit_sa) return -1; return wpa_s->driver->enable_transmit_sa(wpa_s->drv_priv, channel, an); } static inline int wpa_drv_disable_transmit_sa(struct wpa_supplicant *wpa_s, u32 channel, u8 an) { if (!wpa_s->driver->disable_transmit_sa) return -1; return wpa_s->driver->disable_transmit_sa(wpa_s->drv_priv, channel, an); } #endif /* CONFIG_MACSEC */ #endif /* DRIVER_I_H */ wpa_supplicant-2.2/wpa_supplicant/todo.txt0000664000175000017500000001172112343617166016760 0ustar jmjmTo do: - add support for WPA with ap_scan=0 (update selected cipher etc. based on AssocInfo; make sure these match with configuration) - consider closing smart card / PCSC connection when EAP-SIM/EAP-AKA authentication has been completed (cache scard data based on serial#(?) and try to optimize next connection if the same card is present for next auth) - on disconnect event, could try to associate with another AP if one is present in scan results; would need to update scan results periodically.. - if driver/hw is not WPA2 capable, must remove WPA_PROTO_RSN flag from ssid->proto fields to avoid detecting downgrade attacks when the driver is not reporting RSN IE, but msg 3/4 has one - Cisco AP and non-zero keyidx for unicast -> map to broadcast (actually, this already works with driver_ndis; so maybe just change driver_*.c to do the mapping for drivers that cannot handle non-zero keyidx for unicast); worked also with Host AP driver and madwifi - IEEE 802.1X and key update with driver_ndis?? wpa_supplicant did not seem to see unencrypted EAPOL-Key frames at all.. - EAP-PAX with PAX_SEC - EAP (RFC 3748) * OTP Extended Responses (Sect. 5.5) - test what happens if authenticator sends EAP-Success before real EAP authentication ("canned" Success); this should be ignored based on RFC 3748 Sect. 4.2 - test compilation with gcc -W options (more warnings?) (Done once; number of unused function arguments still present) - add proper support for using dot11RSNAConfigSATimeout - ctrl_iface: get/set/remove blob - use doc/docbook/*.sgml and docbook2{txt,html,pdf} to replace README and web pages including the same information.. i.e., have this information only in one page; how to build a PDF file with all the SGML included? - EAP-POTP/RSA SecurID profile (RFC 4793) - document wpa_gui build and consider adding it to 'make install' - test madwifi with pairwise=TKIP group=WEP104 - consider merging hostapd and wpa_supplicant PMKSA cache implementations - consider redesigning pending EAP requests (identity/password/otp from ctrl_iface) by moving the retrying of the previous request into EAP state machine so that EAPOL state machine is not needed for this - rfc4284.txt (network selection for eap) - www pages about configuring wpa_supplicant: * global options (ap_scan, ctrl_interfaces) based on OS/driver * network block * key_mgmt selection * WPA parameters * EAP options (one page for each method) * "configuration wizard" (step 1: select OS, step 2: select driver, ...) to generate example configuration - error path in rsn_preauth_init: should probably deinit l2_packet handlers if something fails; does something else need deinit? - consider moving SIM card functionality (IMSI fetching) away from eap.c; this should likely happen before EAP is initialized for authentication; now IMSI is read only after receiving EAP-Identity/Request, but since it is really needed for all cases, reading IMSI and generating Identity string could very well be done before EAP has been started - try to work around race in receiving association event and first EAPOL message - try to work around race in configuring PTK and sending msg 4/4 (some NDIS drivers with ndiswrapper end up not being able to complete 4-way handshake in some cases; extra delay before setting the key seems to help) - add wpa_secure_memzero() macro and secure implementation (volatile u8*) to clear memory; this would be used to clear temporary buffers containing private data (e.g., keys); the macro can be defined to NOP in order to save space (i.e., no code should depend on the macro doing something) - make sure that TLS session cache is not shared between EAP types or if it is, that the cache entries are bound to only one EAP type; e.g., cache entry created with EAP-TLS must not be allowed to do fast re-auth with EAP-TTLS - consider moving eap_tls_build_ack() call into eap_tls_process_helper() (it seems to be called always if helper returns 1) * could need to modify eap_{ttls,peap,fast}_decrypt to do same - add support for fetching full user cert chain from Windows certificate stores even when there are intermediate CA certs that are not in the configured ca_cert store (e.g., ROOT) (they could be, e.g., in CA store) - clean up common.[ch] - change TLS/crypto library interface to use a structure of function pointers and helper inline functions (like driver_ops) instead of requiring every TLS wrapper to implement all functions - add support for encrypted configuration fields (e.g., password, psk, passphrase, pin) - wpa_gui: add support for setting and showing priority - cleanup TLS/PEAP/TTLS/FAST fragmentation: both the handshake and Appl. Data phases should be able to use the same functions for this; the last step in processing sent should be this code and rest of the code should not need to care about fragmentation at all - test EAP-FAST peer with OpenSSL and verify that fallback to full handshake (ServerHello followed by something else than ChangeCipherSpec) wpa_supplicant-2.2/wpa_supplicant/Makefile0000664000175000017500000011315612343617166016717 0ustar jmjmifndef CC CC=gcc endif ifndef CFLAGS CFLAGS = -MMD -O2 -Wall -g endif export LIBDIR ?= /usr/local/lib/ export BINDIR ?= /usr/local/sbin/ PKG_CONFIG ?= pkg-config CFLAGS += -I$(abspath ../src) CFLAGS += -I$(abspath ../src/utils) -include .config ifdef CONFIG_TESTING_OPTIONS CFLAGS += -DCONFIG_TESTING_OPTIONS CONFIG_WPS_TESTING=y CONFIG_TDLS_TESTING=y endif BINALL=wpa_supplicant wpa_cli ifndef CONFIG_NO_WPA_PASSPHRASE BINALL += wpa_passphrase endif ALL = $(BINALL) ALL += systemd/wpa_supplicant.service ALL += systemd/wpa_supplicant@.service ALL += systemd/wpa_supplicant-nl80211@.service ALL += systemd/wpa_supplicant-wired@.service ALL += dbus/fi.epitest.hostap.WPASupplicant.service ALL += dbus/fi.w1.wpa_supplicant1.service all: verify_config $(ALL) dynamic_eap_methods verify_config: @if [ ! -r .config ]; then \ echo 'Building wpa_supplicant requires a configuration file'; \ echo '(.config). See README for more instructions. You can'; \ echo 'run "cp defconfig .config" to create an example'; \ echo 'configuration.'; \ exit 1; \ fi mkconfig: @if [ -f .config ]; then \ echo '.config exists - did not replace it'; \ exit 1; \ fi echo CONFIG_DRIVER_HOSTAP=y >> .config echo CONFIG_DRIVER_WEXT=y >> .config $(DESTDIR)$(BINDIR)/%: % install -D $(<) $(@) install: $(addprefix $(DESTDIR)$(BINDIR)/,$(BINALL)) $(MAKE) -C ../src install ifdef CONFIG_FIPS CONFIG_NO_RANDOM_POOL= CONFIG_OPENSSL_CMAC=y endif OBJS = config.o OBJS += notify.o OBJS += bss.o OBJS += eap_register.o OBJS += ../src/utils/common.o OBJS += ../src/utils/wpa_debug.o OBJS += ../src/utils/wpabuf.o OBJS_p = wpa_passphrase.o OBJS_p += ../src/utils/common.o OBJS_p += ../src/utils/wpa_debug.o OBJS_p += ../src/utils/wpabuf.o OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o OBJS_c += ../src/utils/wpa_debug.o OBJS_c += ../src/utils/common.o ifndef CONFIG_OS ifdef CONFIG_NATIVE_WINDOWS CONFIG_OS=win32 else CONFIG_OS=unix endif endif ifeq ($(CONFIG_OS), internal) CFLAGS += -DOS_NO_C_LIB_DEFINES endif OBJS += ../src/utils/os_$(CONFIG_OS).o OBJS_p += ../src/utils/os_$(CONFIG_OS).o OBJS_c += ../src/utils/os_$(CONFIG_OS).o ifdef CONFIG_WPA_TRACE CFLAGS += -DWPA_TRACE OBJS += ../src/utils/trace.o OBJS_p += ../src/utils/trace.o OBJS_c += ../src/utils/trace.o OBJS_priv += ../src/utils/trace.o LDFLAGS += -rdynamic CFLAGS += -funwind-tables ifdef CONFIG_WPA_TRACE_BFD CFLAGS += -DPACKAGE="wpa_supplicant" -DWPA_TRACE_BFD LIBS += -lbfd -ldl -liberty -lz LIBS_p += -lbfd -ldl -liberty -lz LIBS_c += -lbfd -ldl -liberty -lz endif endif ifndef CONFIG_ELOOP CONFIG_ELOOP=eloop endif OBJS += ../src/utils/$(CONFIG_ELOOP).o OBJS_c += ../src/utils/$(CONFIG_ELOOP).o ifeq ($(CONFIG_ELOOP), eloop) # Using glibc < 2.17 requires -lrt for clock_gettime() LIBS += -lrt LIBS_c += -lrt LIBS_p += -lrt endif ifdef CONFIG_ELOOP_POLL CFLAGS += -DCONFIG_ELOOP_POLL endif ifdef CONFIG_ELOOP_EPOLL CFLAGS += -DCONFIG_ELOOP_EPOLL endif ifdef CONFIG_EAPOL_TEST CFLAGS += -Werror -DEAPOL_TEST endif ifdef CONFIG_CODE_COVERAGE CFLAGS += -O0 -fprofile-arcs -ftest-coverage LIBS += -lgcov LIBS_c += -lgcov LIBS_p += -lgcov endif ifdef CONFIG_HT_OVERRIDES CFLAGS += -DCONFIG_HT_OVERRIDES endif ifdef CONFIG_VHT_OVERRIDES CFLAGS += -DCONFIG_VHT_OVERRIDES endif ifndef CONFIG_BACKEND CONFIG_BACKEND=file endif ifeq ($(CONFIG_BACKEND), file) OBJS += config_file.o ifndef CONFIG_NO_CONFIG_BLOBS NEED_BASE64=y endif CFLAGS += -DCONFIG_BACKEND_FILE endif ifeq ($(CONFIG_BACKEND), winreg) OBJS += config_winreg.o endif ifeq ($(CONFIG_BACKEND), none) OBJS += config_none.o endif ifdef CONFIG_NO_CONFIG_WRITE CFLAGS += -DCONFIG_NO_CONFIG_WRITE endif ifdef CONFIG_NO_CONFIG_BLOBS CFLAGS += -DCONFIG_NO_CONFIG_BLOBS endif ifdef CONFIG_NO_SCAN_PROCESSING CFLAGS += -DCONFIG_NO_SCAN_PROCESSING endif ifdef CONFIG_IEEE80211W CFLAGS += -DCONFIG_IEEE80211W NEED_SHA256=y NEED_AES_OMAC1=y endif ifdef CONFIG_IEEE80211R CFLAGS += -DCONFIG_IEEE80211R OBJS += ../src/rsn_supp/wpa_ft.o NEED_80211_COMMON=y NEED_SHA256=y NEED_AES_OMAC1=y endif ifdef CONFIG_SAE CFLAGS += -DCONFIG_SAE OBJS += ../src/common/sae.o NEED_ECC=y NEED_DH_GROUPS=y endif ifdef CONFIG_WNM CFLAGS += -DCONFIG_WNM OBJS += wnm_sta.o endif ifdef CONFIG_TDLS CFLAGS += -DCONFIG_TDLS OBJS += ../src/rsn_supp/tdls.o NEED_SHA256=y NEED_AES_OMAC1=y endif ifdef CONFIG_TDLS_TESTING CFLAGS += -DCONFIG_TDLS_TESTING endif ifdef CONFIG_PEERKEY CFLAGS += -DCONFIG_PEERKEY endif ifndef CONFIG_NO_WPA OBJS += ../src/rsn_supp/wpa.o OBJS += ../src/rsn_supp/preauth.o OBJS += ../src/rsn_supp/pmksa_cache.o OBJS += ../src/rsn_supp/peerkey.o OBJS += ../src/rsn_supp/wpa_ie.o OBJS += ../src/common/wpa_common.o NEED_AES=y NEED_SHA1=y NEED_MD5=y NEED_RC4=y else CFLAGS += -DCONFIG_NO_WPA endif ifdef CONFIG_IBSS_RSN NEED_RSN_AUTHENTICATOR=y CFLAGS += -DCONFIG_IBSS_RSN OBJS += ibss_rsn.o endif ifdef CONFIG_P2P OBJS += p2p_supplicant.o OBJS += ../src/p2p/p2p.o OBJS += ../src/p2p/p2p_utils.o OBJS += ../src/p2p/p2p_parse.o OBJS += ../src/p2p/p2p_build.o OBJS += ../src/p2p/p2p_go_neg.o OBJS += ../src/p2p/p2p_sd.o OBJS += ../src/p2p/p2p_pd.o OBJS += ../src/p2p/p2p_invitation.o OBJS += ../src/p2p/p2p_dev_disc.o OBJS += ../src/p2p/p2p_group.o OBJS += ../src/ap/p2p_hostapd.o OBJS += ../src/utils/bitfield.o CFLAGS += -DCONFIG_P2P NEED_GAS=y NEED_OFFCHANNEL=y NEED_80211_COMMON=y CONFIG_WPS=y CONFIG_AP=y ifdef CONFIG_P2P_STRICT CFLAGS += -DCONFIG_P2P_STRICT endif endif ifdef CONFIG_WIFI_DISPLAY CFLAGS += -DCONFIG_WIFI_DISPLAY OBJS += wifi_display.o endif ifdef CONFIG_HS20 OBJS += hs20_supplicant.o CFLAGS += -DCONFIG_HS20 CONFIG_INTERWORKING=y NEED_AES_OMAC1=y endif ifdef CONFIG_INTERWORKING OBJS += interworking.o CFLAGS += -DCONFIG_INTERWORKING NEED_GAS=y endif include ../src/drivers/drivers.mak ifdef CONFIG_AP OBJS_d += $(DRV_BOTH_OBJS) CFLAGS += $(DRV_BOTH_CFLAGS) LDFLAGS += $(DRV_BOTH_LDFLAGS) LIBS += $(DRV_BOTH_LIBS) else NEED_AP_MLME= OBJS_d += $(DRV_WPA_OBJS) CFLAGS += $(DRV_WPA_CFLAGS) LDFLAGS += $(DRV_WPA_LDFLAGS) LIBS += $(DRV_WPA_LIBS) endif ifndef CONFIG_L2_PACKET CONFIG_L2_PACKET=linux endif OBJS_l2 += ../src/l2_packet/l2_packet_$(CONFIG_L2_PACKET).o ifeq ($(CONFIG_L2_PACKET), pcap) ifdef CONFIG_WINPCAP CFLAGS += -DCONFIG_WINPCAP LIBS += -lwpcap -lpacket LIBS_w += -lwpcap else LIBS += -ldnet -lpcap endif endif ifeq ($(CONFIG_L2_PACKET), winpcap) LIBS += -lwpcap -lpacket LIBS_w += -lwpcap endif ifeq ($(CONFIG_L2_PACKET), freebsd) LIBS += -lpcap endif ifdef CONFIG_EAP_TLS # EAP-TLS ifeq ($(CONFIG_EAP_TLS), dyn) CFLAGS += -DEAP_TLS_DYNAMIC EAPDYN += ../src/eap_peer/eap_tls.so else CFLAGS += -DEAP_TLS OBJS += ../src/eap_peer/eap_tls.o OBJS_h += ../src/eap_server/eap_server_tls.o endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_UNAUTH_TLS # EAP-UNAUTH-TLS CFLAGS += -DEAP_UNAUTH_TLS ifndef CONFIG_EAP_UNAUTH_TLS OBJS += ../src/eap_peer/eap_tls.o OBJS_h += ../src/eap_server/eap_server_tls.o TLS_FUNCS=y endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_PEAP # EAP-PEAP ifeq ($(CONFIG_EAP_PEAP), dyn) CFLAGS += -DEAP_PEAP_DYNAMIC EAPDYN += ../src/eap_peer/eap_peap.so else CFLAGS += -DEAP_PEAP OBJS += ../src/eap_peer/eap_peap.o OBJS += ../src/eap_common/eap_peap_common.o OBJS_h += ../src/eap_server/eap_server_peap.o endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_TTLS # EAP-TTLS ifeq ($(CONFIG_EAP_TTLS), dyn) CFLAGS += -DEAP_TTLS_DYNAMIC EAPDYN += ../src/eap_peer/eap_ttls.so else CFLAGS += -DEAP_TTLS OBJS += ../src/eap_peer/eap_ttls.o OBJS_h += ../src/eap_server/eap_server_ttls.o endif MS_FUNCS=y TLS_FUNCS=y CHAP=y CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_MD5 # EAP-MD5 ifeq ($(CONFIG_EAP_MD5), dyn) CFLAGS += -DEAP_MD5_DYNAMIC EAPDYN += ../src/eap_peer/eap_md5.so else CFLAGS += -DEAP_MD5 OBJS += ../src/eap_peer/eap_md5.o OBJS_h += ../src/eap_server/eap_server_md5.o endif CHAP=y CONFIG_IEEE8021X_EAPOL=y endif # backwards compatibility for old spelling ifdef CONFIG_MSCHAPV2 ifndef CONFIG_EAP_MSCHAPV2 CONFIG_EAP_MSCHAPV2=y endif endif ifdef CONFIG_EAP_MSCHAPV2 # EAP-MSCHAPv2 ifeq ($(CONFIG_EAP_MSCHAPV2), dyn) CFLAGS += -DEAP_MSCHAPv2_DYNAMIC EAPDYN += ../src/eap_peer/eap_mschapv2.so EAPDYN += ../src/eap_peer/mschapv2.so else CFLAGS += -DEAP_MSCHAPv2 OBJS += ../src/eap_peer/eap_mschapv2.o OBJS += ../src/eap_peer/mschapv2.o OBJS_h += ../src/eap_server/eap_server_mschapv2.o endif MS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_GTC # EAP-GTC ifeq ($(CONFIG_EAP_GTC), dyn) CFLAGS += -DEAP_GTC_DYNAMIC EAPDYN += ../src/eap_peer/eap_gtc.so else CFLAGS += -DEAP_GTC OBJS += ../src/eap_peer/eap_gtc.o OBJS_h += ../src/eap_server/eap_server_gtc.o endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_OTP # EAP-OTP ifeq ($(CONFIG_EAP_OTP), dyn) CFLAGS += -DEAP_OTP_DYNAMIC EAPDYN += ../src/eap_peer/eap_otp.so else CFLAGS += -DEAP_OTP OBJS += ../src/eap_peer/eap_otp.o endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_SIM # EAP-SIM ifeq ($(CONFIG_EAP_SIM), dyn) CFLAGS += -DEAP_SIM_DYNAMIC EAPDYN += ../src/eap_peer/eap_sim.so else CFLAGS += -DEAP_SIM OBJS += ../src/eap_peer/eap_sim.o OBJS_h += ../src/eap_server/eap_server_sim.o endif CONFIG_IEEE8021X_EAPOL=y CONFIG_EAP_SIM_COMMON=y NEED_AES_CBC=y endif ifdef CONFIG_EAP_LEAP # EAP-LEAP ifeq ($(CONFIG_EAP_LEAP), dyn) CFLAGS += -DEAP_LEAP_DYNAMIC EAPDYN += ../src/eap_peer/eap_leap.so else CFLAGS += -DEAP_LEAP OBJS += ../src/eap_peer/eap_leap.o endif MS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_PSK # EAP-PSK ifeq ($(CONFIG_EAP_PSK), dyn) CFLAGS += -DEAP_PSK_DYNAMIC EAPDYN += ../src/eap_peer/eap_psk.so else CFLAGS += -DEAP_PSK OBJS += ../src/eap_peer/eap_psk.o ../src/eap_common/eap_psk_common.o OBJS_h += ../src/eap_server/eap_server_psk.o endif CONFIG_IEEE8021X_EAPOL=y NEED_AES=y NEED_AES_OMAC1=y NEED_AES_ENCBLOCK=y NEED_AES_EAX=y endif ifdef CONFIG_EAP_AKA # EAP-AKA ifeq ($(CONFIG_EAP_AKA), dyn) CFLAGS += -DEAP_AKA_DYNAMIC EAPDYN += ../src/eap_peer/eap_aka.so else CFLAGS += -DEAP_AKA OBJS += ../src/eap_peer/eap_aka.o OBJS_h += ../src/eap_server/eap_server_aka.o endif CONFIG_IEEE8021X_EAPOL=y CONFIG_EAP_SIM_COMMON=y NEED_AES_CBC=y endif ifdef CONFIG_EAP_PROXY CFLAGS += -DCONFIG_EAP_PROXY OBJS += ../src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).o include eap_proxy_$(CONFIG_EAP_PROXY).mak CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_AKA_PRIME # EAP-AKA' ifeq ($(CONFIG_EAP_AKA_PRIME), dyn) CFLAGS += -DEAP_AKA_PRIME_DYNAMIC else CFLAGS += -DEAP_AKA_PRIME endif NEED_SHA256=y endif ifdef CONFIG_EAP_SIM_COMMON OBJS += ../src/eap_common/eap_sim_common.o OBJS_h += ../src/eap_server/eap_sim_db.o NEED_AES=y NEED_FIPS186_2_PRF=y endif ifdef CONFIG_EAP_FAST # EAP-FAST ifeq ($(CONFIG_EAP_FAST), dyn) CFLAGS += -DEAP_FAST_DYNAMIC EAPDYN += ../src/eap_peer/eap_fast.so EAPDYN += ../src/eap_common/eap_fast_common.o else CFLAGS += -DEAP_FAST OBJS += ../src/eap_peer/eap_fast.o ../src/eap_peer/eap_fast_pac.o OBJS += ../src/eap_common/eap_fast_common.o OBJS_h += ../src/eap_server/eap_server_fast.o endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y NEED_T_PRF=y endif ifdef CONFIG_EAP_PAX # EAP-PAX ifeq ($(CONFIG_EAP_PAX), dyn) CFLAGS += -DEAP_PAX_DYNAMIC EAPDYN += ../src/eap_peer/eap_pax.so else CFLAGS += -DEAP_PAX OBJS += ../src/eap_peer/eap_pax.o ../src/eap_common/eap_pax_common.o OBJS_h += ../src/eap_server/eap_server_pax.o endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_SAKE # EAP-SAKE ifeq ($(CONFIG_EAP_SAKE), dyn) CFLAGS += -DEAP_SAKE_DYNAMIC EAPDYN += ../src/eap_peer/eap_sake.so else CFLAGS += -DEAP_SAKE OBJS += ../src/eap_peer/eap_sake.o ../src/eap_common/eap_sake_common.o OBJS_h += ../src/eap_server/eap_server_sake.o endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_GPSK # EAP-GPSK ifeq ($(CONFIG_EAP_GPSK), dyn) CFLAGS += -DEAP_GPSK_DYNAMIC EAPDYN += ../src/eap_peer/eap_gpsk.so else CFLAGS += -DEAP_GPSK OBJS += ../src/eap_peer/eap_gpsk.o ../src/eap_common/eap_gpsk_common.o OBJS_h += ../src/eap_server/eap_server_gpsk.o endif CONFIG_IEEE8021X_EAPOL=y ifdef CONFIG_EAP_GPSK_SHA256 CFLAGS += -DEAP_GPSK_SHA256 endif NEED_SHA256=y NEED_AES_OMAC1=y endif ifdef CONFIG_EAP_PWD CFLAGS += -DEAP_PWD OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o OBJS_h += ../src/eap_server/eap_server_pwd.o CONFIG_IEEE8021X_EAPOL=y NEED_SHA256=y endif ifdef CONFIG_EAP_EKE # EAP-EKE ifeq ($(CONFIG_EAP_EKE), dyn) CFLAGS += -DEAP_EKE_DYNAMIC EAPDYN += ../src/eap_peer/eap_eke.so else CFLAGS += -DEAP_EKE OBJS += ../src/eap_peer/eap_eke.o ../src/eap_common/eap_eke_common.o OBJS_h += ../src/eap_server/eap_server_eke.o endif CONFIG_IEEE8021X_EAPOL=y NEED_DH_GROUPS=y NEED_DH_GROUPS_ALL=y NEED_SHA256=y endif ifdef CONFIG_WPS # EAP-WSC CFLAGS += -DCONFIG_WPS -DEAP_WSC OBJS += wps_supplicant.o OBJS += ../src/utils/uuid.o OBJS += ../src/eap_peer/eap_wsc.o ../src/eap_common/eap_wsc_common.o OBJS += ../src/wps/wps.o OBJS += ../src/wps/wps_common.o OBJS += ../src/wps/wps_attr_parse.o OBJS += ../src/wps/wps_attr_build.o OBJS += ../src/wps/wps_attr_process.o OBJS += ../src/wps/wps_dev_attr.o OBJS += ../src/wps/wps_enrollee.o OBJS += ../src/wps/wps_registrar.o OBJS_h += ../src/eap_server/eap_server_wsc.o CONFIG_IEEE8021X_EAPOL=y NEED_DH_GROUPS=y NEED_SHA256=y NEED_BASE64=y NEED_80211_COMMON=y NEED_AES_CBC=y NEED_MODEXP=y ifdef CONFIG_WPS_NFC CFLAGS += -DCONFIG_WPS_NFC OBJS += ../src/wps/ndef.o NEED_WPS_OOB=y endif ifdef NEED_WPS_OOB CFLAGS += -DCONFIG_WPS_OOB endif ifdef CONFIG_WPS_ER CONFIG_WPS_UPNP=y CFLAGS += -DCONFIG_WPS_ER OBJS += ../src/wps/wps_er.o OBJS += ../src/wps/wps_er_ssdp.o endif ifdef CONFIG_WPS_UPNP CFLAGS += -DCONFIG_WPS_UPNP OBJS += ../src/wps/wps_upnp.o OBJS += ../src/wps/wps_upnp_ssdp.o OBJS += ../src/wps/wps_upnp_web.o OBJS += ../src/wps/wps_upnp_event.o OBJS += ../src/wps/wps_upnp_ap.o OBJS += ../src/wps/upnp_xml.o OBJS += ../src/wps/httpread.o OBJS += ../src/wps/http_client.o OBJS += ../src/wps/http_server.o endif ifdef CONFIG_WPS_STRICT CFLAGS += -DCONFIG_WPS_STRICT OBJS += ../src/wps/wps_validate.o endif ifdef CONFIG_WPS_TESTING CFLAGS += -DCONFIG_WPS_TESTING endif ifdef CONFIG_WPS_REG_DISABLE_OPEN CFLAGS += -DCONFIG_WPS_REG_DISABLE_OPEN endif endif ifdef CONFIG_EAP_IKEV2 # EAP-IKEv2 ifeq ($(CONFIG_EAP_IKEV2), dyn) CFLAGS += -DEAP_IKEV2_DYNAMIC EAPDYN += ../src/eap_peer/eap_ikev2.so ../src/eap_peer/ikev2.o EAPDYN += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o else CFLAGS += -DEAP_IKEV2 OBJS += ../src/eap_peer/eap_ikev2.o ../src/eap_peer/ikev2.o OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o OBJS_h += ../src/eap_server/eap_server_ikev2.o OBJS_h += ../src/eap_server/ikev2.o endif CONFIG_IEEE8021X_EAPOL=y NEED_DH_GROUPS=y NEED_DH_GROUPS_ALL=y NEED_MODEXP=y NEED_CIPHER=y endif ifdef CONFIG_EAP_VENDOR_TEST ifeq ($(CONFIG_EAP_VENDOR_TEST), dyn) CFLAGS += -DEAP_VENDOR_TEST_DYNAMIC EAPDYN += ../src/eap_peer/eap_vendor_test.so else CFLAGS += -DEAP_VENDOR_TEST OBJS += ../src/eap_peer/eap_vendor_test.o OBJS_h += ../src/eap_server/eap_server_vendor_test.o endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_TNC # EAP-TNC CFLAGS += -DEAP_TNC OBJS += ../src/eap_peer/eap_tnc.o OBJS += ../src/eap_peer/tncc.o OBJS_h += ../src/eap_server/eap_server_tnc.o OBJS_h += ../src/eap_server/tncs.o NEED_BASE64=y ifndef CONFIG_NATIVE_WINDOWS ifndef CONFIG_DRIVER_BSD LIBS += -ldl endif endif endif ifdef CONFIG_IEEE8021X_EAPOL # IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication) CFLAGS += -DIEEE8021X_EAPOL OBJS += ../src/eapol_supp/eapol_supp_sm.o OBJS += ../src/eap_peer/eap.o ../src/eap_peer/eap_methods.o NEED_EAP_COMMON=y ifdef CONFIG_DYNAMIC_EAP_METHODS CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS LIBS += -ldl -rdynamic endif endif ifdef CONFIG_MACSEC CFLAGS += -DCONFIG_MACSEC NEED_AES_ENCBLOCK=y NEED_AES_UNWRAP=y NEED_AES_WRAP=y NEED_AES_OMAC1=y OBJS += wpas_kay.o OBJS += ../src/pae/ieee802_1x_cp.o OBJS += ../src/pae/ieee802_1x_kay.o OBJS += ../src/pae/ieee802_1x_key.o OBJS += ../src/pae/ieee802_1x_secy_ops.o endif ifdef CONFIG_AP NEED_80211_COMMON=y NEED_EAP_COMMON=y NEED_RSN_AUTHENTICATOR=y CFLAGS += -DCONFIG_AP OBJS += ap.o CFLAGS += -DCONFIG_NO_RADIUS CFLAGS += -DCONFIG_NO_ACCOUNTING CFLAGS += -DCONFIG_NO_VLAN OBJS += ../src/ap/hostapd.o OBJS += ../src/ap/wpa_auth_glue.o OBJS += ../src/ap/utils.o OBJS += ../src/ap/authsrv.o OBJS += ../src/ap/ap_config.o OBJS += ../src/utils/ip_addr.o OBJS += ../src/ap/sta_info.o OBJS += ../src/ap/tkip_countermeasures.o OBJS += ../src/ap/ap_mlme.o OBJS += ../src/ap/ieee802_1x.o OBJS += ../src/eapol_auth/eapol_auth_sm.o OBJS += ../src/ap/ieee802_11_auth.o OBJS += ../src/ap/ieee802_11_shared.o OBJS += ../src/ap/drv_callbacks.o OBJS += ../src/ap/ap_drv_ops.o OBJS += ../src/ap/beacon.o OBJS += ../src/ap/eap_user_db.o ifdef CONFIG_IEEE80211N OBJS += ../src/ap/ieee802_11_ht.o ifdef CONFIG_IEEE80211AC OBJS += ../src/ap/ieee802_11_vht.o endif endif ifdef CONFIG_WNM OBJS += ../src/ap/wnm_ap.o endif ifdef CONFIG_CTRL_IFACE OBJS += ../src/ap/ctrl_iface_ap.o endif CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY OBJS += ../src/eap_server/eap_server.o OBJS += ../src/eap_server/eap_server_identity.o OBJS += ../src/eap_server/eap_server_methods.o ifdef CONFIG_IEEE80211N CFLAGS += -DCONFIG_IEEE80211N ifdef CONFIG_IEEE80211AC CFLAGS += -DCONFIG_IEEE80211AC endif endif ifdef NEED_AP_MLME OBJS += ../src/ap/wmm.o OBJS += ../src/ap/ap_list.o OBJS += ../src/ap/ieee802_11.o OBJS += ../src/ap/hw_features.o OBJS += ../src/ap/dfs.o CFLAGS += -DNEED_AP_MLME endif ifdef CONFIG_WPS CFLAGS += -DEAP_SERVER_WSC OBJS += ../src/ap/wps_hostapd.o OBJS += ../src/eap_server/eap_server_wsc.o endif ifdef CONFIG_INTERWORKING OBJS += ../src/ap/gas_serv.o endif ifdef CONFIG_HS20 OBJS += ../src/ap/hs20.o endif endif ifdef NEED_RSN_AUTHENTICATOR CFLAGS += -DCONFIG_NO_RADIUS NEED_AES_WRAP=y OBJS += ../src/ap/wpa_auth.o OBJS += ../src/ap/wpa_auth_ie.o OBJS += ../src/ap/pmksa_cache_auth.o ifdef CONFIG_IEEE80211R OBJS += ../src/ap/wpa_auth_ft.o endif ifdef CONFIG_PEERKEY OBJS += ../src/ap/peerkey_auth.o endif endif ifdef CONFIG_EAP_SERVER CFLAGS += -DEAP_SERVER OBJS_h += ../src/eap_server/eap_server.o OBJS_h += ../src/eap_server/eap_server_identity.o OBJS_h += ../src/eap_server/eap_server_methods.o endif ifdef CONFIG_RADIUS_CLIENT OBJS_h += ../src/utils/ip_addr.o OBJS_h += ../src/radius/radius.o OBJS_h += ../src/radius/radius_client.o endif ifdef CONFIG_AUTHENTICATOR OBJS_h += ../src/eapol_auth/eapol_auth_sm.o OBJS_h += ../src/ap/ieee802_1x.o endif ifdef CONFIG_WPA_AUTHENTICATOR OBJS_h += ../src/ap/wpa_auth.o OBJS_h += ../src/ap/wpa_auth_ie.o OBJS_h += ../src/ap/pmksa_cache_auth.o ifdef CONFIG_IEEE80211R OBJS_h += ../src/ap/wpa_auth_ft.o endif ifdef CONFIG_PEERKEY OBJS_h += ../src/ap/peerkey_auth.o endif endif ifdef CONFIG_PCSC # PC/SC interface for smartcards (USIM, GSM SIM) CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC OBJS += ../src/utils/pcsc_funcs.o # -lpthread may not be needed depending on how pcsc-lite was configured ifdef CONFIG_NATIVE_WINDOWS #Once MinGW gets support for WinScard, -lwinscard could be used instead of the #dynamic symbol loading that is now used in pcsc_funcs.c #LIBS += -lwinscard else LIBS += -lpcsclite -lpthread endif endif ifdef CONFIG_SIM_SIMULATOR CFLAGS += -DCONFIG_SIM_SIMULATOR NEED_MILENAGE=y endif ifdef CONFIG_USIM_SIMULATOR CFLAGS += -DCONFIG_USIM_SIMULATOR NEED_MILENAGE=y endif ifdef NEED_MILENAGE OBJS += ../src/crypto/milenage.o NEED_AES_ENCBLOCK=y endif ifdef CONFIG_PKCS12 CFLAGS += -DPKCS12_FUNCS endif ifdef CONFIG_SMARTCARD CFLAGS += -DCONFIG_SMARTCARD endif ifdef MS_FUNCS OBJS += ../src/crypto/ms_funcs.o NEED_DES=y NEED_MD4=y endif ifdef CHAP OBJS += ../src/eap_common/chap.o endif ifdef TLS_FUNCS NEED_DES=y # Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST) OBJS += ../src/eap_peer/eap_tls_common.o OBJS_h += ../src/eap_server/eap_server_tls_common.o ifndef CONFIG_FIPS NEED_TLS_PRF=y NEED_SHA1=y NEED_MD5=y endif endif ifndef CONFIG_TLS CONFIG_TLS=openssl endif ifdef CONFIG_TLSV11 CFLAGS += -DCONFIG_TLSV11 endif ifdef CONFIG_TLSV12 CFLAGS += -DCONFIG_TLSV12 NEED_SHA256=y endif ifeq ($(CONFIG_TLS), openssl) ifdef TLS_FUNCS CFLAGS += -DEAP_TLS_OPENSSL OBJS += ../src/crypto/tls_openssl.o LIBS += -lssl endif OBJS += ../src/crypto/crypto_openssl.o OBJS_p += ../src/crypto/crypto_openssl.o ifdef NEED_FIPS186_2_PRF OBJS += ../src/crypto/fips_prf_openssl.o endif LIBS += -lcrypto LIBS_p += -lcrypto ifdef CONFIG_TLS_ADD_DL LIBS += -ldl LIBS_p += -ldl endif endif ifeq ($(CONFIG_TLS), gnutls) ifdef TLS_FUNCS OBJS += ../src/crypto/tls_gnutls.o LIBS += -lgnutls -lgpg-error endif OBJS += ../src/crypto/crypto_gnutls.o OBJS_p += ../src/crypto/crypto_gnutls.o ifdef NEED_FIPS186_2_PRF OBJS += ../src/crypto/fips_prf_internal.o SHA1OBJS += ../src/crypto/sha1-internal.o endif LIBS += -lgcrypt LIBS_p += -lgcrypt CONFIG_INTERNAL_SHA256=y CONFIG_INTERNAL_RC4=y CONFIG_INTERNAL_DH_GROUP5=y endif ifeq ($(CONFIG_TLS), schannel) ifdef TLS_FUNCS OBJS += ../src/crypto/tls_schannel.o endif OBJS += ../src/crypto/crypto_cryptoapi.o OBJS_p += ../src/crypto/crypto_cryptoapi.o ifdef NEED_FIPS186_2_PRF OBJS += ../src/crypto/fips_prf_internal.o SHA1OBJS += ../src/crypto/sha1-internal.o endif CONFIG_INTERNAL_SHA256=y CONFIG_INTERNAL_RC4=y CONFIG_INTERNAL_DH_GROUP5=y endif ifeq ($(CONFIG_TLS), nss) ifdef TLS_FUNCS OBJS += ../src/crypto/tls_nss.o LIBS += -lssl3 endif OBJS += ../src/crypto/crypto_nss.o OBJS_p += ../src/crypto/crypto_nss.o ifdef NEED_FIPS186_2_PRF OBJS += ../src/crypto/fips_prf_internal.o SHA1OBJS += ../src/crypto/sha1-internal.o endif LIBS += -lnss3 LIBS_p += -lnss3 CONFIG_INTERNAL_MD4=y CONFIG_INTERNAL_DH_GROUP5=y endif ifeq ($(CONFIG_TLS), internal) ifndef CONFIG_CRYPTO CONFIG_CRYPTO=internal endif ifdef TLS_FUNCS OBJS += ../src/crypto/crypto_internal-rsa.o OBJS += ../src/crypto/tls_internal.o OBJS += ../src/tls/tlsv1_common.o OBJS += ../src/tls/tlsv1_record.o OBJS += ../src/tls/tlsv1_cred.o OBJS += ../src/tls/tlsv1_client.o OBJS += ../src/tls/tlsv1_client_write.o OBJS += ../src/tls/tlsv1_client_read.o OBJS += ../src/tls/asn1.o OBJS += ../src/tls/rsa.o OBJS += ../src/tls/x509v3.o OBJS += ../src/tls/pkcs1.o OBJS += ../src/tls/pkcs5.o OBJS += ../src/tls/pkcs8.o NEED_SHA256=y NEED_BASE64=y NEED_TLS_PRF=y ifdef CONFIG_TLSV12 NEED_TLS_PRF_SHA256=y endif NEED_MODEXP=y NEED_CIPHER=y CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT endif ifdef NEED_CIPHER NEED_DES=y OBJS += ../src/crypto/crypto_internal-cipher.o endif ifdef NEED_MODEXP OBJS += ../src/crypto/crypto_internal-modexp.o OBJS += ../src/tls/bignum.o endif ifeq ($(CONFIG_CRYPTO), libtomcrypt) OBJS += ../src/crypto/crypto_libtomcrypt.o OBJS_p += ../src/crypto/crypto_libtomcrypt.o LIBS += -ltomcrypt -ltfm LIBS_p += -ltomcrypt -ltfm CONFIG_INTERNAL_SHA256=y CONFIG_INTERNAL_RC4=y CONFIG_INTERNAL_DH_GROUP5=y endif ifeq ($(CONFIG_CRYPTO), internal) OBJS += ../src/crypto/crypto_internal.o OBJS_p += ../src/crypto/crypto_internal.o NEED_AES_ENC=y CFLAGS += -DCONFIG_CRYPTO_INTERNAL ifdef CONFIG_INTERNAL_LIBTOMMATH CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST CFLAGS += -DLTM_FAST endif else LIBS += -ltommath LIBS_p += -ltommath endif CONFIG_INTERNAL_AES=y CONFIG_INTERNAL_DES=y CONFIG_INTERNAL_SHA1=y CONFIG_INTERNAL_MD4=y CONFIG_INTERNAL_MD5=y CONFIG_INTERNAL_SHA256=y CONFIG_INTERNAL_RC4=y CONFIG_INTERNAL_DH_GROUP5=y endif ifeq ($(CONFIG_CRYPTO), cryptoapi) OBJS += ../src/crypto/crypto_cryptoapi.o OBJS_p += ../src/crypto/crypto_cryptoapi.o CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI CONFIG_INTERNAL_SHA256=y CONFIG_INTERNAL_RC4=y endif endif ifeq ($(CONFIG_TLS), none) ifdef TLS_FUNCS OBJS += ../src/crypto/tls_none.o CFLAGS += -DEAP_TLS_NONE CONFIG_INTERNAL_AES=y CONFIG_INTERNAL_SHA1=y CONFIG_INTERNAL_MD5=y endif OBJS += ../src/crypto/crypto_none.o OBJS_p += ../src/crypto/crypto_none.o CONFIG_INTERNAL_SHA256=y CONFIG_INTERNAL_RC4=y endif ifdef TLS_FUNCS ifdef CONFIG_SMARTCARD ifndef CONFIG_NATIVE_WINDOWS ifneq ($(CONFIG_L2_PACKET), freebsd) LIBS += -ldl endif endif endif endif ifndef TLS_FUNCS OBJS += ../src/crypto/tls_none.o ifeq ($(CONFIG_TLS), internal) CONFIG_INTERNAL_AES=y CONFIG_INTERNAL_SHA1=y CONFIG_INTERNAL_MD5=y CONFIG_INTERNAL_RC4=y endif endif AESOBJS = # none so far (see below) ifdef CONFIG_INTERNAL_AES AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-dec.o endif AESOBJS += ../src/crypto/aes-unwrap.o ifdef NEED_AES_EAX AESOBJS += ../src/crypto/aes-eax.o NEED_AES_CTR=y endif ifdef NEED_AES_CTR AESOBJS += ../src/crypto/aes-ctr.o endif ifdef NEED_AES_ENCBLOCK AESOBJS += ../src/crypto/aes-encblock.o endif ifdef NEED_AES_OMAC1 NEED_AES_ENC=y ifdef CONFIG_OPENSSL_CMAC CFLAGS += -DCONFIG_OPENSSL_CMAC else AESOBJS += ../src/crypto/aes-omac1.o endif endif ifdef NEED_AES_WRAP NEED_AES_ENC=y AESOBJS += ../src/crypto/aes-wrap.o endif ifdef NEED_AES_CBC NEED_AES_ENC=y AESOBJS += ../src/crypto/aes-cbc.o endif ifdef NEED_AES_ENC ifdef CONFIG_INTERNAL_AES AESOBJS += ../src/crypto/aes-internal-enc.o endif endif ifdef NEED_AES OBJS += $(AESOBJS) endif ifdef NEED_SHA1 ifneq ($(CONFIG_TLS), openssl) SHA1OBJS += ../src/crypto/sha1.o endif SHA1OBJS += ../src/crypto/sha1-prf.o ifdef CONFIG_INTERNAL_SHA1 SHA1OBJS += ../src/crypto/sha1-internal.o ifdef NEED_FIPS186_2_PRF SHA1OBJS += ../src/crypto/fips_prf_internal.o endif endif ifdef CONFIG_NO_WPA_PASSPHRASE CFLAGS += -DCONFIG_NO_PBKDF2 else ifneq ($(CONFIG_TLS), openssl) SHA1OBJS += ../src/crypto/sha1-pbkdf2.o endif endif ifdef NEED_T_PRF SHA1OBJS += ../src/crypto/sha1-tprf.o endif ifdef NEED_TLS_PRF SHA1OBJS += ../src/crypto/sha1-tlsprf.o endif endif ifndef CONFIG_FIPS MD5OBJS += ../src/crypto/md5.o endif ifdef NEED_MD5 ifdef CONFIG_INTERNAL_MD5 MD5OBJS += ../src/crypto/md5-internal.o endif OBJS += $(MD5OBJS) OBJS_p += $(MD5OBJS) endif ifdef NEED_MD4 ifdef CONFIG_INTERNAL_MD4 OBJS += ../src/crypto/md4-internal.o endif endif DESOBJS = # none needed when not internal ifdef NEED_DES ifdef CONFIG_INTERNAL_DES DESOBJS += ../src/crypto/des-internal.o endif endif ifdef NEED_RC4 ifdef CONFIG_INTERNAL_RC4 OBJS += ../src/crypto/rc4.o endif endif SHA256OBJS = # none by default ifdef NEED_SHA256 CFLAGS += -DCONFIG_SHA256 ifneq ($(CONFIG_TLS), openssl) SHA256OBJS += ../src/crypto/sha256.o endif SHA256OBJS += ../src/crypto/sha256-prf.o ifdef CONFIG_INTERNAL_SHA256 SHA256OBJS += ../src/crypto/sha256-internal.o endif ifdef NEED_TLS_PRF_SHA256 SHA256OBJS += ../src/crypto/sha256-tlsprf.o endif OBJS += $(SHA256OBJS) endif ifdef NEED_DH_GROUPS OBJS += ../src/crypto/dh_groups.o endif ifdef NEED_DH_GROUPS_ALL CFLAGS += -DALL_DH_GROUPS endif ifdef CONFIG_INTERNAL_DH_GROUP5 ifdef NEED_DH_GROUPS OBJS += ../src/crypto/dh_group5.o endif endif ifdef NEED_ECC CFLAGS += -DCONFIG_ECC endif ifdef CONFIG_NO_RANDOM_POOL CFLAGS += -DCONFIG_NO_RANDOM_POOL else OBJS += ../src/crypto/random.o endif ifdef CONFIG_CTRL_IFACE ifeq ($(CONFIG_CTRL_IFACE), y) ifdef CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE=named_pipe else CONFIG_CTRL_IFACE=unix endif endif CFLAGS += -DCONFIG_CTRL_IFACE ifeq ($(CONFIG_CTRL_IFACE), unix) CFLAGS += -DCONFIG_CTRL_IFACE_UNIX endif ifeq ($(CONFIG_CTRL_IFACE), udp) CFLAGS += -DCONFIG_CTRL_IFACE_UDP endif ifeq ($(CONFIG_CTRL_IFACE), udp6) CONFIG_CTRL_IFACE=udp CFLAGS += -DCONFIG_CTRL_IFACE_UDP CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6 endif ifeq ($(CONFIG_CTRL_IFACE), named_pipe) CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE endif ifeq ($(CONFIG_CTRL_IFACE), udp-remote) CONFIG_CTRL_IFACE=udp CFLAGS += -DCONFIG_CTRL_IFACE_UDP CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE endif ifeq ($(CONFIG_CTRL_IFACE), udp6-remote) CONFIG_CTRL_IFACE=udp CFLAGS += -DCONFIG_CTRL_IFACE_UDP CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6 endif OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o endif ifdef CONFIG_CTRL_IFACE_DBUS DBUS=y DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE DBUS_OBJS += dbus/dbus_old.o dbus/dbus_old_handlers.o ifdef CONFIG_WPS DBUS_OBJS += dbus/dbus_old_handlers_wps.o endif DBUS_OBJS += dbus/dbus_dict_helpers.o ifndef DBUS_LIBS DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1) endif ifndef DBUS_INCLUDE DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1) endif DBUS_CFLAGS += $(DBUS_INCLUDE) endif ifdef CONFIG_CTRL_IFACE_DBUS_NEW DBUS=y DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW DBUS_OBJS ?= dbus/dbus_dict_helpers.o DBUS_OBJS += dbus/dbus_new_helpers.o DBUS_OBJS += dbus/dbus_new.o dbus/dbus_new_handlers.o ifdef CONFIG_WPS DBUS_OBJS += dbus/dbus_new_handlers_wps.o endif ifdef CONFIG_P2P DBUS_OBJS += dbus/dbus_new_handlers_p2p.o endif ifndef DBUS_LIBS DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1) endif ifndef DBUS_INCLUDE DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1) endif ifdef CONFIG_CTRL_IFACE_DBUS_INTRO DBUS_OBJS += dbus/dbus_new_introspect.o DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO endif DBUS_CFLAGS += $(DBUS_INCLUDE) endif ifdef DBUS DBUS_CFLAGS += -DCONFIG_DBUS DBUS_OBJS += dbus/dbus_common.o endif OBJS += $(DBUS_OBJS) CFLAGS += $(DBUS_CFLAGS) LIBS += $(DBUS_LIBS) ifdef CONFIG_READLINE OBJS_c += ../src/utils/edit_readline.o LIBS_c += -lncurses -lreadline else ifdef CONFIG_WPA_CLI_EDIT OBJS_c += ../src/utils/edit.o else OBJS_c += ../src/utils/edit_simple.o endif endif ifdef CONFIG_NATIVE_WINDOWS CFLAGS += -DCONFIG_NATIVE_WINDOWS LIBS += -lws2_32 -lgdi32 -lcrypt32 LIBS_c += -lws2_32 LIBS_p += -lws2_32 -lgdi32 ifeq ($(CONFIG_CRYPTO), cryptoapi) LIBS_p += -lcrypt32 endif endif ifdef CONFIG_NO_STDOUT_DEBUG CFLAGS += -DCONFIG_NO_STDOUT_DEBUG ifndef CONFIG_CTRL_IFACE CFLAGS += -DCONFIG_NO_WPA_MSG endif endif ifdef CONFIG_IPV6 # for eapol_test only CFLAGS += -DCONFIG_IPV6 endif ifdef NEED_BASE64 OBJS += ../src/utils/base64.o endif ifdef NEED_SME NEED_80211_COMMON=y OBJS += sme.o CFLAGS += -DCONFIG_SME endif ifdef NEED_80211_COMMON OBJS += ../src/common/ieee802_11_common.o endif ifdef NEED_EAP_COMMON OBJS += ../src/eap_common/eap_common.o endif ifndef CONFIG_MAIN CONFIG_MAIN=main endif ifdef CONFIG_DEBUG_SYSLOG CFLAGS += -DCONFIG_DEBUG_SYSLOG ifdef CONFIG_DEBUG_SYSLOG_FACILITY CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)" endif endif ifdef CONFIG_DEBUG_LINUX_TRACING CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING endif ifdef CONFIG_DEBUG_FILE CFLAGS += -DCONFIG_DEBUG_FILE endif ifdef CONFIG_DELAYED_MIC_ERROR_REPORT CFLAGS += -DCONFIG_DELAYED_MIC_ERROR_REPORT endif ifdef CONFIG_FIPS CFLAGS += -DCONFIG_FIPS ifneq ($(CONFIG_TLS), openssl) $(error CONFIG_FIPS=y requires CONFIG_TLS=openssl) endif endif OBJS += $(SHA1OBJS) $(DESOBJS) OBJS_p += $(SHA1OBJS) OBJS_p += $(SHA256OBJS) ifdef CONFIG_BGSCAN_SIMPLE CFLAGS += -DCONFIG_BGSCAN_SIMPLE OBJS += bgscan_simple.o NEED_BGSCAN=y endif ifdef CONFIG_BGSCAN_LEARN CFLAGS += -DCONFIG_BGSCAN_LEARN OBJS += bgscan_learn.o NEED_BGSCAN=y endif ifdef NEED_BGSCAN CFLAGS += -DCONFIG_BGSCAN OBJS += bgscan.o endif ifdef CONFIG_AUTOSCAN_EXPONENTIAL CFLAGS += -DCONFIG_AUTOSCAN_EXPONENTIAL OBJS += autoscan_exponential.o NEED_AUTOSCAN=y endif ifdef CONFIG_AUTOSCAN_PERIODIC CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC OBJS += autoscan_periodic.o NEED_AUTOSCAN=y endif ifdef NEED_AUTOSCAN CFLAGS += -DCONFIG_AUTOSCAN OBJS += autoscan.o endif ifdef CONFIG_EXT_PASSWORD_TEST OBJS += ../src/utils/ext_password_test.o CFLAGS += -DCONFIG_EXT_PASSWORD_TEST NEED_EXT_PASSWORD=y endif ifdef NEED_EXT_PASSWORD OBJS += ../src/utils/ext_password.o CFLAGS += -DCONFIG_EXT_PASSWORD endif ifdef NEED_GAS OBJS += ../src/common/gas.o OBJS += gas_query.o CFLAGS += -DCONFIG_GAS NEED_OFFCHANNEL=y endif ifdef NEED_OFFCHANNEL OBJS += offchannel.o CFLAGS += -DCONFIG_OFFCHANNEL endif ifdef CONFIG_MODULE_TESTS CFLAGS += -DCONFIG_MODULE_TESTS OBJS += wpas_module_tests.o OBJS += ../src/utils/utils_module_tests.o OBJS += ../src/common/common_module_tests.o ifdef CONFIG_WPS OBJS += ../src/wps/wps_module_tests.o endif endif OBJS += ../src/drivers/driver_common.o OBJS_priv += ../src/drivers/driver_common.o OBJS_wpa_rm := ctrl_iface.o ctrl_iface_unix.o OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.o ifdef CONFIG_AUTHENTICATOR OBJS_wpa += tests/link_test.o endif OBJS_wpa += $(OBJS_l2) OBJS += wpa_supplicant.o events.o blacklist.o wpas_glue.o scan.o OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o OBJS_t += ../src/radius/radius_client.o OBJS_t += ../src/radius/radius.o ifndef CONFIG_AP OBJS_t += ../src/utils/ip_addr.o endif OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o OBJS_nfc := $(OBJS) $(OBJS_l2) nfc_pw_token.o OBJS_nfc += $(OBJS_d) ../src/drivers/drivers.o OBJS += $(CONFIG_MAIN).o ifdef CONFIG_PRIVSEP OBJS_priv += $(OBJS_d) ../src/drivers/drivers.o OBJS_priv += $(OBJS_l2) OBJS_priv += ../src/utils/os_$(CONFIG_OS).o OBJS_priv += ../src/utils/$(CONFIG_ELOOP).o OBJS_priv += ../src/utils/common.o OBJS_priv += ../src/utils/wpa_debug.o OBJS_priv += ../src/utils/wpabuf.o OBJS_priv += wpa_priv.o ifdef CONFIG_DRIVER_NL80211 OBJS_priv += ../src/common/ieee802_11_common.o endif ifdef CONFIG_DRIVER_TEST OBJS_priv += $(SHA1OBJS) OBJS_priv += $(MD5OBJS) ifeq ($(CONFIG_TLS), openssl) OBJS_priv += ../src/crypto/crypto_openssl.o endif ifeq ($(CONFIG_TLS), gnutls) OBJS_priv += ../src/crypto/crypto_gnutls.o endif ifeq ($(CONFIG_TLS), nss) OBJS_priv += ../src/crypto/crypto_nss.o endif ifeq ($(CONFIG_TLS), internal) ifeq ($(CONFIG_CRYPTO), libtomcrypt) OBJS_priv += ../src/crypto/crypto_libtomcrypt.o else OBJS_priv += ../src/crypto/crypto_internal.o endif endif endif # CONFIG_DRIVER_TEST OBJS += ../src/l2_packet/l2_packet_privsep.o OBJS += ../src/drivers/driver_privsep.o EXTRA_progs += wpa_priv else OBJS += $(OBJS_d) ../src/drivers/drivers.o OBJS += $(OBJS_l2) endif ifdef CONFIG_NDIS_EVENTS_INTEGRATED CFLAGS += -DCONFIG_NDIS_EVENTS_INTEGRATED OBJS += ../src/drivers/ndis_events.o EXTRALIBS += -loleaut32 -lole32 -luuid ifdef PLATFORMSDKLIB EXTRALIBS += $(PLATFORMSDKLIB)/WbemUuid.Lib else EXTRALIBS += WbemUuid.Lib endif endif ifndef LDO LDO=$(CC) endif Q=@ E=echo ifeq ($(V), 1) Q= E=true endif dynamic_eap_methods: $(EAPDYN) ../src/drivers/build.wpa_supplicant: @if [ -f ../src/drivers/build.hostapd ]; then \ $(MAKE) -C ../src/drivers clean; \ fi @touch ../src/drivers/build.wpa_supplicant BCHECK=../src/drivers/build.wpa_supplicant wpa_priv: $(BCHECK) $(OBJS_priv) $(Q)$(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS) @$(E) " LD " $@ $(OBJS_c) $(OBJS_t) $(OBJS_t2) $(OBJS) $(BCHECK) $(EXTRA_progs): .config wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs) $(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS) @$(E) " LD " $@ eapol_test: $(OBJS_t) $(Q)$(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS) @$(E) " LD " $@ preauth_test: $(OBJS_t2) $(Q)$(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS) @$(E) " LD " $@ wpa_passphrase: $(OBJS_p) $(Q)$(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p) @$(E) " LD " $@ wpa_cli: $(OBJS_c) $(Q)$(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c) @$(E) " LD " $@ link_test: $(OBJS) $(OBJS_h) tests/link_test.o $(Q)$(LDO) $(LDFLAGS) -o link_test $(OBJS) $(OBJS_h) tests/link_test.o $(LIBS) @$(E) " LD " $@ test_wpa: $(OBJS_wpa) $(OBJS_h) $(Q)$(LDO) $(LDFLAGS) -o test_wpa $(OBJS_wpa) $(LIBS) @$(E) " LD " $@ nfc_pw_token: $(OBJS_nfc) $(Q)$(LDO) $(LDFLAGS) -o nfc_pw_token $(OBJS_nfc) $(LIBS) @$(E) " LD " $@ win_if_list: win_if_list.c $(Q)$(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w) @$(E) " LD " $@ eap_psk.so: ../src/eap_peer/eap_psk.c ../src/eap_common/eap_psk_common.c $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ -Deap_peer_psk_register=eap_peer_method_dynamic_init eap_pax.so: ../src/eap_peer/eap_pax.c ../src/eap_common/eap_pax_common.c $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ -Deap_peer_pax_register=eap_peer_method_dynamic_init eap_sake.so: ../src/eap_peer/eap_sake.c ../src/eap_common/eap_sake_common.c $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ -Deap_peer_sake_register=eap_peer_method_dynamic_init eap_wsc.so: ../src/eap_peer/eap_wsc.c ../src/eap_common/eap_wsc_common.c ../src/wps/wps.c $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ -Deap_peer_wsc_register=eap_peer_method_dynamic_init eap_ikev2.so: ../src/eap_peer/eap_ikev2.c ../src/eap_peer/ikev2.c ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.c $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ -Deap_peer_ikev2_register=eap_peer_method_dynamic_init eap_eke.so: ../src/eap_peer/eap_eke.c ../src/eap_common/eap_eke_common.c $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ -Deap_peer_eke_register=eap_peer_method_dynamic_init %.so: %.c $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \ -D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init ifdef CONFIG_CODE_COVERAGE %.o: %.c @$(E) " CC " $< $(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<) else %.o: %.c $(Q)$(CC) -c -o $@ $(CFLAGS) $< @$(E) " CC " $< endif %.service: %.service.in sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@ %@.service: %.service.arg.in sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@ wpa_supplicant.exe: wpa_supplicant mv -f $< $@ wpa_cli.exe: wpa_cli mv -f $< $@ wpa_passphrase.exe: wpa_passphrase mv -f $< $@ win_if_list.exe: win_if_list mv -f $< $@ eapol_test.exe: eapol_test mv -f $< $@ WINALL=wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe win_if_list.exe windows-bin: $(WINALL) $(STRIP) $(WINALL) wpa_gui: @echo "wpa_gui has been removed - see wpa_gui-qt4 for replacement" wpa_gui-qt4/Makefile: qmake -o wpa_gui-qt4/Makefile wpa_gui-qt4/wpa_gui.pro wpa_gui-qt4/lang/wpa_gui_de.qm: wpa_gui-qt4/lang/wpa_gui_de.ts lrelease wpa_gui-qt4/wpa_gui.pro wpa_gui-qt4: wpa_gui-qt4/Makefile wpa_gui-qt4/lang/wpa_gui_de.qm $(MAKE) -C wpa_gui-qt4 TEST_EAP_SIM_COMMON_OBJS = $(SHA1OBJS) $(MD5OBJS) \ ../src/utils/common.o ../src/utils/os_unix.o \ ../src/utils/wpa_debug.o $(AESOBJS) \ tests/test_eap_sim_common.o test-eap_sim_common: $(TEST_EAP_SIM_COMMON_OBJS) $(LDO) $(LDFLAGS) -o $@ $(TEST_EAP_SIM_COMMON_OBJS) $(LIBS) ./test-eap_sim_common rm test-eap_sim_common tests: test-eap_sim_common FIPSDIR=/usr/local/ssl/fips-2.0 FIPSLD=$(FIPSDIR)/bin/fipsld fips: $(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)" lcov-html: wpa_supplicant.gcda lcov -c -d .. > lcov.info genhtml lcov.info --output-directory lcov-html clean: $(MAKE) -C ../src clean $(MAKE) -C dbus clean rm -f core *~ *.o *.d *.gcno *.gcda *.gcov rm -f eap_*.so $(ALL) $(WINALL) eapol_test preauth_test rm -f wpa_priv rm -f nfc_pw_token rm -f lcov.info rm -rf lcov-html -include $(OBJS:%.o=%.d) wpa_supplicant-2.2/wpa_supplicant/autoscan.h0000664000175000017500000000210512343617166017234 0ustar jmjm/* * WPA Supplicant - auto scan * Copyright (c) 2012, Intel Corporation. All rights reserved. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef AUTOSCAN_H #define AUTOSCAN_H struct wpa_supplicant; struct autoscan_ops { const char *name; void * (*init)(struct wpa_supplicant *wpa_s, const char *params); void (*deinit)(void *priv); int (*notify_scan)(void *priv, struct wpa_scan_results *scan_res); }; #ifdef CONFIG_AUTOSCAN int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan); void autoscan_deinit(struct wpa_supplicant *wpa_s); int autoscan_notify_scan(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); #else /* CONFIG_AUTOSCAN */ static inline int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan) { return 0; } static inline void autoscan_deinit(struct wpa_supplicant *wpa_s) { } static inline int autoscan_notify_scan(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { return 0; } #endif /* CONFIG_AUTOSCAN */ #endif /* AUTOSCAN_H */ wpa_supplicant-2.2/wpa_supplicant/tests/0000775000175000017500000000000012343617166016412 5ustar jmjmwpa_supplicant-2.2/wpa_supplicant/tests/link_test.c0000664000175000017500000000302112343617166020546 0ustar jmjm/* * Dummy functions to allow link_test to be linked. The need for these * functions should be removed to allow IEEE 802.1X/EAPOL authenticator to * be built outside hostapd. */ #include "includes.h" #include "common.h" struct hostapd_data; struct sta_info; struct rsn_pmksa_cache_entry; struct eapol_state_machine; struct hostapd_eap_user; struct hostapd_bss_config; struct hostapd_vlan; struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta) { return NULL; } int ap_for_each_sta(struct hostapd_data *hapd, int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, void *ctx), void *ctx) { return 0; } void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta, u32 session_timeout) { } int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, int old_vlanid) { return 0; } void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta, int success) { } void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta, u8 *buf, size_t len) { } void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) { } void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry, struct eapol_state_machine *eapol) { } const struct hostapd_eap_user * hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity, size_t identity_len, int phase2) { return NULL; } const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id) { return NULL; } wpa_supplicant-2.2/wpa_supplicant/tests/test_eap_sim_common.c0000664000175000017500000000206112343617166022601 0ustar jmjm/* * Test program for EAP-SIM PRF * Copyright (c) 2004-2006, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "eap_common/eap_sim_common.c" static int test_eap_sim_prf(void) { /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */ u8 xkey[] = { 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b, 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f, 0xeb, 0x5a, 0x38, 0xb6 }; u8 w[] = { 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f, 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49, 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba, 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78, 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16 }; u8 buf[40]; printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n"); eap_sim_prf(xkey, buf, sizeof(buf)); if (memcmp(w, buf, sizeof(w)) != 0) { printf("eap_sim_prf failed\n"); return 1; } return 0; } int main(int argc, char *argv[]) { int errors = 0; errors += test_eap_sim_prf(); return errors; } wpa_supplicant-2.2/wpa_supplicant/tests/test_wpa.c0000664000175000017500000002042512343617166020407 0ustar jmjm/* * Test program for combined WPA authenticator/supplicant * Copyright (c) 2006-2007, 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 "eloop.h" #include "common/ieee802_11_defs.h" #include "../config.h" #include "rsn_supp/wpa.h" #include "rsn_supp/wpa_ie.h" #include "ap/wpa_auth.h" struct wpa { u8 auth_addr[ETH_ALEN]; u8 supp_addr[ETH_ALEN]; u8 psk[PMK_LEN]; /* from authenticator */ u8 auth_eapol_dst[ETH_ALEN]; u8 *auth_eapol; size_t auth_eapol_len; /* from supplicant */ u8 *supp_eapol; size_t supp_eapol_len; struct wpa_sm *supp; struct wpa_authenticator *auth_group; struct wpa_state_machine *auth; struct wpa_ssid ssid; u8 supp_ie[80]; size_t supp_ie_len; }; static int supp_get_bssid(void *ctx, u8 *bssid) { struct wpa *wpa = ctx; wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); os_memcpy(bssid, wpa->auth_addr, ETH_ALEN); return 0; } static void supp_set_state(void *ctx, enum wpa_states state) { wpa_printf(MSG_DEBUG, "SUPP: %s(state=%d)", __func__, state); } static void auth_eapol_rx(void *eloop_data, void *user_ctx) { struct wpa *wpa = eloop_data; wpa_printf(MSG_DEBUG, "AUTH: RX EAPOL frame"); wpa_receive(wpa->auth_group, wpa->auth, wpa->supp_eapol, wpa->supp_eapol_len); } static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf, size_t len) { struct wpa *wpa = ctx; wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x " "len=%lu)", __func__, MAC2STR(dest), proto, (unsigned long) len); os_free(wpa->supp_eapol); wpa->supp_eapol = os_malloc(len); if (wpa->supp_eapol == NULL) return -1; os_memcpy(wpa->supp_eapol, buf, len); wpa->supp_eapol_len = len; eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL); return 0; } static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data, u16 data_len, size_t *msg_len, void **data_pos) { struct ieee802_1x_hdr *hdr; wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)", __func__, type, data_len); *msg_len = sizeof(*hdr) + data_len; hdr = os_malloc(*msg_len); if (hdr == NULL) return NULL; hdr->version = 2; hdr->type = type; hdr->length = host_to_be16(data_len); if (data) os_memcpy(hdr + 1, data, data_len); else os_memset(hdr + 1, 0, data_len); if (data_pos) *data_pos = hdr + 1; return (u8 *) hdr; } static int supp_get_beacon_ie(void *ctx) { struct wpa *wpa = ctx; const u8 *ie; size_t ielen; wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); ie = wpa_auth_get_wpa_ie(wpa->auth_group, &ielen); if (ie == NULL || ielen < 1) return -1; if (ie[0] == WLAN_EID_RSN) return wpa_sm_set_ap_rsn_ie(wpa->supp, ie, 2 + ie[1]); return wpa_sm_set_ap_wpa_ie(wpa->supp, ie, 2 + ie[1]); } static int supp_set_key(void *ctx, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len) { wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d " "set_tx=%d)", __func__, alg, MAC2STR(addr), key_idx, set_tx); wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len); wpa_hexdump(MSG_DEBUG, "SUPP: set_key - key", key, key_len); return 0; } static int supp_mlme_setprotection(void *ctx, const u8 *addr, int protection_type, int key_type) { wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d " "key_type=%d)", __func__, MAC2STR(addr), protection_type, key_type); return 0; } static void supp_cancel_auth_timeout(void *ctx) { wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); } static int supp_init(struct wpa *wpa) { struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx)); if (ctx == NULL) return -1; ctx->ctx = wpa; ctx->msg_ctx = wpa; ctx->set_state = supp_set_state; ctx->get_bssid = supp_get_bssid; ctx->ether_send = supp_ether_send; ctx->get_beacon_ie = supp_get_beacon_ie; ctx->alloc_eapol = supp_alloc_eapol; ctx->set_key = supp_set_key; ctx->mlme_setprotection = supp_mlme_setprotection; ctx->cancel_auth_timeout = supp_cancel_auth_timeout; wpa->supp = wpa_sm_init(ctx); if (wpa->supp == NULL) { wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed"); return -1; } wpa_sm_set_own_addr(wpa->supp, wpa->supp_addr); wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 1); wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN); wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP); wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP); wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK); wpa_sm_set_pmk(wpa->supp, wpa->psk, PMK_LEN); wpa->supp_ie_len = sizeof(wpa->supp_ie); if (wpa_sm_set_assoc_wpa_ie_default(wpa->supp, wpa->supp_ie, &wpa->supp_ie_len) < 0) { wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()" " failed"); return -1; } wpa_sm_notify_assoc(wpa->supp, wpa->auth_addr); return 0; } static void auth_logger(void *ctx, const u8 *addr, logger_level level, const char *txt) { if (addr) wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s", MAC2STR(addr), txt); else wpa_printf(MSG_DEBUG, "AUTH: %s", txt); } static void supp_eapol_rx(void *eloop_data, void *user_ctx) { struct wpa *wpa = eloop_data; wpa_printf(MSG_DEBUG, "SUPP: RX EAPOL frame"); wpa_sm_rx_eapol(wpa->supp, wpa->auth_addr, wpa->auth_eapol, wpa->auth_eapol_len); } static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data, size_t data_len, int encrypt) { struct wpa *wpa = ctx; wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu " "encrypt=%d)", __func__, MAC2STR(addr), (unsigned long) data_len, encrypt); os_free(wpa->auth_eapol); wpa->auth_eapol = os_malloc(data_len); if (wpa->auth_eapol == NULL) return -1; os_memcpy(wpa->auth_eapol_dst, addr, ETH_ALEN); os_memcpy(wpa->auth_eapol, data, data_len); wpa->auth_eapol_len = data_len; eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL); return 0; } static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk) { struct wpa *wpa = ctx; wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", __func__, MAC2STR(addr), prev_psk); if (prev_psk) return NULL; return wpa->psk; } static int auth_init_group(struct wpa *wpa) { struct wpa_auth_config conf; struct wpa_auth_callbacks cb; wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); os_memset(&conf, 0, sizeof(conf)); conf.wpa = 2; conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK; conf.wpa_pairwise = WPA_CIPHER_CCMP; conf.rsn_pairwise = WPA_CIPHER_CCMP; conf.wpa_group = WPA_CIPHER_CCMP; conf.eapol_version = 2; os_memset(&cb, 0, sizeof(cb)); cb.ctx = wpa; cb.logger = auth_logger; cb.send_eapol = auth_send_eapol; cb.get_psk = auth_get_psk; wpa->auth_group = wpa_init(wpa->auth_addr, &conf, &cb); if (wpa->auth_group == NULL) { wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed"); return -1; } return 0; } static int auth_init(struct wpa *wpa) { wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr, NULL); if (wpa->auth == NULL) { wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed"); return -1; } if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, wpa->supp_ie, wpa->supp_ie_len, NULL, 0) != WPA_IE_OK) { wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); return -1; } wpa_auth_sm_event(wpa->auth, WPA_ASSOC); wpa_auth_sta_associated(wpa->auth_group, wpa->auth); return 0; } static void deinit(struct wpa *wpa) { wpa_auth_sta_deinit(wpa->auth); wpa_sm_deinit(wpa->supp); wpa_deinit(wpa->auth_group); os_free(wpa->auth_eapol); wpa->auth_eapol = NULL; os_free(wpa->supp_eapol); wpa->supp_eapol = NULL; } int main(int argc, char *argv[]) { struct wpa wpa; if (os_program_init()) return -1; os_memset(&wpa, 0, sizeof(wpa)); os_memset(wpa.auth_addr, 0x12, ETH_ALEN); os_memset(wpa.supp_addr, 0x32, ETH_ALEN); os_memset(wpa.psk, 0x44, PMK_LEN); wpa_debug_level = 0; wpa_debug_show_keys = 1; if (eloop_init()) { wpa_printf(MSG_ERROR, "Failed to initialize event loop"); return -1; } if (auth_init_group(&wpa) < 0) return -1; if (supp_init(&wpa) < 0) return -1; if (auth_init(&wpa) < 0) return -1; wpa_printf(MSG_DEBUG, "Starting eloop"); eloop_run(); wpa_printf(MSG_DEBUG, "eloop done"); deinit(&wpa); eloop_destroy(); os_program_deinit(); return 0; } wpa_supplicant-2.2/wpa_supplicant/config_winreg.c0000664000175000017500000005765312343617166020254 0ustar jmjm/* * WPA Supplicant / Configuration backend: Windows registry * Copyright (c) 2003-2008, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. * * This file implements a configuration backend for Windows registry. All the * configuration information is stored in the registry and the format for * network configuration fields is same as described in the sample * configuration file, wpa_supplicant.conf. * * Configuration data is in * \a HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant\\configs * key. Each configuration profile has its own key under this. In terms of text * files, each profile would map to a separate text file with possibly multiple * networks. Under each profile, there is a networks key that lists all * networks as a subkey. Each network has set of values in the same way as * network block in the configuration file. In addition, blobs subkey has * possible blobs as values. * * Example network configuration block: * \verbatim HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000 ssid="example" key_mgmt=WPA-PSK \endverbatim */ #include "includes.h" #include "common.h" #include "uuid.h" #include "config.h" #ifndef WPA_KEY_ROOT #define WPA_KEY_ROOT HKEY_LOCAL_MACHINE #endif #ifndef WPA_KEY_PREFIX #define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant") #endif #ifdef UNICODE #define TSTR "%S" #else /* UNICODE */ #define TSTR "%s" #endif /* UNICODE */ static int wpa_config_read_blobs(struct wpa_config *config, HKEY hk) { struct wpa_config_blob *blob; int errors = 0; HKEY bhk; LONG ret; DWORD i; ret = RegOpenKeyEx(hk, TEXT("blobs"), 0, KEY_QUERY_VALUE, &bhk); if (ret != ERROR_SUCCESS) { wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config " "blobs key"); return 0; /* assume no blobs */ } for (i = 0; ; i++) { #define TNAMELEN 255 TCHAR name[TNAMELEN]; char data[4096]; DWORD namelen, datalen, type; namelen = TNAMELEN; datalen = sizeof(data); ret = RegEnumValue(bhk, i, name, &namelen, NULL, &type, (LPBYTE) data, &datalen); if (ret == ERROR_NO_MORE_ITEMS) break; if (ret != ERROR_SUCCESS) { wpa_printf(MSG_DEBUG, "RegEnumValue failed: 0x%x", (unsigned int) ret); break; } if (namelen >= TNAMELEN) namelen = TNAMELEN - 1; name[namelen] = TEXT('\0'); wpa_unicode2ascii_inplace(name); if (datalen >= sizeof(data)) datalen = sizeof(data) - 1; wpa_printf(MSG_MSGDUMP, "blob %d: field='%s' len %d", (int) i, name, (int) datalen); blob = os_zalloc(sizeof(*blob)); if (blob == NULL) { errors++; break; } blob->name = os_strdup((char *) name); blob->data = os_malloc(datalen); if (blob->name == NULL || blob->data == NULL) { wpa_config_free_blob(blob); errors++; break; } os_memcpy(blob->data, data, datalen); blob->len = datalen; wpa_config_set_blob(config, blob); } RegCloseKey(bhk); return errors ? -1 : 0; } static int wpa_config_read_reg_dword(HKEY hk, const TCHAR *name, int *_val) { DWORD val, buflen; LONG ret; buflen = sizeof(val); ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) &val, &buflen); if (ret == ERROR_SUCCESS && buflen == sizeof(val)) { wpa_printf(MSG_DEBUG, TSTR "=%d", name, (int) val); *_val = val; return 0; } return -1; } static char * wpa_config_read_reg_string(HKEY hk, const TCHAR *name) { DWORD buflen; LONG ret; TCHAR *val; buflen = 0; ret = RegQueryValueEx(hk, name, NULL, NULL, NULL, &buflen); if (ret != ERROR_SUCCESS) return NULL; val = os_malloc(buflen); if (val == NULL) return NULL; ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) val, &buflen); if (ret != ERROR_SUCCESS) { os_free(val); return NULL; } wpa_unicode2ascii_inplace(val); wpa_printf(MSG_DEBUG, TSTR "=%s", name, (char *) val); return (char *) val; } #ifdef CONFIG_WPS static int wpa_config_read_global_uuid(struct wpa_config *config, HKEY hk) { char *str; int ret = 0; str = wpa_config_read_reg_string(hk, TEXT("uuid")); if (str == NULL) return 0; if (uuid_str2bin(str, config->uuid)) ret = -1; os_free(str); return ret; } static int wpa_config_read_global_os_version(struct wpa_config *config, HKEY hk) { char *str; int ret = 0; str = wpa_config_read_reg_string(hk, TEXT("os_version")); if (str == NULL) return 0; if (hexstr2bin(str, config->os_version, 4)) ret = -1; os_free(str); return ret; } #endif /* CONFIG_WPS */ static int wpa_config_read_global(struct wpa_config *config, HKEY hk) { int errors = 0; int val; wpa_config_read_reg_dword(hk, TEXT("ap_scan"), &config->ap_scan); wpa_config_read_reg_dword(hk, TEXT("fast_reauth"), &config->fast_reauth); wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"), (int *) &config->dot11RSNAConfigPMKLifetime); wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigPMKReauthThreshold"), (int *) &config->dot11RSNAConfigPMKReauthThreshold); wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"), (int *) &config->dot11RSNAConfigSATimeout); wpa_config_read_reg_dword(hk, TEXT("update_config"), &config->update_config); if (wpa_config_read_reg_dword(hk, TEXT("eapol_version"), &config->eapol_version) == 0) { if (config->eapol_version < 1 || config->eapol_version > 2) { wpa_printf(MSG_ERROR, "Invalid EAPOL version (%d)", config->eapol_version); errors++; } } config->ctrl_interface = wpa_config_read_reg_string( hk, TEXT("ctrl_interface")); #ifdef CONFIG_WPS if (wpa_config_read_global_uuid(config, hk)) errors++; config->device_name = wpa_config_read_reg_string( hk, TEXT("device_name")); config->manufacturer = wpa_config_read_reg_string( hk, TEXT("manufacturer")); config->model_name = wpa_config_read_reg_string( hk, TEXT("model_name")); config->serial_number = wpa_config_read_reg_string( hk, TEXT("serial_number")); { char *t = wpa_config_read_reg_string( hk, TEXT("device_type")); if (t && wps_dev_type_str2bin(t, config->device_type)) errors++; os_free(t); } config->config_methods = wpa_config_read_reg_string( hk, TEXT("config_methods")); if (wpa_config_read_global_os_version(config, hk)) errors++; wpa_config_read_reg_dword(hk, TEXT("wps_cred_processing"), &config->wps_cred_processing); #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P config->p2p_ssid_postfix = wpa_config_read_reg_string( hk, TEXT("p2p_ssid_postfix")); wpa_config_read_reg_dword(hk, TEXT("p2p_group_idle"), (int *) &config->p2p_group_idle); #endif /* CONFIG_P2P */ wpa_config_read_reg_dword(hk, TEXT("bss_max_count"), (int *) &config->bss_max_count); wpa_config_read_reg_dword(hk, TEXT("filter_ssids"), &config->filter_ssids); wpa_config_read_reg_dword(hk, TEXT("max_num_sta"), (int *) &config->max_num_sta); wpa_config_read_reg_dword(hk, TEXT("disassoc_low_ack"), (int *) &config->disassoc_low_ack); wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc); wpa_config_read_reg_dword(hk, TEXT("pmf"), &val); config->pmf = val; return errors ? -1 : 0; } static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw, int id) { HKEY nhk; LONG ret; DWORD i; struct wpa_ssid *ssid; int errors = 0; ret = RegOpenKeyEx(hk, netw, 0, KEY_QUERY_VALUE, &nhk); if (ret != ERROR_SUCCESS) { wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config " "network '" TSTR "'", netw); return NULL; } wpa_printf(MSG_MSGDUMP, "Start of a new network '" TSTR "'", netw); ssid = os_zalloc(sizeof(*ssid)); if (ssid == NULL) { RegCloseKey(nhk); return NULL; } dl_list_init(&ssid->psk_list); ssid->id = id; wpa_config_set_network_defaults(ssid); for (i = 0; ; i++) { TCHAR name[255], data[1024]; DWORD namelen, datalen, type; namelen = 255; datalen = sizeof(data); ret = RegEnumValue(nhk, i, name, &namelen, NULL, &type, (LPBYTE) data, &datalen); if (ret == ERROR_NO_MORE_ITEMS) break; if (ret != ERROR_SUCCESS) { wpa_printf(MSG_ERROR, "RegEnumValue failed: 0x%x", (unsigned int) ret); break; } if (namelen >= 255) namelen = 255 - 1; name[namelen] = TEXT('\0'); if (datalen >= 1024) datalen = 1024 - 1; data[datalen] = TEXT('\0'); wpa_unicode2ascii_inplace(name); wpa_unicode2ascii_inplace(data); if (wpa_config_set(ssid, (char *) name, (char *) data, 0) < 0) errors++; } RegCloseKey(nhk); if (ssid->passphrase) { if (ssid->psk_set) { wpa_printf(MSG_ERROR, "Both PSK and passphrase " "configured for network '" TSTR "'.", netw); errors++; } wpa_config_update_psk(ssid); } if ((ssid->group_cipher & WPA_CIPHER_CCMP) && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) && !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) { /* Group cipher cannot be stronger than the pairwise cipher. */ wpa_printf(MSG_DEBUG, "Removed CCMP from group cipher " "list since it was not allowed for pairwise " "cipher for network '" TSTR "'.", netw); ssid->group_cipher &= ~WPA_CIPHER_CCMP; } if (errors) { wpa_config_free_ssid(ssid); ssid = NULL; } return ssid; } static int wpa_config_read_networks(struct wpa_config *config, HKEY hk) { HKEY nhk; struct wpa_ssid *ssid, *tail = NULL, *head = NULL; int errors = 0; LONG ret; DWORD i; ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_ENUMERATE_SUB_KEYS, &nhk); if (ret != ERROR_SUCCESS) { wpa_printf(MSG_ERROR, "Could not open wpa_supplicant networks " "registry key"); return -1; } for (i = 0; ; i++) { TCHAR name[255]; DWORD namelen; namelen = 255; ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL, NULL); if (ret == ERROR_NO_MORE_ITEMS) break; if (ret != ERROR_SUCCESS) { wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x", (unsigned int) ret); break; } if (namelen >= 255) namelen = 255 - 1; name[namelen] = '\0'; ssid = wpa_config_read_network(nhk, name, i); if (ssid == NULL) { wpa_printf(MSG_ERROR, "Failed to parse network " "profile '%s'.", name); errors++; continue; } if (head == NULL) { head = tail = ssid; } else { tail->next = ssid; tail = ssid; } if (wpa_config_add_prio_network(config, ssid)) { wpa_printf(MSG_ERROR, "Failed to add network profile " "'%s' to priority list.", name); errors++; continue; } } RegCloseKey(nhk); config->ssid = head; return errors ? -1 : 0; } struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) { TCHAR buf[256]; int errors = 0; struct wpa_config *config; HKEY hk; LONG ret; if (name == NULL) return NULL; if (cfgp) config = cfgp; else config = wpa_config_alloc_empty(NULL, NULL); if (config == NULL) return NULL; wpa_printf(MSG_DEBUG, "Reading configuration profile '%s'", name); #ifdef UNICODE _snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name); #else /* UNICODE */ os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name); #endif /* UNICODE */ ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_QUERY_VALUE, &hk); if (ret != ERROR_SUCCESS) { wpa_printf(MSG_ERROR, "Could not open wpa_supplicant " "configuration registry HKLM\\" TSTR, buf); os_free(config); return NULL; } if (wpa_config_read_global(config, hk)) errors++; if (wpa_config_read_networks(config, hk)) errors++; if (wpa_config_read_blobs(config, hk)) errors++; wpa_config_debug_dump_networks(config); RegCloseKey(hk); if (errors) { wpa_config_free(config); config = NULL; } return config; } static int wpa_config_write_reg_dword(HKEY hk, const TCHAR *name, int val, int def) { LONG ret; DWORD _val = val; if (val == def) { RegDeleteValue(hk, name); return 0; } ret = RegSetValueEx(hk, name, 0, REG_DWORD, (LPBYTE) &_val, sizeof(_val)); if (ret != ERROR_SUCCESS) { wpa_printf(MSG_ERROR, "WINREG: Failed to set %s=%d: error %d", name, val, (int) GetLastError()); return -1; } return 0; } static int wpa_config_write_reg_string(HKEY hk, const char *name, const char *val) { LONG ret; TCHAR *_name, *_val; _name = wpa_strdup_tchar(name); if (_name == NULL) return -1; if (val == NULL) { RegDeleteValue(hk, _name); os_free(_name); return 0; } _val = wpa_strdup_tchar(val); if (_val == NULL) { os_free(_name); return -1; } ret = RegSetValueEx(hk, _name, 0, REG_SZ, (BYTE *) _val, (os_strlen(val) + 1) * sizeof(TCHAR)); if (ret != ERROR_SUCCESS) { wpa_printf(MSG_ERROR, "WINREG: Failed to set %s='%s': " "error %d", name, val, (int) GetLastError()); os_free(_name); os_free(_val); return -1; } os_free(_name); os_free(_val); return 0; } static int wpa_config_write_global(struct wpa_config *config, HKEY hk) { #ifdef CONFIG_CTRL_IFACE wpa_config_write_reg_string(hk, "ctrl_interface", config->ctrl_interface); #endif /* CONFIG_CTRL_IFACE */ wpa_config_write_reg_dword(hk, TEXT("eapol_version"), config->eapol_version, DEFAULT_EAPOL_VERSION); wpa_config_write_reg_dword(hk, TEXT("ap_scan"), config->ap_scan, DEFAULT_AP_SCAN); wpa_config_write_reg_dword(hk, TEXT("fast_reauth"), config->fast_reauth, DEFAULT_FAST_REAUTH); wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"), config->dot11RSNAConfigPMKLifetime, 0); wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigPMKReauthThreshold"), config->dot11RSNAConfigPMKReauthThreshold, 0); wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"), config->dot11RSNAConfigSATimeout, 0); wpa_config_write_reg_dword(hk, TEXT("update_config"), config->update_config, 0); #ifdef CONFIG_WPS if (!is_nil_uuid(config->uuid)) { char buf[40]; uuid_bin2str(config->uuid, buf, sizeof(buf)); wpa_config_write_reg_string(hk, "uuid", buf); } wpa_config_write_reg_string(hk, "device_name", config->device_name); wpa_config_write_reg_string(hk, "manufacturer", config->manufacturer); wpa_config_write_reg_string(hk, "model_name", config->model_name); wpa_config_write_reg_string(hk, "model_number", config->model_number); wpa_config_write_reg_string(hk, "serial_number", config->serial_number); { char _buf[WPS_DEV_TYPE_BUFSIZE], *buf; buf = wps_dev_type_bin2str(config->device_type, _buf, sizeof(_buf)); wpa_config_write_reg_string(hk, "device_type", buf); } wpa_config_write_reg_string(hk, "config_methods", config->config_methods); if (WPA_GET_BE32(config->os_version)) { char vbuf[10]; os_snprintf(vbuf, sizeof(vbuf), "%08x", WPA_GET_BE32(config->os_version)); wpa_config_write_reg_string(hk, "os_version", vbuf); } wpa_config_write_reg_dword(hk, TEXT("wps_cred_processing"), config->wps_cred_processing, 0); #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P wpa_config_write_reg_string(hk, "p2p_ssid_postfix", config->p2p_ssid_postfix); wpa_config_write_reg_dword(hk, TEXT("p2p_group_idle"), config->p2p_group_idle, 0); #endif /* CONFIG_P2P */ wpa_config_write_reg_dword(hk, TEXT("bss_max_count"), config->bss_max_count, DEFAULT_BSS_MAX_COUNT); wpa_config_write_reg_dword(hk, TEXT("filter_ssids"), config->filter_ssids, 0); wpa_config_write_reg_dword(hk, TEXT("max_num_sta"), config->max_num_sta, DEFAULT_MAX_NUM_STA); wpa_config_write_reg_dword(hk, TEXT("disassoc_low_ack"), config->disassoc_low_ack, 0); wpa_config_write_reg_dword(hk, TEXT("okc"), config->okc, 0); wpa_config_write_reg_dword(hk, TEXT("pmf"), config->pmf, 0); wpa_config_write_reg_dword(hk, TEXT("external_sim"), config->external_sim, 0); return 0; } static int wpa_config_delete_subkeys(HKEY hk, const TCHAR *key) { HKEY nhk; int i, errors = 0; LONG ret; ret = RegOpenKeyEx(hk, key, 0, KEY_ENUMERATE_SUB_KEYS | DELETE, &nhk); if (ret != ERROR_SUCCESS) { wpa_printf(MSG_DEBUG, "WINREG: Could not open key '" TSTR "' for subkey deletion: error 0x%x (%d)", key, (unsigned int) ret, (int) GetLastError()); return 0; } for (i = 0; ; i++) { TCHAR name[255]; DWORD namelen; namelen = 255; ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL, NULL); if (ret == ERROR_NO_MORE_ITEMS) break; if (ret != ERROR_SUCCESS) { wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x (%d)", (unsigned int) ret, (int) GetLastError()); break; } if (namelen >= 255) namelen = 255 - 1; name[namelen] = TEXT('\0'); ret = RegDeleteKey(nhk, name); if (ret != ERROR_SUCCESS) { wpa_printf(MSG_DEBUG, "RegDeleteKey failed: 0x%x (%d)", (unsigned int) ret, (int) GetLastError()); errors++; } } RegCloseKey(nhk); return errors ? -1 : 0; } static void write_str(HKEY hk, const char *field, struct wpa_ssid *ssid) { char *value = wpa_config_get(ssid, field); if (value == NULL) return; wpa_config_write_reg_string(hk, field, value); os_free(value); } static void write_int(HKEY hk, const char *field, int value, int def) { char val[20]; if (value == def) return; os_snprintf(val, sizeof(val), "%d", value); wpa_config_write_reg_string(hk, field, val); } static void write_bssid(HKEY hk, struct wpa_ssid *ssid) { char *value = wpa_config_get(ssid, "bssid"); if (value == NULL) return; wpa_config_write_reg_string(hk, "bssid", value); os_free(value); } static void write_psk(HKEY hk, struct wpa_ssid *ssid) { char *value = wpa_config_get(ssid, "psk"); if (value == NULL) return; wpa_config_write_reg_string(hk, "psk", value); os_free(value); } static void write_proto(HKEY hk, struct wpa_ssid *ssid) { char *value; if (ssid->proto == DEFAULT_PROTO) return; value = wpa_config_get(ssid, "proto"); if (value == NULL) return; if (value[0]) wpa_config_write_reg_string(hk, "proto", value); os_free(value); } static void write_key_mgmt(HKEY hk, struct wpa_ssid *ssid) { char *value; if (ssid->key_mgmt == DEFAULT_KEY_MGMT) return; value = wpa_config_get(ssid, "key_mgmt"); if (value == NULL) return; if (value[0]) wpa_config_write_reg_string(hk, "key_mgmt", value); os_free(value); } static void write_pairwise(HKEY hk, struct wpa_ssid *ssid) { char *value; if (ssid->pairwise_cipher == DEFAULT_PAIRWISE) return; value = wpa_config_get(ssid, "pairwise"); if (value == NULL) return; if (value[0]) wpa_config_write_reg_string(hk, "pairwise", value); os_free(value); } static void write_group(HKEY hk, struct wpa_ssid *ssid) { char *value; if (ssid->group_cipher == DEFAULT_GROUP) return; value = wpa_config_get(ssid, "group"); if (value == NULL) return; if (value[0]) wpa_config_write_reg_string(hk, "group", value); os_free(value); } static void write_auth_alg(HKEY hk, struct wpa_ssid *ssid) { char *value; if (ssid->auth_alg == 0) return; value = wpa_config_get(ssid, "auth_alg"); if (value == NULL) return; if (value[0]) wpa_config_write_reg_string(hk, "auth_alg", value); os_free(value); } #ifdef IEEE8021X_EAPOL static void write_eap(HKEY hk, struct wpa_ssid *ssid) { char *value; value = wpa_config_get(ssid, "eap"); if (value == NULL) return; if (value[0]) wpa_config_write_reg_string(hk, "eap", value); os_free(value); } #endif /* IEEE8021X_EAPOL */ static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid) { char field[20], *value; os_snprintf(field, sizeof(field), "wep_key%d", idx); value = wpa_config_get(ssid, field); if (value) { wpa_config_write_reg_string(hk, field, value); os_free(value); } } static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id) { int i, errors = 0; HKEY nhk, netw; LONG ret; TCHAR name[5]; ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_CREATE_SUB_KEY, &nhk); if (ret != ERROR_SUCCESS) { wpa_printf(MSG_DEBUG, "WINREG: Could not open networks key " "for subkey addition: error 0x%x (%d)", (unsigned int) ret, (int) GetLastError()); return 0; } #ifdef UNICODE wsprintf(name, L"%04d", id); #else /* UNICODE */ os_snprintf(name, sizeof(name), "%04d", id); #endif /* UNICODE */ ret = RegCreateKeyEx(nhk, name, 0, NULL, 0, KEY_WRITE, NULL, &netw, NULL); RegCloseKey(nhk); if (ret != ERROR_SUCCESS) { wpa_printf(MSG_DEBUG, "WINREG: Could not add network key '%s':" " error 0x%x (%d)", name, (unsigned int) ret, (int) GetLastError()); return -1; } #define STR(t) write_str(netw, #t, ssid) #define INT(t) write_int(netw, #t, ssid->t, 0) #define INTe(t) write_int(netw, #t, ssid->eap.t, 0) #define INT_DEF(t, def) write_int(netw, #t, ssid->t, def) #define INT_DEFe(t, def) write_int(netw, #t, ssid->eap.t, def) STR(ssid); INT(scan_ssid); write_bssid(netw, ssid); write_psk(netw, ssid); write_proto(netw, ssid); write_key_mgmt(netw, ssid); write_pairwise(netw, ssid); write_group(netw, ssid); write_auth_alg(netw, ssid); #ifdef IEEE8021X_EAPOL write_eap(netw, ssid); STR(identity); STR(anonymous_identity); STR(password); STR(ca_cert); STR(ca_path); STR(client_cert); STR(private_key); STR(private_key_passwd); STR(dh_file); STR(subject_match); STR(altsubject_match); STR(ca_cert2); STR(ca_path2); STR(client_cert2); STR(private_key2); STR(private_key2_passwd); STR(dh_file2); STR(subject_match2); STR(altsubject_match2); STR(phase1); STR(phase2); STR(pcsc); STR(pin); STR(engine_id); STR(key_id); STR(cert_id); STR(ca_cert_id); STR(key2_id); STR(pin2); STR(engine2_id); STR(cert2_id); STR(ca_cert2_id); INTe(engine); INTe(engine2); INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS); #endif /* IEEE8021X_EAPOL */ for (i = 0; i < 4; i++) write_wep_key(netw, i, ssid); INT(wep_tx_keyidx); INT(priority); #ifdef IEEE8021X_EAPOL INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND); STR(pac_file); INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE); #endif /* IEEE8021X_EAPOL */ INT(mode); write_int(netw, "proactive_key_caching", ssid->proactive_key_caching, -1); INT(disabled); INT(peerkey); #ifdef CONFIG_IEEE80211W write_int(netw, "ieee80211w", ssid->ieee80211w, MGMT_FRAME_PROTECTION_DEFAULT); #endif /* CONFIG_IEEE80211W */ STR(id_str); #undef STR #undef INT #undef INT_DEF RegCloseKey(netw); return errors ? -1 : 0; } static int wpa_config_write_blob(HKEY hk, struct wpa_config_blob *blob) { HKEY bhk; LONG ret; TCHAR *name; ret = RegCreateKeyEx(hk, TEXT("blobs"), 0, NULL, 0, KEY_WRITE, NULL, &bhk, NULL); if (ret != ERROR_SUCCESS) { wpa_printf(MSG_DEBUG, "WINREG: Could not add blobs key: " "error 0x%x (%d)", (unsigned int) ret, (int) GetLastError()); return -1; } name = wpa_strdup_tchar(blob->name); ret = RegSetValueEx(bhk, name, 0, REG_BINARY, blob->data, blob->len); if (ret != ERROR_SUCCESS) { wpa_printf(MSG_ERROR, "WINREG: Failed to set blob %s': " "error 0x%x (%d)", blob->name, (unsigned int) ret, (int) GetLastError()); RegCloseKey(bhk); os_free(name); return -1; } os_free(name); RegCloseKey(bhk); return 0; } int wpa_config_write(const char *name, struct wpa_config *config) { TCHAR buf[256]; HKEY hk; LONG ret; int errors = 0; struct wpa_ssid *ssid; struct wpa_config_blob *blob; int id; wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name); #ifdef UNICODE _snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name); #else /* UNICODE */ os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name); #endif /* UNICODE */ ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_SET_VALUE | DELETE, &hk); if (ret != ERROR_SUCCESS) { wpa_printf(MSG_ERROR, "Could not open wpa_supplicant " "configuration registry %s: error %d", buf, (int) GetLastError()); return -1; } if (wpa_config_write_global(config, hk)) { wpa_printf(MSG_ERROR, "Failed to write global configuration " "data"); errors++; } wpa_config_delete_subkeys(hk, TEXT("networks")); for (ssid = config->ssid, id = 0; ssid; ssid = ssid->next, id++) { if (ssid->key_mgmt == WPA_KEY_MGMT_WPS) continue; /* do not save temporary WPS networks */ if (wpa_config_write_network(hk, ssid, id)) errors++; } RegDeleteKey(hk, TEXT("blobs")); for (blob = config->blobs; blob; blob = blob->next) { if (wpa_config_write_blob(hk, blob)) errors++; } RegCloseKey(hk); wpa_printf(MSG_DEBUG, "Configuration '%s' written %ssuccessfully", name, errors ? "un" : ""); return errors ? -1 : 0; } wpa_supplicant-2.2/wpa_supplicant/interworking.c0000664000175000017500000022430612343617166020145 0ustar jmjm/* * Interworking (IEEE 802.11u) * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. * Copyright (c) 2011-2014, 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 "common/ieee802_11_defs.h" #include "common/gas.h" #include "common/wpa_ctrl.h" #include "utils/pcsc_funcs.h" #include "utils/eloop.h" #include "drivers/driver.h" #include "eap_common/eap_defs.h" #include "eap_peer/eap.h" #include "eap_peer/eap_methods.h" #include "eapol_supp/eapol_supp_sm.h" #include "rsn_supp/wpa.h" #include "wpa_supplicant_i.h" #include "config.h" #include "config_ssid.h" #include "bss.h" #include "scan.h" #include "notify.h" #include "driver_i.h" #include "gas_query.h" #include "hs20_supplicant.h" #include "interworking.h" #if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC) #define INTERWORKING_3GPP #else #if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC) #define INTERWORKING_3GPP #else #if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC) #define INTERWORKING_3GPP #endif #endif #endif static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s); static struct wpa_cred * interworking_credentials_available_realm( struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw, int *excluded); static struct wpa_cred * interworking_credentials_available_3gpp( struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw, int *excluded); static int cred_prio_cmp(const struct wpa_cred *a, const struct wpa_cred *b) { if (a->priority > b->priority) return 1; if (a->priority < b->priority) return -1; if (a->provisioning_sp == NULL || b->provisioning_sp == NULL || os_strcmp(a->provisioning_sp, b->provisioning_sp) != 0) return 0; if (a->sp_priority < b->sp_priority) return 1; if (a->sp_priority > b->sp_priority) return -1; return 0; } static void interworking_reconnect(struct wpa_supplicant *wpa_s) { if (wpa_s->wpa_state >= WPA_AUTHENTICATING) { wpa_supplicant_cancel_sched_scan(wpa_s); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); } wpa_s->disconnected = 0; wpa_s->reassociate = 1; if (wpa_supplicant_fast_associate(wpa_s) >= 0) return; wpa_supplicant_req_scan(wpa_s, 0, 0); } static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids, struct wpabuf *extra) { struct wpabuf *buf; size_t i; u8 *len_pos; buf = gas_anqp_build_initial_req(0, 4 + num_ids * 2 + (extra ? wpabuf_len(extra) : 0)); if (buf == NULL) return NULL; len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST); for (i = 0; i < num_ids; i++) wpabuf_put_le16(buf, info_ids[i]); gas_anqp_set_element_len(buf, len_pos); if (extra) wpabuf_put_buf(buf, extra); gas_anqp_set_len(buf); return buf; } static void interworking_anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, const struct wpabuf *resp, u16 status_code) { struct wpa_supplicant *wpa_s = ctx; wpa_printf(MSG_DEBUG, "ANQP: Response callback dst=" MACSTR " dialog_token=%u result=%d status_code=%u", MAC2STR(dst), dialog_token, result, status_code); anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp, status_code); interworking_next_anqp_fetch(wpa_s); } static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s) { struct wpa_cred *cred; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { if (cred->roaming_consortium_len) return 1; if (cred->required_roaming_consortium_len) return 1; } return 0; } static int cred_with_3gpp(struct wpa_supplicant *wpa_s) { struct wpa_cred *cred; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { if (cred->pcsc || cred->imsi) return 1; } return 0; } static int cred_with_nai_realm(struct wpa_supplicant *wpa_s) { struct wpa_cred *cred; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { if (cred->pcsc || cred->imsi) continue; if (!cred->eap_method) return 1; if (cred->realm && cred->roaming_consortium_len == 0) return 1; } return 0; } static int cred_with_domain(struct wpa_supplicant *wpa_s) { struct wpa_cred *cred; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { if (cred->domain || cred->pcsc || cred->imsi || cred->roaming_partner) return 1; } return 0; } #ifdef CONFIG_HS20 static int cred_with_min_backhaul(struct wpa_supplicant *wpa_s) { struct wpa_cred *cred; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { if (cred->min_dl_bandwidth_home || cred->min_ul_bandwidth_home || cred->min_dl_bandwidth_roaming || cred->min_ul_bandwidth_roaming) return 1; } return 0; } static int cred_with_conn_capab(struct wpa_supplicant *wpa_s) { struct wpa_cred *cred; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { if (cred->num_req_conn_capab) return 1; } return 0; } #endif /* CONFIG_HS20 */ static int additional_roaming_consortiums(struct wpa_bss *bss) { const u8 *ie; ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); if (ie == NULL || ie[1] == 0) return 0; return ie[2]; /* Number of ANQP OIs */ } static void interworking_continue_anqp(void *eloop_ctx, void *sock_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; interworking_next_anqp_fetch(wpa_s); } static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { struct wpabuf *buf; int ret = 0; int res; u16 info_ids[8]; size_t num_info_ids = 0; struct wpabuf *extra = NULL; int all = wpa_s->fetch_all_anqp; wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR, MAC2STR(bss->bssid)); wpa_s->interworking_gas_bss = bss; info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST; if (all) { info_ids[num_info_ids++] = ANQP_VENUE_NAME; info_ids[num_info_ids++] = ANQP_NETWORK_AUTH_TYPE; } if (all || (cred_with_roaming_consortium(wpa_s) && additional_roaming_consortiums(bss))) info_ids[num_info_ids++] = ANQP_ROAMING_CONSORTIUM; if (all) info_ids[num_info_ids++] = ANQP_IP_ADDR_TYPE_AVAILABILITY; if (all || cred_with_nai_realm(wpa_s)) info_ids[num_info_ids++] = ANQP_NAI_REALM; if (all || cred_with_3gpp(wpa_s)) { info_ids[num_info_ids++] = ANQP_3GPP_CELLULAR_NETWORK; wpa_supplicant_scard_init(wpa_s, NULL); } if (all || cred_with_domain(wpa_s)) info_ids[num_info_ids++] = ANQP_DOMAIN_NAME; wpa_hexdump(MSG_DEBUG, "Interworking: ANQP Query info", (u8 *) info_ids, num_info_ids * 2); #ifdef CONFIG_HS20 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) { u8 *len_pos; extra = wpabuf_alloc(100); if (!extra) return -1; len_pos = gas_anqp_add_element(extra, ANQP_VENDOR_SPECIFIC); wpabuf_put_be24(extra, OUI_WFA); wpabuf_put_u8(extra, HS20_ANQP_OUI_TYPE); wpabuf_put_u8(extra, HS20_STYPE_QUERY_LIST); wpabuf_put_u8(extra, 0); /* Reserved */ wpabuf_put_u8(extra, HS20_STYPE_CAPABILITY_LIST); if (all) wpabuf_put_u8(extra, HS20_STYPE_OPERATOR_FRIENDLY_NAME); if (all || cred_with_min_backhaul(wpa_s)) wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS); if (all || cred_with_conn_capab(wpa_s)) wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY); if (all) wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS); if (all) wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_LIST); gas_anqp_set_element_len(extra, len_pos); } #endif /* CONFIG_HS20 */ buf = anqp_build_req(info_ids, num_info_ids, extra); wpabuf_free(extra); if (buf == NULL) return -1; res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf, interworking_anqp_resp_cb, wpa_s); if (res < 0) { wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); wpabuf_free(buf); ret = -1; eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s, NULL); } else wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " "%u", res); return ret; } struct nai_realm_eap { u8 method; u8 inner_method; enum nai_realm_eap_auth_inner_non_eap inner_non_eap; u8 cred_type; u8 tunneled_cred_type; }; struct nai_realm { u8 encoding; char *realm; u8 eap_count; struct nai_realm_eap *eap; }; static void nai_realm_free(struct nai_realm *realms, u16 count) { u16 i; if (realms == NULL) return; for (i = 0; i < count; i++) { os_free(realms[i].eap); os_free(realms[i].realm); } os_free(realms); } static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos, const u8 *end) { u8 elen, auth_count, a; const u8 *e_end; if (pos + 3 > end) { wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields"); return NULL; } elen = *pos++; if (pos + elen > end || elen < 2) { wpa_printf(MSG_DEBUG, "No room for EAP Method subfield"); return NULL; } e_end = pos + elen; e->method = *pos++; auth_count = *pos++; wpa_printf(MSG_DEBUG, "EAP Method: len=%u method=%u auth_count=%u", elen, e->method, auth_count); for (a = 0; a < auth_count; a++) { u8 id, len; if (pos + 2 > end || pos + 2 + pos[1] > end) { wpa_printf(MSG_DEBUG, "No room for Authentication " "Parameter subfield"); return NULL; } id = *pos++; len = *pos++; switch (id) { case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH: if (len < 1) break; e->inner_non_eap = *pos; if (e->method != EAP_TYPE_TTLS) break; switch (*pos) { case NAI_REALM_INNER_NON_EAP_PAP: wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP"); break; case NAI_REALM_INNER_NON_EAP_CHAP: wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP"); break; case NAI_REALM_INNER_NON_EAP_MSCHAP: wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP"); break; case NAI_REALM_INNER_NON_EAP_MSCHAPV2: wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2"); break; } break; case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD: if (len < 1) break; e->inner_method = *pos; wpa_printf(MSG_DEBUG, "Inner EAP method: %u", e->inner_method); break; case NAI_REALM_EAP_AUTH_CRED_TYPE: if (len < 1) break; e->cred_type = *pos; wpa_printf(MSG_DEBUG, "Credential Type: %u", e->cred_type); break; case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE: if (len < 1) break; e->tunneled_cred_type = *pos; wpa_printf(MSG_DEBUG, "Tunneled EAP Method Credential " "Type: %u", e->tunneled_cred_type); break; default: wpa_printf(MSG_DEBUG, "Unsupported Authentication " "Parameter: id=%u len=%u", id, len); wpa_hexdump(MSG_DEBUG, "Authentication Parameter " "Value", pos, len); break; } pos += len; } return e_end; } static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos, const u8 *end) { u16 len; const u8 *f_end; u8 realm_len, e; if (end - pos < 4) { wpa_printf(MSG_DEBUG, "No room for NAI Realm Data " "fixed fields"); return NULL; } len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */ pos += 2; if (pos + len > end || len < 3) { wpa_printf(MSG_DEBUG, "No room for NAI Realm Data " "(len=%u; left=%u)", len, (unsigned int) (end - pos)); return NULL; } f_end = pos + len; r->encoding = *pos++; realm_len = *pos++; if (pos + realm_len > f_end) { wpa_printf(MSG_DEBUG, "No room for NAI Realm " "(len=%u; left=%u)", realm_len, (unsigned int) (f_end - pos)); return NULL; } wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len); r->realm = dup_binstr(pos, realm_len); if (r->realm == NULL) return NULL; pos += realm_len; if (pos + 1 > f_end) { wpa_printf(MSG_DEBUG, "No room for EAP Method Count"); return NULL; } r->eap_count = *pos++; wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count); if (pos + r->eap_count * 3 > f_end) { wpa_printf(MSG_DEBUG, "No room for EAP Methods"); return NULL; } r->eap = os_calloc(r->eap_count, sizeof(struct nai_realm_eap)); if (r->eap == NULL) return NULL; for (e = 0; e < r->eap_count; e++) { pos = nai_realm_parse_eap(&r->eap[e], pos, f_end); if (pos == NULL) return NULL; } return f_end; } static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count) { struct nai_realm *realm; const u8 *pos, *end; u16 i, num; if (anqp == NULL || wpabuf_len(anqp) < 2) return NULL; pos = wpabuf_head_u8(anqp); end = pos + wpabuf_len(anqp); num = WPA_GET_LE16(pos); wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num); pos += 2; if (num * 5 > end - pos) { wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not " "enough data (%u octets) for that many realms", num, (unsigned int) (end - pos)); return NULL; } realm = os_calloc(num, sizeof(struct nai_realm)); if (realm == NULL) return NULL; for (i = 0; i < num; i++) { pos = nai_realm_parse_realm(&realm[i], pos, end); if (pos == NULL) { nai_realm_free(realm, num); return NULL; } } *count = num; return realm; } static int nai_realm_match(struct nai_realm *realm, const char *home_realm) { char *tmp, *pos, *end; int match = 0; if (realm->realm == NULL || home_realm == NULL) return 0; if (os_strchr(realm->realm, ';') == NULL) return os_strcasecmp(realm->realm, home_realm) == 0; tmp = os_strdup(realm->realm); if (tmp == NULL) return 0; pos = tmp; while (*pos) { end = os_strchr(pos, ';'); if (end) *end = '\0'; if (os_strcasecmp(pos, home_realm) == 0) { match = 1; break; } if (end == NULL) break; pos = end + 1; } os_free(tmp); return match; } static int nai_realm_cred_username(struct nai_realm_eap *eap) { if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) return 0; /* method not supported */ if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP && eap->method != EAP_TYPE_FAST) { /* Only tunneled methods with username/password supported */ return 0; } if (eap->method == EAP_TYPE_PEAP || eap->method == EAP_TYPE_FAST) { if (eap->inner_method && eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) return 0; if (!eap->inner_method && eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL) return 0; } if (eap->method == EAP_TYPE_TTLS) { if (eap->inner_method == 0 && eap->inner_non_eap == 0) return 1; /* Assume TTLS/MSCHAPv2 is used */ if (eap->inner_method && eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) return 0; if (eap->inner_non_eap && eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP && eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP && eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP && eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2) return 0; } if (eap->inner_method && eap->inner_method != EAP_TYPE_GTC && eap->inner_method != EAP_TYPE_MSCHAPV2) return 0; return 1; } static int nai_realm_cred_cert(struct nai_realm_eap *eap) { if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) return 0; /* method not supported */ if (eap->method != EAP_TYPE_TLS) { /* Only EAP-TLS supported for credential authentication */ return 0; } return 1; } static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred, struct nai_realm *realm) { u8 e; if (cred == NULL || cred->username == NULL || cred->username[0] == '\0' || ((cred->password == NULL || cred->password[0] == '\0') && (cred->private_key == NULL || cred->private_key[0] == '\0'))) return NULL; for (e = 0; e < realm->eap_count; e++) { struct nai_realm_eap *eap = &realm->eap[e]; if (cred->password && cred->password[0] && nai_realm_cred_username(eap)) return eap; if (cred->private_key && cred->private_key[0] && nai_realm_cred_cert(eap)) return eap; } return NULL; } #ifdef INTERWORKING_3GPP static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) { u8 plmn[3], plmn2[3]; const u8 *pos, *end; u8 udhl; /* * See Annex A of 3GPP TS 24.234 v8.1.0 for description. The network * operator is allowed to include only two digits of the MNC, so allow * matches based on both two and three digit MNC assumptions. Since some * SIM/USIM cards may not expose MNC length conveniently, we may be * provided the default MNC length 3 here and as such, checking with MNC * length 2 is justifiable even though 3GPP TS 24.234 does not mention * that case. Anyway, MCC/MNC pair where both 2 and 3 digit MNC is used * with otherwise matching values would not be good idea in general, so * this should not result in selecting incorrect networks. */ /* Match with 3 digit MNC */ plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4); plmn[1] = (imsi[2] - '0') | ((imsi[5] - '0') << 4); plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4); /* Match with 2 digit MNC */ plmn2[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4); plmn2[1] = (imsi[2] - '0') | 0xf0; plmn2[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4); if (anqp == NULL) return 0; pos = wpabuf_head_u8(anqp); end = pos + wpabuf_len(anqp); if (pos + 2 > end) return 0; if (*pos != 0) { wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos); return 0; } pos++; udhl = *pos++; if (pos + udhl > end) { wpa_printf(MSG_DEBUG, "Invalid UDHL"); return 0; } end = pos + udhl; wpa_printf(MSG_DEBUG, "Interworking: Matching against MCC/MNC alternatives: %02x:%02x:%02x or %02x:%02x:%02x (IMSI %s, MNC length %d)", plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2], imsi, mnc_len); while (pos + 2 <= end) { u8 iei, len; const u8 *l_end; iei = *pos++; len = *pos++ & 0x7f; if (pos + len > end) break; l_end = pos + len; if (iei == 0 && len > 0) { /* PLMN List */ u8 num, i; wpa_hexdump(MSG_DEBUG, "Interworking: PLMN List information element", pos, len); num = *pos++; for (i = 0; i < num; i++) { if (pos + 3 > l_end) break; if (os_memcmp(pos, plmn, 3) == 0 || os_memcmp(pos, plmn2, 3) == 0) return 1; /* Found matching PLMN */ pos += 3; } } else { wpa_hexdump(MSG_DEBUG, "Interworking: Unrecognized 3GPP information element", pos, len); } pos = l_end; } return 0; } static int build_root_nai(char *nai, size_t nai_len, const char *imsi, size_t mnc_len, char prefix) { const char *sep, *msin; char *end, *pos; size_t msin_len, plmn_len; /* * TS 23.003, Clause 14 (3GPP to WLAN Interworking) * Root NAI: * @wlan.mnc.mcc.3gppnetwork.org * is zero-padded to three digits in case two-digit MNC is used */ if (imsi == NULL || os_strlen(imsi) > 16) { wpa_printf(MSG_DEBUG, "No valid IMSI available"); return -1; } sep = os_strchr(imsi, '-'); if (sep) { plmn_len = sep - imsi; msin = sep + 1; } else if (mnc_len && os_strlen(imsi) >= 3 + mnc_len) { plmn_len = 3 + mnc_len; msin = imsi + plmn_len; } else return -1; if (plmn_len != 5 && plmn_len != 6) return -1; msin_len = os_strlen(msin); pos = nai; end = nai + nai_len; if (prefix) *pos++ = prefix; os_memcpy(pos, imsi, plmn_len); pos += plmn_len; os_memcpy(pos, msin, msin_len); pos += msin_len; pos += os_snprintf(pos, end - pos, "@wlan.mnc"); if (plmn_len == 5) { *pos++ = '0'; *pos++ = imsi[3]; *pos++ = imsi[4]; } else { *pos++ = imsi[3]; *pos++ = imsi[4]; *pos++ = imsi[5]; } pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org", imsi[0], imsi[1], imsi[2]); return 0; } static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix) { char nai[100]; if (build_root_nai(nai, sizeof(nai), imsi, 0, prefix) < 0) return -1; return wpa_config_set_quoted(ssid, "identity", nai); } #endif /* INTERWORKING_3GPP */ static int already_connected(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_bss *bss) { struct wpa_ssid *ssid, *sel_ssid; struct wpa_bss *selected; if (wpa_s->wpa_state < WPA_ASSOCIATED || wpa_s->current_ssid == NULL) return 0; ssid = wpa_s->current_ssid; if (ssid->parent_cred != cred) return 0; if (ssid->ssid_len != bss->ssid_len || os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0) return 0; sel_ssid = NULL; selected = wpa_supplicant_pick_network(wpa_s, &sel_ssid); if (selected && sel_ssid && sel_ssid->priority > ssid->priority) return 0; /* higher priority network in scan results */ return 1; } static void remove_duplicate_network(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_bss *bss) { struct wpa_ssid *ssid; for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (ssid->parent_cred != cred) continue; if (ssid->ssid_len != bss->ssid_len || os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0) continue; break; } if (ssid == NULL) return; wpa_printf(MSG_DEBUG, "Interworking: Remove duplicate network entry for the same credential"); if (ssid == wpa_s->current_ssid) { wpa_sm_set_config(wpa_s->wpa, NULL); eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); } wpas_notify_network_removed(wpa_s, ssid); wpa_config_remove_network(wpa_s->conf, ssid->id); } static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { const char *key_mgmt = NULL; #ifdef CONFIG_IEEE80211R int res; struct wpa_driver_capa capa; res = wpa_drv_get_capa(wpa_s, &capa); if (res == 0 && capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) { key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ? "WPA-EAP WPA-EAP-SHA256 FT-EAP" : "WPA-EAP FT-EAP"; } #endif /* CONFIG_IEEE80211R */ if (!key_mgmt) key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ? "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP"; if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0) return -1; if (wpa_config_set(ssid, "proto", "RSN", 0) < 0) return -1; if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0) return -1; return 0; } static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_bss *bss) { #ifdef INTERWORKING_3GPP struct wpa_ssid *ssid; int eap_type; int res; char prefix; if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL) return -1; wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)", MAC2STR(bss->bssid)); if (already_connected(wpa_s, cred, bss)) { wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, MAC2STR(bss->bssid)); return 0; } remove_duplicate_network(wpa_s, cred, bss); ssid = wpa_config_add_network(wpa_s->conf); if (ssid == NULL) return -1; ssid->parent_cred = cred; wpas_notify_network_added(wpa_s, ssid); wpa_config_set_network_defaults(ssid); ssid->priority = cred->priority; ssid->temporary = 1; ssid->ssid = os_zalloc(bss->ssid_len + 1); if (ssid->ssid == NULL) goto fail; os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len); ssid->ssid_len = bss->ssid_len; ssid->eap.sim_num = cred->sim_num; if (interworking_set_hs20_params(wpa_s, ssid) < 0) goto fail; eap_type = EAP_TYPE_SIM; if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard)) eap_type = EAP_TYPE_AKA; if (cred->eap_method && cred->eap_method[0].vendor == EAP_VENDOR_IETF) { if (cred->eap_method[0].method == EAP_TYPE_SIM || cred->eap_method[0].method == EAP_TYPE_AKA || cred->eap_method[0].method == EAP_TYPE_AKA_PRIME) eap_type = cred->eap_method[0].method; } switch (eap_type) { case EAP_TYPE_SIM: prefix = '1'; res = wpa_config_set(ssid, "eap", "SIM", 0); break; case EAP_TYPE_AKA: prefix = '0'; res = wpa_config_set(ssid, "eap", "AKA", 0); break; case EAP_TYPE_AKA_PRIME: prefix = '6'; res = wpa_config_set(ssid, "eap", "AKA'", 0); break; default: res = -1; break; } if (res < 0) { wpa_printf(MSG_DEBUG, "Selected EAP method (%d) not supported", eap_type); goto fail; } if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) { wpa_printf(MSG_DEBUG, "Failed to set Root NAI"); goto fail; } if (cred->milenage && cred->milenage[0]) { if (wpa_config_set_quoted(ssid, "password", cred->milenage) < 0) goto fail; } else if (cred->pcsc) { if (wpa_config_set_quoted(ssid, "pcsc", "") < 0) goto fail; if (wpa_s->conf->pcsc_pin && wpa_config_set_quoted(ssid, "pin", wpa_s->conf->pcsc_pin) < 0) goto fail; } wpa_s->next_ssid = ssid; wpa_config_update_prio_list(wpa_s->conf); interworking_reconnect(wpa_s); return 0; fail: wpas_notify_network_removed(wpa_s, ssid); wpa_config_remove_network(wpa_s->conf, ssid->id); #endif /* INTERWORKING_3GPP */ return -1; } static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id, size_t rc_len) { const u8 *pos, *end; u8 lens; if (ie == NULL) return 0; pos = ie + 2; end = ie + 2 + ie[1]; /* Roaming Consortium element: * Number of ANQP OIs * OI #1 and #2 lengths * OI #1, [OI #2], [OI #3] */ if (pos + 2 > end) return 0; pos++; /* skip Number of ANQP OIs */ lens = *pos++; if (pos + (lens & 0x0f) + (lens >> 4) > end) return 0; if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) return 1; pos += lens & 0x0f; if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) return 1; pos += lens >> 4; if (pos < end && (size_t) (end - pos) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) return 1; return 0; } static int roaming_consortium_anqp_match(const struct wpabuf *anqp, const u8 *rc_id, size_t rc_len) { const u8 *pos, *end; u8 len; if (anqp == NULL) return 0; pos = wpabuf_head(anqp); end = pos + wpabuf_len(anqp); /* Set of duples */ while (pos < end) { len = *pos++; if (pos + len > end) break; if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) return 1; pos += len; } return 0; } static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp, const u8 *rc_id, size_t rc_len) { return roaming_consortium_element_match(ie, rc_id, rc_len) || roaming_consortium_anqp_match(anqp, rc_id, rc_len); } static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss) { const u8 *ie; if (cred->required_roaming_consortium_len == 0) return 0; ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); if (ie == NULL && (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL)) return 1; return !roaming_consortium_match(ie, bss->anqp ? bss->anqp->roaming_consortium : NULL, cred->required_roaming_consortium, cred->required_roaming_consortium_len); } static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss) { size_t i; if (!cred->excluded_ssid) return 0; for (i = 0; i < cred->num_excluded_ssid; i++) { struct excluded_ssid *e = &cred->excluded_ssid[i]; if (bss->ssid_len == e->ssid_len && os_memcmp(bss->ssid, e->ssid, e->ssid_len) == 0) return 1; } return 0; } static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_bss *bss) { int res; unsigned int dl_bandwidth, ul_bandwidth; const u8 *wan; u8 wan_info, dl_load, ul_load; u16 lmd; u32 ul_speed, dl_speed; if (!cred->min_dl_bandwidth_home && !cred->min_ul_bandwidth_home && !cred->min_dl_bandwidth_roaming && !cred->min_ul_bandwidth_roaming) return 0; /* No bandwidth constraint specified */ if (bss->anqp == NULL || bss->anqp->hs20_wan_metrics == NULL) return 0; /* No WAN Metrics known - ignore constraint */ wan = wpabuf_head(bss->anqp->hs20_wan_metrics); wan_info = wan[0]; if (wan_info & BIT(3)) return 1; /* WAN link at capacity */ lmd = WPA_GET_LE16(wan + 11); if (lmd == 0) return 0; /* Downlink/Uplink Load was not measured */ dl_speed = WPA_GET_LE32(wan + 1); ul_speed = WPA_GET_LE32(wan + 5); dl_load = wan[9]; ul_load = wan[10]; if (dl_speed >= 0xffffff) dl_bandwidth = dl_speed / 255 * (255 - dl_load); else dl_bandwidth = dl_speed * (255 - dl_load) / 255; if (ul_speed >= 0xffffff) ul_bandwidth = ul_speed / 255 * (255 - ul_load); else ul_bandwidth = ul_speed * (255 - ul_load) / 255; res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ? bss->anqp->domain_name : NULL); if (res > 0) { if (cred->min_dl_bandwidth_home > dl_bandwidth) return 1; if (cred->min_ul_bandwidth_home > ul_bandwidth) return 1; } else { if (cred->min_dl_bandwidth_roaming > dl_bandwidth) return 1; if (cred->min_ul_bandwidth_roaming > ul_bandwidth) return 1; } return 0; } static int cred_over_max_bss_load(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_bss *bss) { const u8 *ie; int res; if (!cred->max_bss_load) return 0; /* No BSS Load constraint specified */ ie = wpa_bss_get_ie(bss, WLAN_EID_BSS_LOAD); if (ie == NULL || ie[1] < 3) return 0; /* No BSS Load advertised */ res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ? bss->anqp->domain_name : NULL); if (res <= 0) return 0; /* Not a home network */ return ie[4] > cred->max_bss_load; } static int has_proto_match(const u8 *pos, const u8 *end, u8 proto) { while (pos + 4 <= end) { if (pos[0] == proto && pos[3] == 1 /* Open */) return 1; pos += 4; } return 0; } static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto, u16 port) { while (pos + 4 <= end) { if (pos[0] == proto && WPA_GET_LE16(&pos[1]) == port && pos[3] == 1 /* Open */) return 1; pos += 4; } return 0; } static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_bss *bss) { int res; const u8 *capab, *end; unsigned int i, j; int *ports; if (!cred->num_req_conn_capab) return 0; /* No connection capability constraint specified */ if (bss->anqp == NULL || bss->anqp->hs20_connection_capability == NULL) return 0; /* No Connection Capability known - ignore constraint */ res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ? bss->anqp->domain_name : NULL); if (res > 0) return 0; /* No constraint in home network */ capab = wpabuf_head(bss->anqp->hs20_connection_capability); end = capab + wpabuf_len(bss->anqp->hs20_connection_capability); for (i = 0; i < cred->num_req_conn_capab; i++) { ports = cred->req_conn_capab_port[i]; if (!ports) { if (!has_proto_match(capab, end, cred->req_conn_capab_proto[i])) return 1; } else { for (j = 0; ports[j] > -1; j++) { if (!has_proto_port_match( capab, end, cred->req_conn_capab_proto[i], ports[j])) return 1; } } } return 0; } static struct wpa_cred * interworking_credentials_available_roaming_consortium( struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw, int *excluded) { struct wpa_cred *cred, *selected = NULL; const u8 *ie; int is_excluded = 0; ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); if (ie == NULL && (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL)) return NULL; if (wpa_s->conf->cred == NULL) return NULL; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { if (cred->roaming_consortium_len == 0) continue; if (!roaming_consortium_match(ie, bss->anqp ? bss->anqp->roaming_consortium : NULL, cred->roaming_consortium, cred->roaming_consortium_len)) continue; if (cred_no_required_oi_match(cred, bss)) continue; if (!ignore_bw && cred_below_min_backhaul(wpa_s, cred, bss)) continue; if (!ignore_bw && cred_over_max_bss_load(wpa_s, cred, bss)) continue; if (!ignore_bw && cred_conn_capab_missing(wpa_s, cred, bss)) continue; if (cred_excluded_ssid(cred, bss)) { if (excluded == NULL) continue; if (selected == NULL) { selected = cred; is_excluded = 1; } } else { if (selected == NULL || is_excluded || cred_prio_cmp(selected, cred) < 0) { selected = cred; is_excluded = 0; } } } if (excluded) *excluded = is_excluded; return selected; } static int interworking_set_eap_params(struct wpa_ssid *ssid, struct wpa_cred *cred, int ttls) { if (cred->eap_method) { ttls = cred->eap_method->vendor == EAP_VENDOR_IETF && cred->eap_method->method == EAP_TYPE_TTLS; os_free(ssid->eap.eap_methods); ssid->eap.eap_methods = os_malloc(sizeof(struct eap_method_type) * 2); if (ssid->eap.eap_methods == NULL) return -1; os_memcpy(ssid->eap.eap_methods, cred->eap_method, sizeof(*cred->eap_method)); ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF; ssid->eap.eap_methods[1].method = EAP_TYPE_NONE; } if (ttls && cred->username && cred->username[0]) { const char *pos; char *anon; /* Use anonymous NAI in Phase 1 */ pos = os_strchr(cred->username, '@'); if (pos) { size_t buflen = 9 + os_strlen(pos) + 1; anon = os_malloc(buflen); if (anon == NULL) return -1; os_snprintf(anon, buflen, "anonymous%s", pos); } else if (cred->realm) { size_t buflen = 10 + os_strlen(cred->realm) + 1; anon = os_malloc(buflen); if (anon == NULL) return -1; os_snprintf(anon, buflen, "anonymous@%s", cred->realm); } else { anon = os_strdup("anonymous"); if (anon == NULL) return -1; } if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) < 0) { os_free(anon); return -1; } os_free(anon); } if (cred->username && cred->username[0] && wpa_config_set_quoted(ssid, "identity", cred->username) < 0) return -1; if (cred->password && cred->password[0]) { if (cred->ext_password && wpa_config_set(ssid, "password", cred->password, 0) < 0) return -1; if (!cred->ext_password && wpa_config_set_quoted(ssid, "password", cred->password) < 0) return -1; } if (cred->client_cert && cred->client_cert[0] && wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0) return -1; #ifdef ANDROID if (cred->private_key && os_strncmp(cred->private_key, "keystore://", 11) == 0) { /* Use OpenSSL engine configuration for Android keystore */ if (wpa_config_set_quoted(ssid, "engine_id", "keystore") < 0 || wpa_config_set_quoted(ssid, "key_id", cred->private_key + 11) < 0 || wpa_config_set(ssid, "engine", "1", 0) < 0) return -1; } else #endif /* ANDROID */ if (cred->private_key && cred->private_key[0] && wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0) return -1; if (cred->private_key_passwd && cred->private_key_passwd[0] && wpa_config_set_quoted(ssid, "private_key_passwd", cred->private_key_passwd) < 0) return -1; if (cred->phase1) { os_free(ssid->eap.phase1); ssid->eap.phase1 = os_strdup(cred->phase1); } if (cred->phase2) { os_free(ssid->eap.phase2); ssid->eap.phase2 = os_strdup(cred->phase2); } if (cred->ca_cert && cred->ca_cert[0] && wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0) return -1; if (cred->domain_suffix_match && cred->domain_suffix_match[0] && wpa_config_set_quoted(ssid, "domain_suffix_match", cred->domain_suffix_match) < 0) return -1; ssid->eap.ocsp = cred->ocsp; return 0; } static int interworking_connect_roaming_consortium( struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_bss *bss) { struct wpa_ssid *ssid; wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on " "roaming consortium match", MAC2STR(bss->bssid)); if (already_connected(wpa_s, cred, bss)) { wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, MAC2STR(bss->bssid)); return 0; } remove_duplicate_network(wpa_s, cred, bss); ssid = wpa_config_add_network(wpa_s->conf); if (ssid == NULL) return -1; ssid->parent_cred = cred; wpas_notify_network_added(wpa_s, ssid); wpa_config_set_network_defaults(ssid); ssid->priority = cred->priority; ssid->temporary = 1; ssid->ssid = os_zalloc(bss->ssid_len + 1); if (ssid->ssid == NULL) goto fail; os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len); ssid->ssid_len = bss->ssid_len; if (interworking_set_hs20_params(wpa_s, ssid) < 0) goto fail; if (cred->eap_method == NULL) { wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for " "credential using roaming consortium"); goto fail; } if (interworking_set_eap_params( ssid, cred, cred->eap_method->vendor == EAP_VENDOR_IETF && cred->eap_method->method == EAP_TYPE_TTLS) < 0) goto fail; wpa_s->next_ssid = ssid; wpa_config_update_prio_list(wpa_s->conf); interworking_reconnect(wpa_s); return 0; fail: wpas_notify_network_removed(wpa_s, ssid); wpa_config_remove_network(wpa_s->conf, ssid->id); return -1; } static int interworking_connect_helper(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int allow_excluded) { struct wpa_cred *cred, *cred_rc, *cred_3gpp; struct wpa_ssid *ssid; struct nai_realm *realm; struct nai_realm_eap *eap = NULL; u16 count, i; char buf[100]; int excluded = 0, *excl = allow_excluded ? &excluded : NULL; if (wpa_s->conf->cred == NULL || bss == NULL) return -1; if (disallowed_bssid(wpa_s, bss->bssid) || disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) { wpa_printf(MSG_DEBUG, "Interworking: Reject connection to disallowed BSS " MACSTR, MAC2STR(bss->bssid)); return -1; } wpa_printf(MSG_DEBUG, "Interworking: Considering BSS " MACSTR " for connection (allow_excluded=%d)", MAC2STR(bss->bssid), allow_excluded); if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) { /* * We currently support only HS 2.0 networks and those are * required to use WPA2-Enterprise. */ wpa_printf(MSG_DEBUG, "Interworking: Network does not use " "RSN"); return -1; } cred_rc = interworking_credentials_available_roaming_consortium( wpa_s, bss, 0, excl); if (cred_rc) { wpa_printf(MSG_DEBUG, "Interworking: Highest roaming " "consortium matching credential priority %d " "sp_priority %d", cred_rc->priority, cred_rc->sp_priority); if (allow_excluded && excl && !(*excl)) excl = NULL; } cred = interworking_credentials_available_realm(wpa_s, bss, 0, excl); if (cred) { wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm list " "matching credential priority %d sp_priority %d", cred->priority, cred->sp_priority); if (allow_excluded && excl && !(*excl)) excl = NULL; } cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss, 0, excl); if (cred_3gpp) { wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP matching " "credential priority %d sp_priority %d", cred_3gpp->priority, cred_3gpp->sp_priority); if (allow_excluded && excl && !(*excl)) excl = NULL; } if (!cred_rc && !cred && !cred_3gpp) { wpa_printf(MSG_DEBUG, "Interworking: No full credential matches - consider options without BW(etc.) limits"); cred_rc = interworking_credentials_available_roaming_consortium( wpa_s, bss, 1, excl); if (cred_rc) { wpa_printf(MSG_DEBUG, "Interworking: Highest roaming " "consortium matching credential priority %d " "sp_priority %d (ignore BW)", cred_rc->priority, cred_rc->sp_priority); if (allow_excluded && excl && !(*excl)) excl = NULL; } cred = interworking_credentials_available_realm(wpa_s, bss, 1, excl); if (cred) { wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm " "list matching credential priority %d " "sp_priority %d (ignore BW)", cred->priority, cred->sp_priority); if (allow_excluded && excl && !(*excl)) excl = NULL; } cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss, 1, excl); if (cred_3gpp) { wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP " "matching credential priority %d " "sp_priority %d (ignore BW)", cred_3gpp->priority, cred_3gpp->sp_priority); if (allow_excluded && excl && !(*excl)) excl = NULL; } } if (cred_rc && (cred == NULL || cred_prio_cmp(cred_rc, cred) >= 0) && (cred_3gpp == NULL || cred_prio_cmp(cred_rc, cred_3gpp) >= 0)) return interworking_connect_roaming_consortium(wpa_s, cred_rc, bss); if (cred_3gpp && (cred == NULL || cred_prio_cmp(cred_3gpp, cred) >= 0)) { return interworking_connect_3gpp(wpa_s, cred_3gpp, bss); } if (cred == NULL) { wpa_printf(MSG_DEBUG, "Interworking: No matching credentials " "found for " MACSTR, MAC2STR(bss->bssid)); return -1; } realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL, &count); if (realm == NULL) { wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI " "Realm list from " MACSTR, MAC2STR(bss->bssid)); return -1; } for (i = 0; i < count; i++) { if (!nai_realm_match(&realm[i], cred->realm)) continue; eap = nai_realm_find_eap(cred, &realm[i]); if (eap) break; } if (!eap) { wpa_printf(MSG_DEBUG, "Interworking: No matching credentials " "and EAP method found for " MACSTR, MAC2STR(bss->bssid)); nai_realm_free(realm, count); return -1; } wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR, MAC2STR(bss->bssid)); if (already_connected(wpa_s, cred, bss)) { wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, MAC2STR(bss->bssid)); nai_realm_free(realm, count); return 0; } remove_duplicate_network(wpa_s, cred, bss); ssid = wpa_config_add_network(wpa_s->conf); if (ssid == NULL) { nai_realm_free(realm, count); return -1; } ssid->parent_cred = cred; wpas_notify_network_added(wpa_s, ssid); wpa_config_set_network_defaults(ssid); ssid->priority = cred->priority; ssid->temporary = 1; ssid->ssid = os_zalloc(bss->ssid_len + 1); if (ssid->ssid == NULL) goto fail; os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len); ssid->ssid_len = bss->ssid_len; if (interworking_set_hs20_params(wpa_s, ssid) < 0) goto fail; if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF, eap->method), 0) < 0) goto fail; switch (eap->method) { case EAP_TYPE_TTLS: if (eap->inner_method) { os_snprintf(buf, sizeof(buf), "\"autheap=%s\"", eap_get_name(EAP_VENDOR_IETF, eap->inner_method)); if (wpa_config_set(ssid, "phase2", buf, 0) < 0) goto fail; break; } switch (eap->inner_non_eap) { case NAI_REALM_INNER_NON_EAP_PAP: if (wpa_config_set(ssid, "phase2", "\"auth=PAP\"", 0) < 0) goto fail; break; case NAI_REALM_INNER_NON_EAP_CHAP: if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0) < 0) goto fail; break; case NAI_REALM_INNER_NON_EAP_MSCHAP: if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAP\"", 0) < 0) goto fail; break; case NAI_REALM_INNER_NON_EAP_MSCHAPV2: if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"", 0) < 0) goto fail; break; default: /* EAP params were not set - assume TTLS/MSCHAPv2 */ if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"", 0) < 0) goto fail; break; } break; case EAP_TYPE_PEAP: case EAP_TYPE_FAST: if (wpa_config_set(ssid, "phase1", "\"fast_provisioning=2\"", 0) < 0) goto fail; if (wpa_config_set(ssid, "pac_file", "\"blob://pac_interworking\"", 0) < 0) goto fail; os_snprintf(buf, sizeof(buf), "\"auth=%s\"", eap_get_name(EAP_VENDOR_IETF, eap->inner_method ? eap->inner_method : EAP_TYPE_MSCHAPV2)); if (wpa_config_set(ssid, "phase2", buf, 0) < 0) goto fail; break; case EAP_TYPE_TLS: break; } if (interworking_set_eap_params(ssid, cred, eap->method == EAP_TYPE_TTLS) < 0) goto fail; nai_realm_free(realm, count); wpa_s->next_ssid = ssid; wpa_config_update_prio_list(wpa_s->conf); interworking_reconnect(wpa_s); return 0; fail: wpas_notify_network_removed(wpa_s, ssid); wpa_config_remove_network(wpa_s->conf, ssid->id); nai_realm_free(realm, count); return -1; } int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { return interworking_connect_helper(wpa_s, bss, 1); } #ifdef PCSC_FUNCS static int interworking_pcsc_read_imsi(struct wpa_supplicant *wpa_s) { size_t len; if (wpa_s->imsi[0] && wpa_s->mnc_len) return 0; len = sizeof(wpa_s->imsi) - 1; if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) { scard_deinit(wpa_s->scard); wpa_s->scard = NULL; wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI"); return -1; } wpa_s->imsi[len] = '\0'; wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard); wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)", wpa_s->imsi, wpa_s->mnc_len); return 0; } #endif /* PCSC_FUNCS */ static struct wpa_cred * interworking_credentials_available_3gpp( struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw, int *excluded) { struct wpa_cred *selected = NULL; #ifdef INTERWORKING_3GPP struct wpa_cred *cred; int ret; int is_excluded = 0; if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL) return NULL; #ifdef CONFIG_EAP_PROXY if (!wpa_s->imsi[0]) { size_t len; wpa_printf(MSG_DEBUG, "Interworking: IMSI not available - try to read again through eap_proxy"); wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, wpa_s->imsi, &len); if (wpa_s->mnc_len > 0) { wpa_s->imsi[len] = '\0'; wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)", wpa_s->imsi, wpa_s->mnc_len); } else { wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available"); } } #endif /* CONFIG_EAP_PROXY */ for (cred = wpa_s->conf->cred; cred; cred = cred->next) { char *sep; const char *imsi; int mnc_len; char imsi_buf[16]; size_t msin_len; #ifdef PCSC_FUNCS if (cred->pcsc && wpa_s->scard) { if (interworking_pcsc_read_imsi(wpa_s) < 0) continue; imsi = wpa_s->imsi; mnc_len = wpa_s->mnc_len; goto compare; } #endif /* PCSC_FUNCS */ #ifdef CONFIG_EAP_PROXY if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) { imsi = wpa_s->imsi; mnc_len = wpa_s->mnc_len; goto compare; } #endif /* CONFIG_EAP_PROXY */ if (cred->imsi == NULL || !cred->imsi[0] || (!wpa_s->conf->external_sim && (cred->milenage == NULL || !cred->milenage[0]))) continue; sep = os_strchr(cred->imsi, '-'); if (sep == NULL || (sep - cred->imsi != 5 && sep - cred->imsi != 6)) continue; mnc_len = sep - cred->imsi - 3; os_memcpy(imsi_buf, cred->imsi, 3 + mnc_len); sep++; msin_len = os_strlen(cred->imsi); if (3 + mnc_len + msin_len >= sizeof(imsi_buf) - 1) msin_len = sizeof(imsi_buf) - 3 - mnc_len - 1; os_memcpy(&imsi_buf[3 + mnc_len], sep, msin_len); imsi_buf[3 + mnc_len + msin_len] = '\0'; imsi = imsi_buf; #if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY) compare: #endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */ wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from " MACSTR, MAC2STR(bss->bssid)); ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len); wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not "); if (ret) { if (cred_no_required_oi_match(cred, bss)) continue; if (!ignore_bw && cred_below_min_backhaul(wpa_s, cred, bss)) continue; if (!ignore_bw && cred_over_max_bss_load(wpa_s, cred, bss)) continue; if (!ignore_bw && cred_conn_capab_missing(wpa_s, cred, bss)) continue; if (cred_excluded_ssid(cred, bss)) { if (excluded == NULL) continue; if (selected == NULL) { selected = cred; is_excluded = 1; } } else { if (selected == NULL || is_excluded || cred_prio_cmp(selected, cred) < 0) { selected = cred; is_excluded = 0; } } } } if (excluded) *excluded = is_excluded; #endif /* INTERWORKING_3GPP */ return selected; } static struct wpa_cred * interworking_credentials_available_realm( struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw, int *excluded) { struct wpa_cred *cred, *selected = NULL; struct nai_realm *realm; u16 count, i; int is_excluded = 0; if (bss->anqp == NULL || bss->anqp->nai_realm == NULL) return NULL; if (wpa_s->conf->cred == NULL) return NULL; wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from " MACSTR, MAC2STR(bss->bssid)); realm = nai_realm_parse(bss->anqp->nai_realm, &count); if (realm == NULL) { wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI " "Realm list from " MACSTR, MAC2STR(bss->bssid)); return NULL; } for (cred = wpa_s->conf->cred; cred; cred = cred->next) { if (cred->realm == NULL) continue; for (i = 0; i < count; i++) { if (!nai_realm_match(&realm[i], cred->realm)) continue; if (nai_realm_find_eap(cred, &realm[i])) { if (cred_no_required_oi_match(cred, bss)) continue; if (!ignore_bw && cred_below_min_backhaul(wpa_s, cred, bss)) continue; if (!ignore_bw && cred_over_max_bss_load(wpa_s, cred, bss)) continue; if (!ignore_bw && cred_conn_capab_missing(wpa_s, cred, bss)) continue; if (cred_excluded_ssid(cred, bss)) { if (excluded == NULL) continue; if (selected == NULL) { selected = cred; is_excluded = 1; } } else { if (selected == NULL || is_excluded || cred_prio_cmp(selected, cred) < 0) { selected = cred; is_excluded = 0; } } break; } } } nai_realm_free(realm, count); if (excluded) *excluded = is_excluded; return selected; } static struct wpa_cred * interworking_credentials_available_helper( struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw, int *excluded) { struct wpa_cred *cred, *cred2; int excluded1, excluded2; if (disallowed_bssid(wpa_s, bss->bssid) || disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) { wpa_printf(MSG_DEBUG, "Interworking: Ignore disallowed BSS " MACSTR, MAC2STR(bss->bssid)); return NULL; } cred = interworking_credentials_available_realm(wpa_s, bss, ignore_bw, &excluded1); cred2 = interworking_credentials_available_3gpp(wpa_s, bss, ignore_bw, &excluded2); if (cred && cred2 && (cred_prio_cmp(cred2, cred) >= 0 || (!excluded2 && excluded1))) { cred = cred2; excluded1 = excluded2; } if (!cred) { cred = cred2; excluded1 = excluded2; } cred2 = interworking_credentials_available_roaming_consortium( wpa_s, bss, ignore_bw, &excluded2); if (cred && cred2 && (cred_prio_cmp(cred2, cred) >= 0 || (!excluded2 && excluded1))) { cred = cred2; excluded1 = excluded2; } if (!cred) { cred = cred2; excluded1 = excluded2; } if (excluded) *excluded = excluded1; return cred; } static struct wpa_cred * interworking_credentials_available( struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int *excluded) { struct wpa_cred *cred; if (excluded) *excluded = 0; cred = interworking_credentials_available_helper(wpa_s, bss, 0, excluded); if (cred) return cred; return interworking_credentials_available_helper(wpa_s, bss, 1, excluded); } int domain_name_list_contains(struct wpabuf *domain_names, const char *domain, int exact_match) { const u8 *pos, *end; size_t len; len = os_strlen(domain); pos = wpabuf_head(domain_names); end = pos + wpabuf_len(domain_names); while (pos + 1 < end) { if (pos + 1 + pos[0] > end) break; wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name", pos + 1, pos[0]); if (pos[0] == len && os_strncasecmp(domain, (const char *) (pos + 1), len) == 0) return 1; if (!exact_match && pos[0] > len && pos[pos[0] - len] == '.') { const char *ap = (const char *) (pos + 1); int offset = pos[0] - len; if (os_strncasecmp(domain, ap + offset, len) == 0) return 1; } pos += 1 + pos[0]; } return 0; } int interworking_home_sp_cred(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpabuf *domain_names) { size_t i; int ret = -1; #ifdef INTERWORKING_3GPP char nai[100], *realm; char *imsi = NULL; int mnc_len = 0; if (cred->imsi) imsi = cred->imsi; #ifdef PCSC_FUNCS else if (cred->pcsc && wpa_s->scard) { if (interworking_pcsc_read_imsi(wpa_s) < 0) return -1; imsi = wpa_s->imsi; mnc_len = wpa_s->mnc_len; } #endif /* PCSC_FUNCS */ #ifdef CONFIG_EAP_PROXY else if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) { imsi = wpa_s->imsi; mnc_len = wpa_s->mnc_len; } #endif /* CONFIG_EAP_PROXY */ if (domain_names && imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) { realm = os_strchr(nai, '@'); if (realm) realm++; wpa_printf(MSG_DEBUG, "Interworking: Search for match " "with SIM/USIM domain %s", realm); if (realm && domain_name_list_contains(domain_names, realm, 1)) return 1; if (realm) ret = 0; } #endif /* INTERWORKING_3GPP */ if (domain_names == NULL || cred->domain == NULL) return ret; for (i = 0; i < cred->num_domain; i++) { wpa_printf(MSG_DEBUG, "Interworking: Search for match with " "home SP FQDN %s", cred->domain[i]); if (domain_name_list_contains(domain_names, cred->domain[i], 1)) return 1; } return 0; } static int interworking_home_sp(struct wpa_supplicant *wpa_s, struct wpabuf *domain_names) { struct wpa_cred *cred; if (domain_names == NULL || wpa_s->conf->cred == NULL) return -1; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { int res = interworking_home_sp_cred(wpa_s, cred, domain_names); if (res) return res; } return 0; } static int interworking_find_network_match(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss; struct wpa_ssid *ssid; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (wpas_network_disabled(wpa_s, ssid) || ssid->mode != WPAS_MODE_INFRA) continue; if (ssid->ssid_len != bss->ssid_len || os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 0) continue; /* * TODO: Consider more accurate matching of security * configuration similarly to what is done in events.c */ return 1; } } return 0; } static int roaming_partner_match(struct wpa_supplicant *wpa_s, struct roaming_partner *partner, struct wpabuf *domain_names) { wpa_printf(MSG_DEBUG, "Interworking: Comparing roaming_partner info fqdn='%s' exact_match=%d priority=%u country='%s'", partner->fqdn, partner->exact_match, partner->priority, partner->country); wpa_hexdump_ascii(MSG_DEBUG, "Interworking: Domain names", wpabuf_head(domain_names), wpabuf_len(domain_names)); if (!domain_name_list_contains(domain_names, partner->fqdn, partner->exact_match)) return 0; /* TODO: match Country */ return 1; } static u8 roaming_prio(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_bss *bss) { size_t i; if (bss->anqp == NULL || bss->anqp->domain_name == NULL) { wpa_printf(MSG_DEBUG, "Interworking: No ANQP domain name info -> use default roaming partner priority 128"); return 128; /* cannot check preference with domain name */ } if (interworking_home_sp_cred(wpa_s, cred, bss->anqp->domain_name) > 0) { wpa_printf(MSG_DEBUG, "Interworking: Determined to be home SP -> use maximum preference 0 as roaming partner priority"); return 0; /* max preference for home SP network */ } for (i = 0; i < cred->num_roaming_partner; i++) { if (roaming_partner_match(wpa_s, &cred->roaming_partner[i], bss->anqp->domain_name)) { wpa_printf(MSG_DEBUG, "Interworking: Roaming partner preference match - priority %u", cred->roaming_partner[i].priority); return cred->roaming_partner[i].priority; } } wpa_printf(MSG_DEBUG, "Interworking: No roaming partner preference match - use default roaming partner priority 128"); return 128; } static struct wpa_bss * pick_best_roaming_partner(struct wpa_supplicant *wpa_s, struct wpa_bss *selected, struct wpa_cred *cred) { struct wpa_bss *bss; u8 best_prio, prio; struct wpa_cred *cred2; /* * Check if any other BSS is operated by a more preferred roaming * partner. */ best_prio = roaming_prio(wpa_s, cred, selected); wpa_printf(MSG_DEBUG, "Interworking: roaming_prio=%u for selected BSS " MACSTR " (cred=%d)", best_prio, MAC2STR(selected->bssid), cred->id); dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (bss == selected) continue; cred2 = interworking_credentials_available(wpa_s, bss, NULL); if (!cred2) continue; if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) continue; prio = roaming_prio(wpa_s, cred2, bss); wpa_printf(MSG_DEBUG, "Interworking: roaming_prio=%u for BSS " MACSTR " (cred=%d)", prio, MAC2STR(bss->bssid), cred2->id); if (prio < best_prio) { int bh1, bh2, load1, load2, conn1, conn2; bh1 = cred_below_min_backhaul(wpa_s, cred, selected); load1 = cred_over_max_bss_load(wpa_s, cred, selected); conn1 = cred_conn_capab_missing(wpa_s, cred, selected); bh2 = cred_below_min_backhaul(wpa_s, cred2, bss); load2 = cred_over_max_bss_load(wpa_s, cred2, bss); conn2 = cred_conn_capab_missing(wpa_s, cred2, bss); wpa_printf(MSG_DEBUG, "Interworking: old: %d %d %d new: %d %d %d", bh1, load1, conn1, bh2, load2, conn2); if (bh1 || load1 || conn1 || !(bh2 || load2 || conn2)) { wpa_printf(MSG_DEBUG, "Interworking: Better roaming partner " MACSTR " selected", MAC2STR(bss->bssid)); best_prio = prio; selected = bss; } } } return selected; } static void interworking_select_network(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss, *selected = NULL, *selected_home = NULL; struct wpa_bss *selected2 = NULL, *selected2_home = NULL; unsigned int count = 0; const char *type; int res; struct wpa_cred *cred, *selected_cred = NULL; struct wpa_cred *selected_home_cred = NULL; struct wpa_cred *selected2_cred = NULL; struct wpa_cred *selected2_home_cred = NULL; wpa_s->network_select = 0; wpa_printf(MSG_DEBUG, "Interworking: Select network (auto_select=%d)", wpa_s->auto_select); dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { int excluded = 0; int bh, bss_load, conn_capab; cred = interworking_credentials_available(wpa_s, bss, &excluded); if (!cred) continue; if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) { /* * We currently support only HS 2.0 networks and those * are required to use WPA2-Enterprise. */ wpa_printf(MSG_DEBUG, "Interworking: Credential match " "with " MACSTR " but network does not use " "RSN", MAC2STR(bss->bssid)); continue; } if (!excluded) count++; res = interworking_home_sp(wpa_s, bss->anqp ? bss->anqp->domain_name : NULL); if (res > 0) type = "home"; else if (res == 0) type = "roaming"; else type = "unknown"; bh = cred_below_min_backhaul(wpa_s, cred, bss); bss_load = cred_over_max_bss_load(wpa_s, cred, bss); conn_capab = cred_conn_capab_missing(wpa_s, cred, bss); wpa_msg(wpa_s, MSG_INFO, "%s" MACSTR " type=%s%s%s%s id=%d priority=%d sp_priority=%d", excluded ? INTERWORKING_BLACKLISTED : INTERWORKING_AP, MAC2STR(bss->bssid), type, bh ? " below_min_backhaul=1" : "", bss_load ? " over_max_bss_load=1" : "", conn_capab ? " conn_capab_missing=1" : "", cred->id, cred->priority, cred->sp_priority); if (excluded) continue; if (wpa_s->auto_select || (wpa_s->conf->auto_interworking && wpa_s->auto_network_select)) { if (bh || bss_load || conn_capab) { if (selected2_cred == NULL || cred_prio_cmp(cred, selected2_cred) > 0) { wpa_printf(MSG_DEBUG, "Interworking: Mark as selected2"); selected2 = bss; selected2_cred = cred; } if (res > 0 && (selected2_home_cred == NULL || cred_prio_cmp(cred, selected2_home_cred) > 0)) { wpa_printf(MSG_DEBUG, "Interworking: Mark as selected2_home"); selected2_home = bss; selected2_home_cred = cred; } } else { if (selected_cred == NULL || cred_prio_cmp(cred, selected_cred) > 0) { wpa_printf(MSG_DEBUG, "Interworking: Mark as selected"); selected = bss; selected_cred = cred; } if (res > 0 && (selected_home_cred == NULL || cred_prio_cmp(cred, selected_home_cred) > 0)) { wpa_printf(MSG_DEBUG, "Interworking: Mark as selected_home"); selected_home = bss; selected_home_cred = cred; } } } } if (selected_home && selected_home != selected && selected_home_cred && (selected_cred == NULL || cred_prio_cmp(selected_home_cred, selected_cred) >= 0)) { /* Prefer network operated by the Home SP */ wpa_printf(MSG_DEBUG, "Interworking: Overrided selected with selected_home"); selected = selected_home; selected_cred = selected_home_cred; } if (!selected) { if (selected2_home) { wpa_printf(MSG_DEBUG, "Interworking: Use home BSS with BW limit mismatch since no other network could be selected"); selected = selected2_home; selected_cred = selected2_home_cred; } else if (selected2) { wpa_printf(MSG_DEBUG, "Interworking: Use visited BSS with BW limit mismatch since no other network could be selected"); selected = selected2; selected_cred = selected2_cred; } } if (count == 0) { /* * No matching network was found based on configured * credentials. Check whether any of the enabled network blocks * have matching APs. */ if (interworking_find_network_match(wpa_s)) { wpa_printf(MSG_DEBUG, "Interworking: Possible BSS " "match for enabled network configurations"); if (wpa_s->auto_select) { interworking_reconnect(wpa_s); return; } } if (wpa_s->auto_network_select) { wpa_printf(MSG_DEBUG, "Interworking: Continue " "scanning after ANQP fetch"); wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 0); return; } wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network " "with matching credentials found"); } if (selected) { wpa_printf(MSG_DEBUG, "Interworking: Selected " MACSTR, MAC2STR(selected->bssid)); selected = pick_best_roaming_partner(wpa_s, selected, selected_cred); wpa_printf(MSG_DEBUG, "Interworking: Selected " MACSTR " (after best roaming partner selection)", MAC2STR(selected->bssid)); wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR, MAC2STR(selected->bssid)); interworking_connect(wpa_s, selected); } } static struct wpa_bss_anqp * interworking_match_anqp_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { struct wpa_bss *other; if (is_zero_ether_addr(bss->hessid)) return NULL; /* Cannot be in the same homegenous ESS */ dl_list_for_each(other, &wpa_s->bss, struct wpa_bss, list) { if (other == bss) continue; if (other->anqp == NULL) continue; if (other->anqp->roaming_consortium == NULL && other->anqp->nai_realm == NULL && other->anqp->anqp_3gpp == NULL && other->anqp->domain_name == NULL) continue; if (!(other->flags & WPA_BSS_ANQP_FETCH_TRIED)) continue; if (os_memcmp(bss->hessid, other->hessid, ETH_ALEN) != 0) continue; if (bss->ssid_len != other->ssid_len || os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0) continue; wpa_printf(MSG_DEBUG, "Interworking: Share ANQP data with " "already fetched BSSID " MACSTR " and " MACSTR, MAC2STR(other->bssid), MAC2STR(bss->bssid)); other->anqp->users++; return other->anqp; } return NULL; } static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss; int found = 0; const u8 *ie; wpa_printf(MSG_DEBUG, "Interworking: next_anqp_fetch - " "fetch_anqp_in_progress=%d fetch_osu_icon_in_progress=%d", wpa_s->fetch_anqp_in_progress, wpa_s->fetch_osu_icon_in_progress); if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress) { wpa_printf(MSG_DEBUG, "Interworking: Stop next-ANQP-fetch"); return; } if (wpa_s->fetch_osu_icon_in_progress) { wpa_printf(MSG_DEBUG, "Interworking: Next icon (in progress)"); hs20_next_osu_icon(wpa_s); return; } dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (!(bss->caps & IEEE80211_CAP_ESS)) continue; ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB); if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80)) continue; /* AP does not support Interworking */ if (disallowed_bssid(wpa_s, bss->bssid) || disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) continue; /* Disallowed BSS */ if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) { if (bss->anqp == NULL) { bss->anqp = interworking_match_anqp_info(wpa_s, bss); if (bss->anqp) { /* Shared data already fetched */ continue; } bss->anqp = wpa_bss_anqp_alloc(); if (bss->anqp == NULL) break; } found++; bss->flags |= WPA_BSS_ANQP_FETCH_TRIED; wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for " MACSTR, MAC2STR(bss->bssid)); interworking_anqp_send_req(wpa_s, bss); break; } } if (found == 0) { if (wpa_s->fetch_osu_info) { if (wpa_s->num_prov_found == 0 && wpa_s->num_osu_scans < 3) { wpa_printf(MSG_DEBUG, "HS 2.0: No OSU providers seen - try to scan again"); hs20_start_osu_scan(wpa_s); return; } wpa_printf(MSG_DEBUG, "Interworking: Next icon"); hs20_osu_icon_fetch(wpa_s); return; } wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed"); wpa_s->fetch_anqp_in_progress = 0; if (wpa_s->network_select) interworking_select_network(wpa_s); } } void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED; wpa_s->fetch_anqp_in_progress = 1; interworking_next_anqp_fetch(wpa_s); } int interworking_fetch_anqp(struct wpa_supplicant *wpa_s) { if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) return 0; wpa_s->network_select = 0; wpa_s->fetch_all_anqp = 1; wpa_s->fetch_osu_info = 0; interworking_start_fetch_anqp(wpa_s); return 0; } void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s) { if (!wpa_s->fetch_anqp_in_progress) return; wpa_s->fetch_anqp_in_progress = 0; } int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u16 info_ids[], size_t num_ids, u32 subtypes) { struct wpabuf *buf; struct wpabuf *hs20_buf = NULL; int ret = 0; int freq; struct wpa_bss *bss; int res; freq = wpa_s->assoc_freq; bss = wpa_bss_get_bssid(wpa_s, dst); if (bss) { wpa_bss_anqp_unshare_alloc(bss); freq = bss->freq; } if (freq <= 0) return -1; wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)", MAC2STR(dst), (unsigned int) num_ids); #ifdef CONFIG_HS20 if (subtypes != 0) { hs20_buf = wpabuf_alloc(100); if (hs20_buf == NULL) return -1; hs20_put_anqp_req(subtypes, NULL, 0, hs20_buf); } #endif /* CONFIG_HS20 */ buf = anqp_build_req(info_ids, num_ids, hs20_buf); wpabuf_free(hs20_buf); if (buf == NULL) return -1; res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s); if (res < 0) { wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); wpabuf_free(buf); ret = -1; } else wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " "%u", res); return ret; } static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const u8 *sa, u16 info_id, const u8 *data, size_t slen) { const u8 *pos = data; struct wpa_bss_anqp *anqp = NULL; #ifdef CONFIG_HS20 u8 type; #endif /* CONFIG_HS20 */ if (bss) anqp = bss->anqp; switch (info_id) { case ANQP_CAPABILITY_LIST: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " ANQP Capability list", MAC2STR(sa)); break; case ANQP_VENUE_NAME: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " Venue Name", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen); if (anqp) { wpabuf_free(anqp->venue_name); anqp->venue_name = wpabuf_alloc_copy(pos, slen); } break; case ANQP_NETWORK_AUTH_TYPE: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " Network Authentication Type information", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication " "Type", pos, slen); if (anqp) { wpabuf_free(anqp->network_auth_type); anqp->network_auth_type = wpabuf_alloc_copy(pos, slen); } break; case ANQP_ROAMING_CONSORTIUM: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " Roaming Consortium list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium", pos, slen); if (anqp) { wpabuf_free(anqp->roaming_consortium); anqp->roaming_consortium = wpabuf_alloc_copy(pos, slen); } break; case ANQP_IP_ADDR_TYPE_AVAILABILITY: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " IP Address Type Availability information", MAC2STR(sa)); wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability", pos, slen); if (anqp) { wpabuf_free(anqp->ip_addr_type_availability); anqp->ip_addr_type_availability = wpabuf_alloc_copy(pos, slen); } break; case ANQP_NAI_REALM: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " NAI Realm list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen); if (anqp) { wpabuf_free(anqp->nai_realm); anqp->nai_realm = wpabuf_alloc_copy(pos, slen); } break; case ANQP_3GPP_CELLULAR_NETWORK: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " 3GPP Cellular Network information", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network", pos, slen); if (anqp) { wpabuf_free(anqp->anqp_3gpp); anqp->anqp_3gpp = wpabuf_alloc_copy(pos, slen); } break; case ANQP_DOMAIN_NAME: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " Domain Name list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen); if (anqp) { wpabuf_free(anqp->domain_name); anqp->domain_name = wpabuf_alloc_copy(pos, slen); } break; case ANQP_VENDOR_SPECIFIC: if (slen < 3) return; switch (WPA_GET_BE24(pos)) { #ifdef CONFIG_HS20 case OUI_WFA: pos += 3; slen -= 3; if (slen < 1) return; type = *pos++; slen--; switch (type) { case HS20_ANQP_OUI_TYPE: hs20_parse_rx_hs20_anqp_resp(wpa_s, sa, pos, slen); break; default: wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP " "vendor type %u", type); break; } break; #endif /* CONFIG_HS20 */ default: wpa_printf(MSG_DEBUG, "Interworking: Unsupported " "vendor-specific ANQP OUI %06x", WPA_GET_BE24(pos)); return; } break; default: wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID " "%u", info_id); break; } } void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, const struct wpabuf *resp, u16 status_code) { struct wpa_supplicant *wpa_s = ctx; const u8 *pos; const u8 *end; u16 info_id; u16 slen; struct wpa_bss *bss = NULL, *tmp; wpa_printf(MSG_DEBUG, "Interworking: anqp_resp_cb dst=" MACSTR " dialog_token=%u result=%d status_code=%u", MAC2STR(dst), dialog_token, result, status_code); if (result != GAS_QUERY_SUCCESS) { if (wpa_s->fetch_osu_icon_in_progress) hs20_icon_fetch_failed(wpa_s); return; } pos = wpabuf_head(adv_proto); if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO || pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) { wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement " "Protocol in response"); if (wpa_s->fetch_osu_icon_in_progress) hs20_icon_fetch_failed(wpa_s); return; } /* * If possible, select the BSS entry based on which BSS entry was used * for the request. This can help in cases where multiple BSS entries * may exist for the same AP. */ dl_list_for_each_reverse(tmp, &wpa_s->bss, struct wpa_bss, list) { if (tmp == wpa_s->interworking_gas_bss && os_memcmp(tmp->bssid, dst, ETH_ALEN) == 0) { bss = tmp; break; } } if (bss == NULL) bss = wpa_bss_get_bssid(wpa_s, dst); pos = wpabuf_head(resp); end = pos + wpabuf_len(resp); while (pos < end) { if (pos + 4 > end) { wpa_printf(MSG_DEBUG, "ANQP: Invalid element"); break; } info_id = WPA_GET_LE16(pos); pos += 2; slen = WPA_GET_LE16(pos); pos += 2; if (pos + slen > end) { wpa_printf(MSG_DEBUG, "ANQP: Invalid element length " "for Info ID %u", info_id); break; } interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos, slen); pos += slen; } hs20_notify_parse_done(wpa_s); } static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start " "ANQP fetch"); interworking_start_fetch_anqp(wpa_s); } int interworking_select(struct wpa_supplicant *wpa_s, int auto_select, int *freqs) { interworking_stop_fetch_anqp(wpa_s); wpa_s->network_select = 1; wpa_s->auto_network_select = 0; wpa_s->auto_select = !!auto_select; wpa_s->fetch_all_anqp = 0; wpa_s->fetch_osu_info = 0; wpa_printf(MSG_DEBUG, "Interworking: Start scan for network " "selection"); wpa_s->scan_res_handler = interworking_scan_res_handler; wpa_s->normal_scans = 0; wpa_s->scan_req = MANUAL_SCAN_REQ; os_free(wpa_s->manual_scan_freqs); wpa_s->manual_scan_freqs = freqs; wpa_s->after_wps = 0; wpa_s->known_wps_freq = 0; wpa_supplicant_req_scan(wpa_s, 0, 0); return 0; } static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, const struct wpabuf *resp, u16 status_code) { struct wpa_supplicant *wpa_s = ctx; struct wpabuf *n; wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR " dialog_token=%d status_code=%d resp_len=%d", MAC2STR(addr), dialog_token, status_code, resp ? (int) wpabuf_len(resp) : -1); if (!resp) return; n = wpabuf_dup(resp); if (n == NULL) return; wpabuf_free(wpa_s->prev_gas_resp); wpa_s->prev_gas_resp = wpa_s->last_gas_resp; os_memcpy(wpa_s->prev_gas_addr, wpa_s->last_gas_addr, ETH_ALEN); wpa_s->prev_gas_dialog_token = wpa_s->last_gas_dialog_token; wpa_s->last_gas_resp = n; os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN); wpa_s->last_gas_dialog_token = dialog_token; } int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *adv_proto, const struct wpabuf *query) { struct wpabuf *buf; int ret = 0; int freq; struct wpa_bss *bss; int res; size_t len; u8 query_resp_len_limit = 0, pame_bi = 0; freq = wpa_s->assoc_freq; bss = wpa_bss_get_bssid(wpa_s, dst); if (bss) freq = bss->freq; if (freq <= 0) return -1; wpa_printf(MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)", MAC2STR(dst), freq); wpa_hexdump_buf(MSG_DEBUG, "Advertisement Protocol ID", adv_proto); wpa_hexdump_buf(MSG_DEBUG, "GAS Query", query); len = 3 + wpabuf_len(adv_proto) + 2; if (query) len += wpabuf_len(query); buf = gas_build_initial_req(0, len); if (buf == NULL) return -1; /* Advertisement Protocol IE */ wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); wpabuf_put_u8(buf, 1 + wpabuf_len(adv_proto)); /* Length */ wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) | (pame_bi ? 0x80 : 0)); wpabuf_put_buf(buf, adv_proto); /* GAS Query */ if (query) { wpabuf_put_le16(buf, wpabuf_len(query)); wpabuf_put_buf(buf, query); } else wpabuf_put_le16(buf, 0); res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s); if (res < 0) { wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request"); wpabuf_free(buf); ret = -1; } else wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token " "%u", res); return ret; } wpa_supplicant-2.2/wpa_supplicant/wnm_sta.c0000664000175000017500000006347712343617166017105 0ustar jmjm/* * wpa_supplicant - WNM * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. * * 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 "common/ieee802_11_defs.h" #include "common/wpa_ctrl.h" #include "rsn_supp/wpa.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "scan.h" #include "ctrl_iface.h" #include "bss.h" #include "wnm_sta.h" #include "hs20_supplicant.h" #define MAX_TFS_IE_LEN 1024 #define WNM_MAX_NEIGHBOR_REPORT 10 /* get the TFS IE from driver */ static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, u16 *buf_len, enum wnm_oper oper) { wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len); } /* set the TFS IE to driver */ static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, const u8 *addr, u8 *buf, u16 *buf_len, enum wnm_oper oper) { wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len); } /* MLME-SLEEPMODE.request */ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, u8 action, u16 intval, struct wpabuf *tfs_req) { struct ieee80211_mgmt *mgmt; int res; size_t len; struct wnm_sleep_element *wnmsleep_ie; u8 *wnmtfs_ie; u8 wnmsleep_ie_len; u16 wnmtfs_ie_len; /* possibly multiple IE(s) */ enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : WNM_SLEEP_TFS_REQ_IE_NONE; wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request " "action=%s to " MACSTR, action == 0 ? "enter" : "exit", MAC2STR(wpa_s->bssid)); /* WNM-Sleep Mode IE */ wnmsleep_ie_len = sizeof(struct wnm_sleep_element); wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element)); if (wnmsleep_ie == NULL) return -1; wnmsleep_ie->eid = WLAN_EID_WNMSLEEP; wnmsleep_ie->len = wnmsleep_ie_len - 2; wnmsleep_ie->action_type = action; wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT; wnmsleep_ie->intval = host_to_le16(intval); wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element", (u8 *) wnmsleep_ie, wnmsleep_ie_len); /* TFS IE(s) */ if (tfs_req) { wnmtfs_ie_len = wpabuf_len(tfs_req); wnmtfs_ie = os_malloc(wnmtfs_ie_len); if (wnmtfs_ie == NULL) { os_free(wnmsleep_ie); return -1; } os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len); } else { wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); if (wnmtfs_ie == NULL) { os_free(wnmsleep_ie); return -1; } if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, tfs_oper)) { wnmtfs_ie_len = 0; os_free(wnmtfs_ie); wnmtfs_ie = NULL; } } wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element", (u8 *) wnmtfs_ie, wnmtfs_ie_len); mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len); if (mgmt == NULL) { wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " "WNM-Sleep Request action frame"); os_free(wnmsleep_ie); os_free(wnmtfs_ie); return -1; } os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); mgmt->u.action.category = WLAN_ACTION_WNM; mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ; mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1; os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie, wnmsleep_ie_len); /* copy TFS IE here */ if (wnmtfs_ie_len > 0) { os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len); } len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + wnmtfs_ie_len; res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, &mgmt->u.action.category, len, 0); if (res < 0) wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " "(action=%d, intval=%d)", action, intval); os_free(wnmsleep_ie); os_free(wnmtfs_ie); os_free(mgmt); return res; } static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s, u8 *tfsresp_ie_start, u8 *tfsresp_ie_end) { wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM, wpa_s->bssid, NULL, NULL); /* remove GTK/IGTK ?? */ /* set the TFS Resp IE(s) */ if (tfsresp_ie_start && tfsresp_ie_end && tfsresp_ie_end - tfsresp_ie_start >= 0) { u16 tfsresp_ie_len; tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) - tfsresp_ie_start; wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found"); /* pass the TFS Resp IE(s) to driver for processing */ if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid, tfsresp_ie_start, &tfsresp_ie_len, WNM_SLEEP_TFS_RESP_IE_SET)) wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE"); } } static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, const u8 *frm, u16 key_len_total) { u8 *ptr, *end; u8 gtk_len; wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, wpa_s->bssid, NULL, NULL); /* Install GTK/IGTK */ /* point to key data field */ ptr = (u8 *) frm + 1 + 2; end = ptr + key_len_total; wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total); while (ptr + 1 < end) { if (ptr + 2 + ptr[1] > end) { wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element " "length"); if (end > ptr) { wpa_hexdump(MSG_DEBUG, "WNM: Remaining data", ptr, end - ptr); } break; } if (*ptr == WNM_SLEEP_SUBELEM_GTK) { if (ptr[1] < 11 + 5) { wpa_printf(MSG_DEBUG, "WNM: Too short GTK " "subelem"); break; } gtk_len = *(ptr + 4); if (ptr[1] < 11 + gtk_len || gtk_len < 5 || gtk_len > 32) { wpa_printf(MSG_DEBUG, "WNM: Invalid GTK " "subelem"); break; } wpa_wnmsleep_install_key( wpa_s->wpa, WNM_SLEEP_SUBELEM_GTK, ptr); ptr += 13 + gtk_len; #ifdef CONFIG_IEEE80211W } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) { if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) { wpa_printf(MSG_DEBUG, "WNM: Too short IGTK " "subelem"); break; } wpa_wnmsleep_install_key(wpa_s->wpa, WNM_SLEEP_SUBELEM_IGTK, ptr); ptr += 10 + WPA_IGTK_LEN; #endif /* CONFIG_IEEE80211W */ } else break; /* skip the loop */ } } static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, const u8 *frm, int len) { /* * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data | * WNM-Sleep Mode IE | TFS Response IE */ u8 *pos = (u8 *) frm; /* point to payload after the action field */ u16 key_len_total; struct wnm_sleep_element *wnmsleep_ie = NULL; /* multiple TFS Resp IE (assuming consecutive) */ u8 *tfsresp_ie_start = NULL; u8 *tfsresp_ie_end = NULL; if (len < 3) return; key_len_total = WPA_GET_LE16(frm + 1); wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d", frm[0], key_len_total); pos += 3 + key_len_total; if (pos > frm + len) { wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field"); return; } while (pos - frm < len) { u8 ie_len = *(pos + 1); if (pos + 2 + ie_len > frm + len) { wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len); break; } wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len); if (*pos == WLAN_EID_WNMSLEEP) wnmsleep_ie = (struct wnm_sleep_element *) pos; else if (*pos == WLAN_EID_TFS_RESP) { if (!tfsresp_ie_start) tfsresp_ie_start = pos; tfsresp_ie_end = pos; } else wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos); pos += ie_len + 2; } if (!wnmsleep_ie) { wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); return; } if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT || wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) { wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response " "frame (action=%d, intval=%d)", wnmsleep_ie->action_type, wnmsleep_ie->intval); if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) { wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start, tfsresp_ie_end); } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total); } } else { wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame " "(action=%d, intval=%d)", wnmsleep_ie->action_type, wnmsleep_ie->intval); if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL, wpa_s->bssid, NULL, NULL); else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL, wpa_s->bssid, NULL, NULL); } } void wnm_deallocate_memory(struct wpa_supplicant *wpa_s) { int i; for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { os_free(wpa_s->wnm_neighbor_report_elements[i].tsf_info); os_free(wpa_s->wnm_neighbor_report_elements[i].con_coun_str); os_free(wpa_s->wnm_neighbor_report_elements[i].bss_tran_can); os_free(wpa_s->wnm_neighbor_report_elements[i].bss_term_dur); os_free(wpa_s->wnm_neighbor_report_elements[i].bearing); os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot); os_free(wpa_s->wnm_neighbor_report_elements[i].rrm_cap); os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid); } wpa_s->wnm_num_neighbor_report = 0; os_free(wpa_s->wnm_neighbor_report_elements); wpa_s->wnm_neighbor_report_elements = NULL; } static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, u8 id, u8 elen, const u8 *pos) { switch (id) { case WNM_NEIGHBOR_TSF: if (elen < 2 + 2) { wpa_printf(MSG_DEBUG, "WNM: Too short TSF"); break; } os_free(rep->tsf_info); rep->tsf_info = os_zalloc(sizeof(struct tsf_info)); if (rep->tsf_info == NULL) break; os_memcpy(rep->tsf_info->tsf_offset, pos, 2); os_memcpy(rep->tsf_info->beacon_interval, pos + 2, 2); break; case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING: if (elen < 2) { wpa_printf(MSG_DEBUG, "WNM: Too short condensed " "country string"); break; } os_free(rep->con_coun_str); rep->con_coun_str = os_zalloc(sizeof(struct condensed_country_string)); if (rep->con_coun_str == NULL) break; os_memcpy(rep->con_coun_str->country_string, pos, 2); break; case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE: if (elen < 1) { wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition " "candidate"); break; } os_free(rep->bss_tran_can); rep->bss_tran_can = os_zalloc(sizeof(struct bss_transition_candidate)); if (rep->bss_tran_can == NULL) break; rep->bss_tran_can->preference = pos[0]; break; case WNM_NEIGHBOR_BSS_TERMINATION_DURATION: if (elen < 10) { wpa_printf(MSG_DEBUG, "WNM: Too short BSS termination " "duration"); break; } os_free(rep->bss_term_dur); rep->bss_term_dur = os_zalloc(sizeof(struct bss_termination_duration)); if (rep->bss_term_dur == NULL) break; os_memcpy(rep->bss_term_dur->duration, pos, 10); break; case WNM_NEIGHBOR_BEARING: if (elen < 8) { wpa_printf(MSG_DEBUG, "WNM: Too short neighbor " "bearing"); break; } os_free(rep->bearing); rep->bearing = os_zalloc(sizeof(struct bearing)); if (rep->bearing == NULL) break; os_memcpy(rep->bearing->bearing, pos, 8); break; case WNM_NEIGHBOR_MEASUREMENT_PILOT: if (elen < 1) { wpa_printf(MSG_DEBUG, "WNM: Too short measurement " "pilot"); break; } os_free(rep->meas_pilot); rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot)); if (rep->meas_pilot == NULL) break; rep->meas_pilot->measurement_pilot = pos[0]; rep->meas_pilot->subelem_len = elen - 1; os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1); break; case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES: if (elen < 5) { wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled " "capabilities"); break; } os_free(rep->rrm_cap); rep->rrm_cap = os_zalloc(sizeof(struct rrm_enabled_capabilities)); if (rep->rrm_cap == NULL) break; os_memcpy(rep->rrm_cap->capabilities, pos, 5); break; case WNM_NEIGHBOR_MULTIPLE_BSSID: if (elen < 1) { wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID"); break; } os_free(rep->mul_bssid); rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid)); if (rep->mul_bssid == NULL) break; rep->mul_bssid->max_bssid_indicator = pos[0]; rep->mul_bssid->subelem_len = elen - 1; os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1); break; } } static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, const u8 *pos, u8 len, struct neighbor_report *rep) { u8 left = len; if (left < 13) { wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report"); return; } os_memcpy(rep->bssid, pos, ETH_ALEN); os_memcpy(rep->bssid_information, pos + ETH_ALEN, 4); rep->regulatory_class = *(pos + 10); rep->channel_number = *(pos + 11); rep->phy_type = *(pos + 12); pos += 13; left -= 13; while (left >= 2) { u8 id, elen; id = *pos++; elen = *pos++; wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen); left -= 2; if (elen > left) { wpa_printf(MSG_DEBUG, "WNM: Truncated neighbor report subelement"); break; } wnm_parse_neighbor_report_elem(rep, id, elen, pos); left -= elen; pos += elen; } } static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res, struct neighbor_report *neigh_rep, u8 num_neigh_rep, u8 *bssid_to_connect) { u8 i, j; if (scan_res == NULL || num_neigh_rep == 0 || !wpa_s->current_bss) return 0; wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", MAC2STR(wpa_s->bssid), wpa_s->current_bss->level); for (i = 0; i < num_neigh_rep; i++) { for (j = 0; j < scan_res->num; j++) { /* Check for a better RSSI AP */ if (os_memcmp(scan_res->res[j]->bssid, neigh_rep[i].bssid, ETH_ALEN) == 0 && scan_res->res[j]->level > wpa_s->current_bss->level) { /* Got a BSSID with better RSSI value */ os_memcpy(bssid_to_connect, neigh_rep[i].bssid, ETH_ALEN); wpa_printf(MSG_DEBUG, "Found a BSS " MACSTR " with better scan RSSI %d", MAC2STR(scan_res->res[j]->bssid), scan_res->res[j]->level); return 1; } wpa_printf(MSG_DEBUG, "scan_res[%d] " MACSTR " RSSI %d", j, MAC2STR(scan_res->res[j]->bssid), scan_res->res[j]->level); } } return 0; } static void wnm_send_bss_transition_mgmt_resp( struct wpa_supplicant *wpa_s, u8 dialog_token, enum bss_trans_mgmt_status_code status, u8 delay, const u8 *target_bssid) { u8 buf[1000], *pos; struct ieee80211_mgmt *mgmt; size_t len; wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response " "to " MACSTR " dialog_token=%u status=%u delay=%d", MAC2STR(wpa_s->bssid), dialog_token, status, delay); mgmt = (struct ieee80211_mgmt *) buf; os_memset(&buf, 0, sizeof(buf)); os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); mgmt->u.action.category = WLAN_ACTION_WNM; mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP; mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token; mgmt->u.action.u.bss_tm_resp.status_code = status; mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay; pos = mgmt->u.action.u.bss_tm_resp.variable; if (target_bssid) { os_memcpy(pos, target_bssid, ETH_ALEN); pos += ETH_ALEN; } else if (status == WNM_BSS_TM_ACCEPT) { /* * P802.11-REVmc clarifies that the Target BSSID field is always * present when status code is zero, so use a fake value here if * no BSSID is yet known. */ os_memset(pos, 0, ETH_ALEN); pos += ETH_ALEN; } len = pos - (u8 *) &mgmt->u.action.category; wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, &mgmt->u.action.category, len, 0); } void wnm_scan_response(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { u8 bssid[ETH_ALEN]; if (scan_res == NULL) { wpa_printf(MSG_ERROR, "Scan result is NULL"); goto send_bss_resp_fail; } /* Compare the Neighbor Report and scan results */ if (compare_scan_neighbor_results(wpa_s, scan_res, wpa_s->wnm_neighbor_report_elements, wpa_s->wnm_num_neighbor_report, bssid) == 1) { /* Associate to the network */ struct wpa_bss *bss; struct wpa_ssid *ssid = wpa_s->current_ssid; bss = wpa_bss_get_bssid(wpa_s, bssid); if (!bss) { wpa_printf(MSG_DEBUG, "WNM: Target AP not found from " "BSS table"); goto send_bss_resp_fail; } /* Send the BSS Management Response - Accept */ if (wpa_s->wnm_reply) { wnm_send_bss_transition_mgmt_resp(wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_ACCEPT, 0, bssid); } wpa_s->reassociate = 1; wpa_supplicant_connect(wpa_s, bss, ssid); wnm_deallocate_memory(wpa_s); return; } /* Send reject response for all the failures */ send_bss_resp_fail: wnm_deallocate_memory(wpa_s); if (wpa_s->wnm_reply) { wnm_send_bss_transition_mgmt_resp(wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_REJECT_UNSPECIFIED, 0, NULL); } return; } static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, const u8 *pos, const u8 *end, int reply) { if (pos + 5 > end) return; wpa_s->wnm_dialog_token = pos[0]; wpa_s->wnm_mode = pos[1]; wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); wpa_s->wnm_validity_interval = pos[4]; wpa_s->wnm_reply = reply; wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " "dialog_token=%u request_mode=0x%x " "disassoc_timer=%u validity_interval=%u", wpa_s->wnm_dialog_token, wpa_s->wnm_mode, wpa_s->wnm_dissoc_timer, wpa_s->wnm_validity_interval); pos += 5; if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { if (pos + 12 > end) { wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); return; } os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); pos += 12; /* BSS Termination Duration */ } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { char url[256]; unsigned int beacon_int; if (pos + 1 > end || pos + 1 + pos[0] > end) { wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " "Management Request (URL)"); return; } os_memcpy(url, pos + 1, pos[0]); url[pos[0]] = '\0'; pos += 1 + pos[0]; if (wpa_s->current_bss) beacon_int = wpa_s->current_bss->beacon_int; else beacon_int = 100; /* best guess */ wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", wpa_sm_pmf_enabled(wpa_s->wpa), wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { /* TODO: mark current BSS less preferred for * selection */ wpa_printf(MSG_DEBUG, "Trying to find another BSS"); wpa_supplicant_req_scan(wpa_s, 0, 0); } } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); wpa_s->wnm_num_neighbor_report = 0; os_free(wpa_s->wnm_neighbor_report_elements); wpa_s->wnm_neighbor_report_elements = os_zalloc( WNM_MAX_NEIGHBOR_REPORT * sizeof(struct neighbor_report)); if (wpa_s->wnm_neighbor_report_elements == NULL) return; while (pos + 2 <= end && wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) { u8 tag = *pos++; u8 len = *pos++; wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", tag); if (pos + len > end) { wpa_printf(MSG_DEBUG, "WNM: Truncated request"); return; } if (tag == WLAN_EID_NEIGHBOR_REPORT) { struct neighbor_report *rep; rep = &wpa_s->wnm_neighbor_report_elements[ wpa_s->wnm_num_neighbor_report]; wnm_parse_neighbor_report(wpa_s, pos, len, rep); } pos += len; wpa_s->wnm_num_neighbor_report++; } wpa_s->scan_res_handler = wnm_scan_response; wpa_supplicant_req_scan(wpa_s, 0, 0); } else if (reply) { enum bss_trans_mgmt_status_code status; if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) status = WNM_BSS_TM_ACCEPT; else { wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); status = WNM_BSS_TM_REJECT_UNSPECIFIED; } wnm_send_bss_transition_mgmt_resp(wpa_s, wpa_s->wnm_dialog_token, status, 0, NULL); } } int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, u8 query_reason) { u8 buf[1000], *pos; struct ieee80211_mgmt *mgmt; size_t len; int ret; wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " MACSTR " query_reason=%u", MAC2STR(wpa_s->bssid), query_reason); mgmt = (struct ieee80211_mgmt *) buf; os_memset(&buf, 0, sizeof(buf)); os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); mgmt->u.action.category = WLAN_ACTION_WNM; mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; mgmt->u.action.u.bss_tm_query.dialog_token = 1; mgmt->u.action.u.bss_tm_query.query_reason = query_reason; pos = mgmt->u.action.u.bss_tm_query.variable; len = pos - (u8 *) &mgmt->u.action.category; ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid, &mgmt->u.action.category, len, 0); return ret; } static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *data, int len) { const u8 *pos, *end, *next; u8 ie, ie_len; pos = data; end = data + len; while (pos + 1 < end) { ie = *pos++; ie_len = *pos++; wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u", ie, ie_len); if (ie_len > end - pos) { wpa_printf(MSG_DEBUG, "WNM: Not enough room for " "subelement"); break; } next = pos + ie_len; if (ie_len < 4) { pos = next; continue; } wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u", WPA_GET_BE24(pos), pos[3]); #ifdef CONFIG_HS20 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && WPA_GET_BE24(pos) == OUI_WFA && pos[3] == HS20_WNM_SUB_REM_NEEDED) { /* Subscription Remediation subelement */ const u8 *ie_end; u8 url_len; char *url; u8 osu_method; wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation " "subelement"); ie_end = pos + ie_len; pos += 4; url_len = *pos++; if (url_len == 0) { wpa_printf(MSG_DEBUG, "WNM: No Server URL included"); url = NULL; osu_method = 1; } else { if (pos + url_len + 1 > ie_end) { wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)", url_len, (int) (ie_end - pos)); break; } url = os_malloc(url_len + 1); if (url == NULL) break; os_memcpy(url, pos, url_len); url[url_len] = '\0'; osu_method = pos[url_len]; } hs20_rx_subscription_remediation(wpa_s, url, osu_method); os_free(url); pos = next; continue; } if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 && WPA_GET_BE24(pos) == OUI_WFA && pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) { const u8 *ie_end; u8 url_len; char *url; u8 code; u16 reauth_delay; ie_end = pos + ie_len; pos += 4; code = *pos++; reauth_delay = WPA_GET_LE16(pos); pos += 2; url_len = *pos++; wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication " "Imminent - Reason Code %u " "Re-Auth Delay %u URL Length %u", code, reauth_delay, url_len); if (pos + url_len > ie_end) break; url = os_malloc(url_len + 1); if (url == NULL) break; os_memcpy(url, pos, url_len); url[url_len] = '\0'; hs20_rx_deauth_imminent_notice(wpa_s, code, reauth_delay, url); os_free(url); pos = next; continue; } #endif /* CONFIG_HS20 */ pos = next; } } static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *frm, int len) { const u8 *pos, *end; u8 dialog_token, type; /* Dialog Token [1] | Type [1] | Subelements */ if (len < 2 || sa == NULL) return; end = frm + len; pos = frm; dialog_token = *pos++; type = *pos++; wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request " "(dialog_token %u type %u sa " MACSTR ")", dialog_token, type, MAC2STR(sa)); wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements", pos, end - pos); if (wpa_s->wpa_state != WPA_COMPLETED || os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not " "from our AP - ignore it"); return; } switch (type) { case 1: ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos); break; default: wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown " "WNM-Notification type %u", type); break; } } void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, const struct ieee80211_mgmt *mgmt, size_t len) { const u8 *pos, *end; u8 act; if (len < IEEE80211_HDRLEN + 2) return; pos = &mgmt->u.action.category; pos++; act = *pos++; end = ((const u8 *) mgmt) + len; wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR, act, MAC2STR(mgmt->sa)); if (wpa_s->wpa_state < WPA_ASSOCIATED || os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " "frame"); return; } switch (act) { case WNM_BSS_TRANS_MGMT_REQ: ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end, !(mgmt->da[0] & 0x01)); break; case WNM_SLEEP_MODE_RESP: ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos); break; case WNM_NOTIFICATION_REQ: ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos); break; default: wpa_printf(MSG_ERROR, "WNM: Unknown request"); break; } } wpa_supplicant-2.2/wpa_supplicant/ap.c0000664000175000017500000007664312343617166016034 0ustar jmjm/* * WPA Supplicant - Basic AP mode support routines * Copyright (c) 2003-2009, Jouni Malinen * Copyright (c) 2009, Atheros Communications * * 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 "utils/uuid.h" #include "common/ieee802_11_defs.h" #include "common/wpa_ctrl.h" #include "eapol_supp/eapol_supp_sm.h" #include "crypto/dh_group5.h" #include "ap/hostapd.h" #include "ap/ap_config.h" #include "ap/ap_drv_ops.h" #ifdef NEED_AP_MLME #include "ap/ieee802_11.h" #endif /* NEED_AP_MLME */ #include "ap/beacon.h" #include "ap/ieee802_1x.h" #include "ap/wps_hostapd.h" #include "ap/ctrl_iface_ap.h" #include "wps/wps.h" #include "common/ieee802_11_defs.h" #include "config_ssid.h" #include "config.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "p2p_supplicant.h" #include "ap.h" #include "ap/sta_info.h" #include "notify.h" #ifdef CONFIG_WPS static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx); #endif /* CONFIG_WPS */ #ifdef CONFIG_IEEE80211N static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s, struct hostapd_config *conf, struct hostapd_hw_modes *mode) { #ifdef CONFIG_P2P u8 center_chan = 0; u8 channel = conf->channel; if (!conf->secondary_channel) goto no_vht; center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel); if (!center_chan) goto no_vht; /* Use 80 MHz channel */ conf->vht_oper_chwidth = 1; conf->vht_oper_centr_freq_seg0_idx = center_chan; return; no_vht: conf->vht_oper_centr_freq_seg0_idx = channel + conf->secondary_channel * 2; #else /* CONFIG_P2P */ conf->vht_oper_centr_freq_seg0_idx = conf->channel + conf->secondary_channel * 2; #endif /* CONFIG_P2P */ } #endif /* CONFIG_IEEE80211N */ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct hostapd_config *conf) { struct hostapd_bss_config *bss = conf->bss[0]; conf->driver = wpa_s->driver; os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface)); conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency, &conf->channel); if (conf->hw_mode == NUM_HOSTAPD_MODES) { wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz", ssid->frequency); return -1; } /* TODO: enable HT40 if driver supports it; * drop to 11b if driver does not support 11g */ #ifdef CONFIG_IEEE80211N /* * Enable HT20 if the driver supports it, by setting conf->ieee80211n * and a mask of allowed capabilities within conf->ht_capab. * Using default config settings for: conf->ht_op_mode_fixed, * conf->secondary_channel, conf->require_ht */ if (wpa_s->hw.modes) { struct hostapd_hw_modes *mode = NULL; int i, no_ht = 0; for (i = 0; i < wpa_s->hw.num_modes; i++) { if (wpa_s->hw.modes[i].mode == conf->hw_mode) { mode = &wpa_s->hw.modes[i]; break; } } #ifdef CONFIG_HT_OVERRIDES if (ssid->disable_ht) { conf->ieee80211n = 0; conf->ht_capab = 0; no_ht = 1; } #endif /* CONFIG_HT_OVERRIDES */ if (!no_ht && mode && mode->ht_capab) { conf->ieee80211n = 1; #ifdef CONFIG_P2P if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && (mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && ssid->ht40) conf->secondary_channel = wpas_p2p_get_ht40_mode(wpa_s, mode, conf->channel); if (conf->secondary_channel) conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; #endif /* CONFIG_P2P */ /* * white-list capabilities that won't cause issues * to connecting stations, while leaving the current * capabilities intact (currently disabled SMPS). */ conf->ht_capab |= mode->ht_capab & (HT_CAP_INFO_GREEN_FIELD | HT_CAP_INFO_SHORT_GI20MHZ | HT_CAP_INFO_SHORT_GI40MHZ | HT_CAP_INFO_RX_STBC_MASK | HT_CAP_INFO_MAX_AMSDU_SIZE); if (mode->vht_capab && ssid->vht) { conf->ieee80211ac = 1; wpas_conf_ap_vht(wpa_s, conf, mode); } } } #endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_P2P if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G && (ssid->mode == WPAS_MODE_P2P_GO || ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)) { /* Remove 802.11b rates from supported and basic rate sets */ int *list = os_malloc(4 * sizeof(int)); if (list) { list[0] = 60; list[1] = 120; list[2] = 240; list[3] = -1; } conf->basic_rates = list; list = os_malloc(9 * sizeof(int)); if (list) { list[0] = 60; list[1] = 90; list[2] = 120; list[3] = 180; list[4] = 240; list[5] = 360; list[6] = 480; list[7] = 540; list[8] = -1; } conf->supported_rates = list; } bss->isolate = !wpa_s->conf->p2p_intra_bss; bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk; if (ssid->p2p_group) { os_memcpy(bss->ip_addr_go, wpa_s->parent->conf->ip_addr_go, 4); os_memcpy(bss->ip_addr_mask, wpa_s->parent->conf->ip_addr_mask, 4); os_memcpy(bss->ip_addr_start, wpa_s->parent->conf->ip_addr_start, 4); os_memcpy(bss->ip_addr_end, wpa_s->parent->conf->ip_addr_end, 4); } #endif /* CONFIG_P2P */ if (ssid->ssid_len == 0) { wpa_printf(MSG_ERROR, "No SSID configured for AP mode"); return -1; } os_memcpy(bss->ssid.ssid, ssid->ssid, ssid->ssid_len); bss->ssid.ssid_len = ssid->ssid_len; bss->ssid.ssid_set = 1; bss->ignore_broadcast_ssid = ssid->ignore_broadcast_ssid; if (ssid->auth_alg) bss->auth_algs = ssid->auth_alg; if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) bss->wpa = ssid->proto; bss->wpa_key_mgmt = ssid->key_mgmt; bss->wpa_pairwise = ssid->pairwise_cipher; if (ssid->psk_set) { os_free(bss->ssid.wpa_psk); bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk)); if (bss->ssid.wpa_psk == NULL) return -1; os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN); bss->ssid.wpa_psk->group = 1; } else if (ssid->passphrase) { bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase); } else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] || ssid->wep_key_len[2] || ssid->wep_key_len[3]) { struct hostapd_wep_keys *wep = &bss->ssid.wep; int i; for (i = 0; i < NUM_WEP_KEYS; i++) { if (ssid->wep_key_len[i] == 0) continue; wep->key[i] = os_malloc(ssid->wep_key_len[i]); if (wep->key[i] == NULL) return -1; os_memcpy(wep->key[i], ssid->wep_key[i], ssid->wep_key_len[i]); wep->len[i] = ssid->wep_key_len[i]; } wep->idx = ssid->wep_tx_keyidx; wep->keys_set = 1; } if (ssid->ap_max_inactivity) bss->ap_max_inactivity = ssid->ap_max_inactivity; if (ssid->dtim_period) bss->dtim_period = ssid->dtim_period; else if (wpa_s->conf->dtim_period) bss->dtim_period = wpa_s->conf->dtim_period; if (ssid->beacon_int) conf->beacon_int = ssid->beacon_int; else if (wpa_s->conf->beacon_int) conf->beacon_int = wpa_s->conf->beacon_int; if ((bss->wpa & 2) && bss->rsn_pairwise == 0) bss->rsn_pairwise = bss->wpa_pairwise; bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise, bss->rsn_pairwise); if (bss->wpa && bss->ieee802_1x) bss->ssid.security_policy = SECURITY_WPA; else if (bss->wpa) bss->ssid.security_policy = SECURITY_WPA_PSK; else if (bss->ieee802_1x) { int cipher = WPA_CIPHER_NONE; bss->ssid.security_policy = SECURITY_IEEE_802_1X; bss->ssid.wep.default_len = bss->default_wep_key_len; if (bss->default_wep_key_len) cipher = bss->default_wep_key_len >= 13 ? WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40; bss->wpa_group = cipher; bss->wpa_pairwise = cipher; bss->rsn_pairwise = cipher; } else if (bss->ssid.wep.keys_set) { int cipher = WPA_CIPHER_WEP40; if (bss->ssid.wep.len[0] >= 13) cipher = WPA_CIPHER_WEP104; bss->ssid.security_policy = SECURITY_STATIC_WEP; bss->wpa_group = cipher; bss->wpa_pairwise = cipher; bss->rsn_pairwise = cipher; } else { bss->ssid.security_policy = SECURITY_PLAINTEXT; bss->wpa_group = WPA_CIPHER_NONE; bss->wpa_pairwise = WPA_CIPHER_NONE; bss->rsn_pairwise = WPA_CIPHER_NONE; } if (bss->wpa_group_rekey < 86400 && (bss->wpa & 2) && (bss->wpa_group == WPA_CIPHER_CCMP || bss->wpa_group == WPA_CIPHER_GCMP || bss->wpa_group == WPA_CIPHER_CCMP_256 || bss->wpa_group == WPA_CIPHER_GCMP_256)) { /* * Strong ciphers do not need frequent rekeying, so increase * the default GTK rekeying period to 24 hours. */ bss->wpa_group_rekey = 86400; } #ifdef CONFIG_IEEE80211W if (ssid->ieee80211w != MGMT_FRAME_PROTECTION_DEFAULT) bss->ieee80211w = ssid->ieee80211w; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WPS /* * Enable WPS by default for open and WPA/WPA2-Personal network, but * require user interaction to actually use it. Only the internal * Registrar is supported. */ if (bss->ssid.security_policy != SECURITY_WPA_PSK && bss->ssid.security_policy != SECURITY_PLAINTEXT) goto no_wps; if (bss->ssid.security_policy == SECURITY_WPA_PSK && (!(bss->rsn_pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2))) goto no_wps; /* WPS2 does not allow WPA/TKIP-only * configuration */ bss->eap_server = 1; if (!ssid->ignore_broadcast_ssid) bss->wps_state = 2; bss->ap_setup_locked = 2; if (wpa_s->conf->config_methods) bss->config_methods = os_strdup(wpa_s->conf->config_methods); os_memcpy(bss->device_type, wpa_s->conf->device_type, WPS_DEV_TYPE_LEN); if (wpa_s->conf->device_name) { bss->device_name = os_strdup(wpa_s->conf->device_name); bss->friendly_name = os_strdup(wpa_s->conf->device_name); } if (wpa_s->conf->manufacturer) bss->manufacturer = os_strdup(wpa_s->conf->manufacturer); if (wpa_s->conf->model_name) bss->model_name = os_strdup(wpa_s->conf->model_name); if (wpa_s->conf->model_number) bss->model_number = os_strdup(wpa_s->conf->model_number); if (wpa_s->conf->serial_number) bss->serial_number = os_strdup(wpa_s->conf->serial_number); if (is_nil_uuid(wpa_s->conf->uuid)) os_memcpy(bss->uuid, wpa_s->wps->uuid, WPS_UUID_LEN); else os_memcpy(bss->uuid, wpa_s->conf->uuid, WPS_UUID_LEN); os_memcpy(bss->os_version, wpa_s->conf->os_version, 4); bss->pbc_in_m1 = wpa_s->conf->pbc_in_m1; no_wps: #endif /* CONFIG_WPS */ if (wpa_s->max_stations && wpa_s->max_stations < wpa_s->conf->max_num_sta) bss->max_num_sta = wpa_s->max_stations; else bss->max_num_sta = wpa_s->conf->max_num_sta; bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack; if (wpa_s->conf->ap_vendor_elements) { bss->vendor_elements = wpabuf_dup(wpa_s->conf->ap_vendor_elements); } return 0; } static void ap_public_action_rx(void *ctx, const u8 *buf, size_t len, int freq) { #ifdef CONFIG_P2P struct wpa_supplicant *wpa_s = ctx; const struct ieee80211_mgmt *mgmt; size_t hdr_len; mgmt = (const struct ieee80211_mgmt *) buf; hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf; if (hdr_len > len) return; if (mgmt->u.action.category != WLAN_ACTION_PUBLIC) return; wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid, mgmt->u.action.category, &mgmt->u.action.u.vs_public_action.action, len - hdr_len, freq); #endif /* CONFIG_P2P */ } static void ap_wps_event_cb(void *ctx, enum wps_event event, union wps_event_data *data) { #ifdef CONFIG_P2P struct wpa_supplicant *wpa_s = ctx; if (event == WPS_EV_FAIL) { struct wps_event_fail *fail = &data->fail; if (wpa_s->parent && wpa_s->parent != wpa_s && wpa_s == wpa_s->global->p2p_group_formation) { /* * src/ap/wps_hostapd.c has already sent this on the * main interface, so only send on the parent interface * here if needed. */ wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL "msg=%d config_error=%d", fail->msg, fail->config_error); } wpas_p2p_wps_failed(wpa_s, fail); } #endif /* CONFIG_P2P */ } static void ap_sta_authorized_cb(void *ctx, const u8 *mac_addr, int authorized, const u8 *p2p_dev_addr) { wpas_notify_sta_authorized(ctx, mac_addr, authorized, p2p_dev_addr); } #ifdef CONFIG_P2P static void ap_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *p2p_dev_addr, const u8 *psk, size_t psk_len) { struct wpa_supplicant *wpa_s = ctx; if (wpa_s->ap_iface == NULL || wpa_s->current_ssid == NULL) return; wpas_p2p_new_psk_cb(wpa_s, mac_addr, p2p_dev_addr, psk, psk_len); } #endif /* CONFIG_P2P */ static int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq) { #ifdef CONFIG_P2P struct wpa_supplicant *wpa_s = ctx; const struct ieee80211_mgmt *mgmt; size_t hdr_len; mgmt = (const struct ieee80211_mgmt *) buf; hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf; if (hdr_len > len) return -1; wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid, mgmt->u.action.category, &mgmt->u.action.u.vs_public_action.action, len - hdr_len, freq); #endif /* CONFIG_P2P */ return 0; } static int ap_probe_req_rx(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid, const u8 *ie, size_t ie_len, int ssi_signal) { #ifdef CONFIG_P2P struct wpa_supplicant *wpa_s = ctx; return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len, ssi_signal); #else /* CONFIG_P2P */ return 0; #endif /* CONFIG_P2P */ } static void ap_wps_reg_success_cb(void *ctx, const u8 *mac_addr, const u8 *uuid_e) { #ifdef CONFIG_P2P struct wpa_supplicant *wpa_s = ctx; wpas_p2p_wps_success(wpa_s, mac_addr, 1); #endif /* CONFIG_P2P */ } static void wpas_ap_configured_cb(void *ctx) { struct wpa_supplicant *wpa_s = ctx; wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); if (wpa_s->ap_configured_cb) wpa_s->ap_configured_cb(wpa_s->ap_configured_cb_ctx, wpa_s->ap_configured_cb_data); } int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct wpa_driver_associate_params params; struct hostapd_iface *hapd_iface; struct hostapd_config *conf; size_t i; if (ssid->ssid == NULL || ssid->ssid_len == 0) { wpa_printf(MSG_ERROR, "No SSID configured for AP mode"); return -1; } wpa_supplicant_ap_deinit(wpa_s); wpa_printf(MSG_DEBUG, "Setting up AP (SSID='%s')", wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); os_memset(¶ms, 0, sizeof(params)); params.ssid = ssid->ssid; params.ssid_len = ssid->ssid_len; switch (ssid->mode) { case WPAS_MODE_AP: case WPAS_MODE_P2P_GO: case WPAS_MODE_P2P_GROUP_FORMATION: params.mode = IEEE80211_MODE_AP; break; default: return -1; } if (ssid->frequency == 0) ssid->frequency = 2462; /* default channel 11 */ params.freq = ssid->frequency; params.wpa_proto = ssid->proto; if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) wpa_s->key_mgmt = WPA_KEY_MGMT_PSK; else wpa_s->key_mgmt = WPA_KEY_MGMT_NONE; params.key_mgmt_suite = wpa_s->key_mgmt; wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 1); if (wpa_s->pairwise_cipher < 0) { wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise " "cipher."); return -1; } params.pairwise_suite = wpa_s->pairwise_cipher; params.group_suite = params.pairwise_suite; #ifdef CONFIG_P2P if (ssid->mode == WPAS_MODE_P2P_GO || ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) params.p2p = 1; #endif /* CONFIG_P2P */ if (wpa_s->parent->set_ap_uapsd) params.uapsd = wpa_s->parent->ap_uapsd; else if (params.p2p && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD)) params.uapsd = 1; /* mandatory for P2P GO */ else params.uapsd = -1; if (wpa_drv_associate(wpa_s, ¶ms) < 0) { wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality"); return -1; } wpa_s->ap_iface = hapd_iface = os_zalloc(sizeof(*wpa_s->ap_iface)); if (hapd_iface == NULL) return -1; hapd_iface->owner = wpa_s; hapd_iface->drv_flags = wpa_s->drv_flags; hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads; hapd_iface->extended_capa = wpa_s->extended_capa; hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask; hapd_iface->extended_capa_len = wpa_s->extended_capa_len; wpa_s->ap_iface->conf = conf = hostapd_config_defaults(); if (conf == NULL) { wpa_supplicant_ap_deinit(wpa_s); return -1; } os_memcpy(wpa_s->ap_iface->conf->wmm_ac_params, wpa_s->conf->wmm_ac_params, sizeof(wpa_s->conf->wmm_ac_params)); if (params.uapsd > 0) { conf->bss[0]->wmm_enabled = 1; conf->bss[0]->wmm_uapsd = 1; } if (wpa_supplicant_conf_ap(wpa_s, ssid, conf)) { wpa_printf(MSG_ERROR, "Failed to create AP configuration"); wpa_supplicant_ap_deinit(wpa_s); return -1; } #ifdef CONFIG_P2P if (ssid->mode == WPAS_MODE_P2P_GO) conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER; else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER | P2P_GROUP_FORMATION; #endif /* CONFIG_P2P */ hapd_iface->num_bss = conf->num_bss; hapd_iface->bss = os_calloc(conf->num_bss, sizeof(struct hostapd_data *)); if (hapd_iface->bss == NULL) { wpa_supplicant_ap_deinit(wpa_s); return -1; } for (i = 0; i < conf->num_bss; i++) { hapd_iface->bss[i] = hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]); if (hapd_iface->bss[i] == NULL) { wpa_supplicant_ap_deinit(wpa_s); return -1; } hapd_iface->bss[i]->msg_ctx = wpa_s; hapd_iface->bss[i]->msg_ctx_parent = wpa_s->parent; hapd_iface->bss[i]->public_action_cb = ap_public_action_rx; hapd_iface->bss[i]->public_action_cb_ctx = wpa_s; hapd_iface->bss[i]->vendor_action_cb = ap_vendor_action_rx; hapd_iface->bss[i]->vendor_action_cb_ctx = wpa_s; hostapd_register_probereq_cb(hapd_iface->bss[i], ap_probe_req_rx, wpa_s); hapd_iface->bss[i]->wps_reg_success_cb = ap_wps_reg_success_cb; hapd_iface->bss[i]->wps_reg_success_cb_ctx = wpa_s; hapd_iface->bss[i]->wps_event_cb = ap_wps_event_cb; hapd_iface->bss[i]->wps_event_cb_ctx = wpa_s; hapd_iface->bss[i]->sta_authorized_cb = ap_sta_authorized_cb; hapd_iface->bss[i]->sta_authorized_cb_ctx = wpa_s; #ifdef CONFIG_P2P hapd_iface->bss[i]->new_psk_cb = ap_new_psk_cb; hapd_iface->bss[i]->new_psk_cb_ctx = wpa_s; hapd_iface->bss[i]->p2p = wpa_s->global->p2p; hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(wpa_s, ssid); #endif /* CONFIG_P2P */ hapd_iface->bss[i]->setup_complete_cb = wpas_ap_configured_cb; hapd_iface->bss[i]->setup_complete_cb_ctx = wpa_s; } os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN); hapd_iface->bss[0]->driver = wpa_s->driver; hapd_iface->bss[0]->drv_priv = wpa_s->drv_priv; wpa_s->current_ssid = ssid; eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN); wpa_s->assoc_freq = ssid->frequency; if (hostapd_setup_interface(wpa_s->ap_iface)) { wpa_printf(MSG_ERROR, "Failed to initialize AP interface"); wpa_supplicant_ap_deinit(wpa_s); return -1; } return 0; } void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s) { #ifdef CONFIG_WPS eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL); #endif /* CONFIG_WPS */ if (wpa_s->ap_iface == NULL) return; wpa_s->current_ssid = NULL; eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_s->assoc_freq = 0; #ifdef CONFIG_P2P if (wpa_s->ap_iface->bss) wpa_s->ap_iface->bss[0]->p2p_group = NULL; wpas_p2p_group_deinit(wpa_s); #endif /* CONFIG_P2P */ wpa_s->ap_iface->driver_ap_teardown = !!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); hostapd_interface_deinit(wpa_s->ap_iface); hostapd_interface_free(wpa_s->ap_iface); wpa_s->ap_iface = NULL; wpa_drv_deinit_ap(wpa_s); } void ap_tx_status(void *ctx, const u8 *addr, const u8 *buf, size_t len, int ack) { #ifdef NEED_AP_MLME struct wpa_supplicant *wpa_s = ctx; hostapd_tx_status(wpa_s->ap_iface->bss[0], addr, buf, len, ack); #endif /* NEED_AP_MLME */ } void ap_eapol_tx_status(void *ctx, const u8 *dst, const u8 *data, size_t len, int ack) { #ifdef NEED_AP_MLME struct wpa_supplicant *wpa_s = ctx; if (!wpa_s->ap_iface) return; hostapd_tx_status(wpa_s->ap_iface->bss[0], dst, data, len, ack); #endif /* NEED_AP_MLME */ } void ap_client_poll_ok(void *ctx, const u8 *addr) { #ifdef NEED_AP_MLME struct wpa_supplicant *wpa_s = ctx; if (wpa_s->ap_iface) hostapd_client_poll_ok(wpa_s->ap_iface->bss[0], addr); #endif /* NEED_AP_MLME */ } void ap_rx_from_unknown_sta(void *ctx, const u8 *addr, int wds) { #ifdef NEED_AP_MLME struct wpa_supplicant *wpa_s = ctx; ieee802_11_rx_from_unknown(wpa_s->ap_iface->bss[0], addr, wds); #endif /* NEED_AP_MLME */ } void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt) { #ifdef NEED_AP_MLME struct wpa_supplicant *wpa_s = ctx; struct hostapd_frame_info fi; os_memset(&fi, 0, sizeof(fi)); fi.datarate = rx_mgmt->datarate; fi.ssi_signal = rx_mgmt->ssi_signal; ieee802_11_mgmt(wpa_s->ap_iface->bss[0], rx_mgmt->frame, rx_mgmt->frame_len, &fi); #endif /* NEED_AP_MLME */ } void ap_mgmt_tx_cb(void *ctx, const u8 *buf, size_t len, u16 stype, int ok) { #ifdef NEED_AP_MLME struct wpa_supplicant *wpa_s = ctx; ieee802_11_mgmt_cb(wpa_s->ap_iface->bss[0], buf, len, stype, ok); #endif /* NEED_AP_MLME */ } void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s, const u8 *src_addr, const u8 *buf, size_t len) { ieee802_1x_receive(wpa_s->ap_iface->bss[0], src_addr, buf, len); } #ifdef CONFIG_WPS int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, const u8 *p2p_dev_addr) { if (!wpa_s->ap_iface) return -1; return hostapd_wps_button_pushed(wpa_s->ap_iface->bss[0], p2p_dev_addr); } int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s) { struct wps_registrar *reg; int reg_sel = 0, wps_sta = 0; if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0]->wps) return -1; reg = wpa_s->ap_iface->bss[0]->wps->registrar; reg_sel = wps_registrar_wps_cancel(reg); wps_sta = ap_for_each_sta(wpa_s->ap_iface->bss[0], ap_sta_wps_cancel, NULL); if (!reg_sel && !wps_sta) { wpa_printf(MSG_DEBUG, "No WPS operation in progress at this " "time"); return -1; } /* * There are 2 cases to return wps cancel as success: * 1. When wps cancel was initiated but no connection has been * established with client yet. * 2. Client is in the middle of exchanging WPS messages. */ return 0; } int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, const char *pin, char *buf, size_t buflen, int timeout) { int ret, ret_len = 0; if (!wpa_s->ap_iface) return -1; if (pin == NULL) { unsigned int rpin = wps_generate_pin(); ret_len = os_snprintf(buf, buflen, "%08d", rpin); pin = buf; } else ret_len = os_snprintf(buf, buflen, "%s", pin); ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin, timeout); if (ret) return -1; return ret_len; } static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx) { struct wpa_supplicant *wpa_s = eloop_data; wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out"); wpas_wps_ap_pin_disable(wpa_s); } static void wpas_wps_ap_pin_enable(struct wpa_supplicant *wpa_s, int timeout) { struct hostapd_data *hapd; if (wpa_s->ap_iface == NULL) return; hapd = wpa_s->ap_iface->bss[0]; wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout); hapd->ap_pin_failures = 0; eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL); if (timeout > 0) eloop_register_timeout(timeout, 0, wpas_wps_ap_pin_timeout, wpa_s, NULL); } void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s) { struct hostapd_data *hapd; if (wpa_s->ap_iface == NULL) return; wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN"); hapd = wpa_s->ap_iface->bss[0]; os_free(hapd->conf->ap_pin); hapd->conf->ap_pin = NULL; eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL); } const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout) { struct hostapd_data *hapd; unsigned int pin; char pin_txt[9]; if (wpa_s->ap_iface == NULL) return NULL; hapd = wpa_s->ap_iface->bss[0]; pin = wps_generate_pin(); os_snprintf(pin_txt, sizeof(pin_txt), "%08u", pin); os_free(hapd->conf->ap_pin); hapd->conf->ap_pin = os_strdup(pin_txt); if (hapd->conf->ap_pin == NULL) return NULL; wpas_wps_ap_pin_enable(wpa_s, timeout); return hapd->conf->ap_pin; } const char * wpas_wps_ap_pin_get(struct wpa_supplicant *wpa_s) { struct hostapd_data *hapd; if (wpa_s->ap_iface == NULL) return NULL; hapd = wpa_s->ap_iface->bss[0]; return hapd->conf->ap_pin; } int wpas_wps_ap_pin_set(struct wpa_supplicant *wpa_s, const char *pin, int timeout) { struct hostapd_data *hapd; char pin_txt[9]; int ret; if (wpa_s->ap_iface == NULL) return -1; hapd = wpa_s->ap_iface->bss[0]; ret = os_snprintf(pin_txt, sizeof(pin_txt), "%s", pin); if (ret < 0 || ret >= (int) sizeof(pin_txt)) return -1; os_free(hapd->conf->ap_pin); hapd->conf->ap_pin = os_strdup(pin_txt); if (hapd->conf->ap_pin == NULL) return -1; wpas_wps_ap_pin_enable(wpa_s, timeout); return 0; } void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s) { struct hostapd_data *hapd; if (wpa_s->ap_iface == NULL) return; hapd = wpa_s->ap_iface->bss[0]; /* * Registrar failed to prove its knowledge of the AP PIN. Disable AP * PIN if this happens multiple times to slow down brute force attacks. */ hapd->ap_pin_failures++; wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u", hapd->ap_pin_failures); if (hapd->ap_pin_failures < 3) return; wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN"); hapd->ap_pin_failures = 0; os_free(hapd->conf->ap_pin); hapd->conf->ap_pin = NULL; } #ifdef CONFIG_WPS_NFC struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s, int ndef) { struct hostapd_data *hapd; if (wpa_s->ap_iface == NULL) return NULL; hapd = wpa_s->ap_iface->bss[0]; return hostapd_wps_nfc_config_token(hapd, ndef); } struct wpabuf * wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef) { struct hostapd_data *hapd; if (wpa_s->ap_iface == NULL) return NULL; hapd = wpa_s->ap_iface->bss[0]; return hostapd_wps_nfc_hs_cr(hapd, ndef); } int wpas_ap_wps_nfc_report_handover(struct wpa_supplicant *wpa_s, const struct wpabuf *req, const struct wpabuf *sel) { struct hostapd_data *hapd; if (wpa_s->ap_iface == NULL) return -1; hapd = wpa_s->ap_iface->bss[0]; return hostapd_wps_nfc_report_handover(hapd, req, sel); } #endif /* CONFIG_WPS_NFC */ #endif /* CONFIG_WPS */ #ifdef CONFIG_CTRL_IFACE int ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { if (wpa_s->ap_iface == NULL) return -1; return hostapd_ctrl_iface_sta_first(wpa_s->ap_iface->bss[0], buf, buflen); } int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr, char *buf, size_t buflen) { if (wpa_s->ap_iface == NULL) return -1; return hostapd_ctrl_iface_sta(wpa_s->ap_iface->bss[0], txtaddr, buf, buflen); } int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr, char *buf, size_t buflen) { if (wpa_s->ap_iface == NULL) return -1; return hostapd_ctrl_iface_sta_next(wpa_s->ap_iface->bss[0], txtaddr, buf, buflen); } int ap_ctrl_iface_sta_disassociate(struct wpa_supplicant *wpa_s, const char *txtaddr) { if (wpa_s->ap_iface == NULL) return -1; return hostapd_ctrl_iface_disassociate(wpa_s->ap_iface->bss[0], txtaddr); } int ap_ctrl_iface_sta_deauthenticate(struct wpa_supplicant *wpa_s, const char *txtaddr) { if (wpa_s->ap_iface == NULL) return -1; return hostapd_ctrl_iface_deauthenticate(wpa_s->ap_iface->bss[0], txtaddr); } int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen, int verbose) { char *pos = buf, *end = buf + buflen; int ret; struct hostapd_bss_config *conf; if (wpa_s->ap_iface == NULL) return -1; conf = wpa_s->ap_iface->bss[0]->conf; if (conf->wpa == 0) return 0; ret = os_snprintf(pos, end - pos, "pairwise_cipher=%s\n" "group_cipher=%s\n" "key_mgmt=%s\n", wpa_cipher_txt(conf->rsn_pairwise), wpa_cipher_txt(conf->wpa_group), wpa_key_mgmt_txt(conf->wpa_key_mgmt, conf->wpa)); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; return pos - buf; } #endif /* CONFIG_CTRL_IFACE */ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s) { struct hostapd_iface *iface = wpa_s->ap_iface; struct wpa_ssid *ssid = wpa_s->current_ssid; struct hostapd_data *hapd; if (ssid == NULL || wpa_s->ap_iface == NULL || ssid->mode == WPAS_MODE_INFRA || ssid->mode == WPAS_MODE_IBSS) return -1; #ifdef CONFIG_P2P if (ssid->mode == WPAS_MODE_P2P_GO) iface->conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER; else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) iface->conf->bss[0]->p2p = P2P_ENABLED | P2P_GROUP_OWNER | P2P_GROUP_FORMATION; #endif /* CONFIG_P2P */ hapd = iface->bss[0]; if (hapd->drv_priv == NULL) return -1; ieee802_11_set_beacons(iface); hostapd_set_ap_wps_ie(hapd); return 0; } int ap_switch_channel(struct wpa_supplicant *wpa_s, struct csa_settings *settings) { #ifdef NEED_AP_MLME if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0]) return -1; return hostapd_switch_channel(wpa_s->ap_iface->bss[0], settings); #else /* NEED_AP_MLME */ return -1; #endif /* NEED_AP_MLME */ } int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos) { struct csa_settings settings; int ret = hostapd_parse_csa_settings(pos, &settings); if (ret) return ret; return ap_switch_channel(wpa_s, &settings); } void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht, int offset, int width, int cf1, int cf2) { if (!wpa_s->ap_iface) return; wpa_s->assoc_freq = freq; hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset, width, cf1, cf1); } int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s, const u8 *addr) { struct hostapd_data *hapd; struct hostapd_bss_config *conf; if (!wpa_s->ap_iface) return -1; if (addr) wpa_printf(MSG_DEBUG, "AP: Set MAC address filter: " MACSTR, MAC2STR(addr)); else wpa_printf(MSG_DEBUG, "AP: Clear MAC address filter"); hapd = wpa_s->ap_iface->bss[0]; conf = hapd->conf; os_free(conf->accept_mac); conf->accept_mac = NULL; conf->num_accept_mac = 0; os_free(conf->deny_mac); conf->deny_mac = NULL; conf->num_deny_mac = 0; if (addr == NULL) { conf->macaddr_acl = ACCEPT_UNLESS_DENIED; return 0; } conf->macaddr_acl = DENY_UNLESS_ACCEPTED; conf->accept_mac = os_zalloc(sizeof(struct mac_acl_entry)); if (conf->accept_mac == NULL) return -1; os_memcpy(conf->accept_mac[0].addr, addr, ETH_ALEN); conf->num_accept_mac = 1; return 0; } #ifdef CONFIG_WPS_NFC int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id, const struct wpabuf *pw, const u8 *pubkey_hash) { struct hostapd_data *hapd; struct wps_context *wps; if (!wpa_s->ap_iface) return -1; hapd = wpa_s->ap_iface->bss[0]; wps = hapd->wps; if (wpa_s->parent->conf->wps_nfc_dh_pubkey == NULL || wpa_s->parent->conf->wps_nfc_dh_privkey == NULL) { wpa_printf(MSG_DEBUG, "P2P: No NFC DH key known"); return -1; } dh5_free(wps->dh_ctx); wpabuf_free(wps->dh_pubkey); wpabuf_free(wps->dh_privkey); wps->dh_privkey = wpabuf_dup( wpa_s->parent->conf->wps_nfc_dh_privkey); wps->dh_pubkey = wpabuf_dup( wpa_s->parent->conf->wps_nfc_dh_pubkey); if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) { wps->dh_ctx = NULL; wpabuf_free(wps->dh_pubkey); wps->dh_pubkey = NULL; wpabuf_free(wps->dh_privkey); wps->dh_privkey = NULL; return -1; } wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey); if (wps->dh_ctx == NULL) return -1; return wps_registrar_add_nfc_pw_token(hapd->wps->registrar, pubkey_hash, pw_id, pw ? wpabuf_head(pw) : NULL, pw ? wpabuf_len(pw) : 0, 1); } #endif /* CONFIG_WPS_NFC */ wpa_supplicant-2.2/wpa_supplicant/wpas_kay.h0000664000175000017500000000163212343617166017241 0ustar jmjm/* * IEEE 802.1X-2010 KaY Interface * Copyright (c) 2013-2014, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef WPAS_KAY_H #define WPAS_KAY_H #ifdef CONFIG_MACSEC int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s, const u8 *peer_addr); void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s); #else /* CONFIG_MACSEC */ static inline int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { return 0; } static inline void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s, const u8 *peer_addr) { return NULL; } static inline void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s) { } #endif /* CONFIG_MACSEC */ #endif /* WPAS_KAY_H */ wpa_supplicant-2.2/wpa_supplicant/notify.h0000664000175000017500000001322112343617166016730 0ustar jmjm/* * wpa_supplicant - Event notifications * Copyright (c) 2009-2010, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef NOTIFY_H #define NOTIFY_H #include "p2p/p2p.h" struct wps_credential; struct wps_event_m2d; struct wps_event_fail; int wpas_notify_supplicant_initialized(struct wpa_global *global); void wpas_notify_supplicant_deinitialized(struct wpa_global *global); int wpas_notify_iface_added(struct wpa_supplicant *wpa_s); void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s); void wpas_notify_state_changed(struct wpa_supplicant *wpa_s, enum wpa_states new_state, enum wpa_states old_state); void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s); void wpas_notify_network_changed(struct wpa_supplicant *wpa_s); void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s); void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s); void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s); void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_notify_network_selected(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_notify_network_request(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, enum wpa_ctrl_req_type rtype, const char *default_txt); void wpas_notify_scanning(struct wpa_supplicant *wpa_s); void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success); void wpas_notify_scan_results(struct wpa_supplicant *wpa_s); void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s, const struct wps_credential *cred); void wpas_notify_wps_event_m2d(struct wpa_supplicant *wpa_s, struct wps_event_m2d *m2d); void wpas_notify_wps_event_fail(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail); void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s); void wpas_notify_network_added(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_notify_network_removed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_notify_bss_added(struct wpa_supplicant *wpa_s, u8 bssid[], unsigned int id); void wpas_notify_bss_removed(struct wpa_supplicant *wpa_s, u8 bssid[], unsigned int id); void wpas_notify_bss_freq_changed(struct wpa_supplicant *wpa_s, unsigned int id); void wpas_notify_bss_signal_changed(struct wpa_supplicant *wpa_s, unsigned int id); void wpas_notify_bss_privacy_changed(struct wpa_supplicant *wpa_s, unsigned int id); void wpas_notify_bss_mode_changed(struct wpa_supplicant *wpa_s, unsigned int id); void wpas_notify_bss_wpaie_changed(struct wpa_supplicant *wpa_s, unsigned int id); void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s, unsigned int id); void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s, unsigned int id); void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s, unsigned int id); void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s, unsigned int id); void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name); void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name); void wpas_notify_debug_level_changed(struct wpa_global *global); void wpas_notify_debug_timestamp_changed(struct wpa_global *global); void wpas_notify_debug_show_keys_changed(struct wpa_global *global); void wpas_notify_suspend(struct wpa_global *global); void wpas_notify_resume(struct wpa_global *global); void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *mac_addr, int authorized, const u8 *p2p_dev_addr); void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s, const u8 *dev_addr, int new_device); void wpas_notify_p2p_device_lost(struct wpa_supplicant *wpa_s, const u8 *dev_addr); void wpas_notify_p2p_group_removed(struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role); void wpas_notify_p2p_go_neg_req(struct wpa_supplicant *wpa_s, const u8 *src, u16 dev_passwd_id); void wpas_notify_p2p_go_neg_completed(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *res); void wpas_notify_p2p_invitation_result(struct wpa_supplicant *wpa_s, int status, const u8 *bssid); void wpas_notify_p2p_sd_request(struct wpa_supplicant *wpa_s, int freq, const u8 *sa, u8 dialog_token, u16 update_indic, const u8 *tlvs, size_t tlvs_len); void wpas_notify_p2p_sd_response(struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic, const u8 *tlvs, size_t tlvs_len); void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request, enum p2p_prov_disc_status status, u16 config_methods, unsigned int generated_pin); void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int network_id, int client); void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_notify_persistent_group_removed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail); void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth, const char *subject, const char *cert_hash, const struct wpabuf *cert); void wpas_notify_preq(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *dst, const u8 *bssid, const u8 *ie, size_t ie_len, u32 ssi_signal); void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status, const char *parameter); #endif /* NOTIFY_H */ wpa_supplicant-2.2/wpa_supplicant/wps_supplicant.h0000664000175000017500000001152512343617166020500 0ustar jmjm/* * wpa_supplicant / WPS integration * Copyright (c) 2008-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef WPS_SUPPLICANT_H #define WPS_SUPPLICANT_H struct wpa_scan_results; #ifdef CONFIG_WPS #include "wps/wps.h" #include "wps/wps_defs.h" struct wpa_bss; struct wps_new_ap_settings { const char *ssid_hex; const char *auth; const char *encr; const char *key_hex; }; int wpas_wps_init(struct wpa_supplicant *wpa_s); void wpas_wps_deinit(struct wpa_supplicant *wpa_s); int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s); enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid); int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, int p2p_group); int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, const char *pin, int p2p_group, u16 dev_pw_id); int wpas_wps_cancel(struct wpa_supplicant *wpa_s); int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid, const char *pin, struct wps_new_ap_settings *settings); int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_bss *bss); int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_bss *bss); int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, struct wpa_bss *selected, struct wpa_ssid *ssid); void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s); int wpas_wps_searching(struct wpa_supplicant *wpa_s); int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *pos, char *end); int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter); int wpas_wps_er_stop(struct wpa_supplicant *wpa_s); int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr, const char *uuid, const char *pin); int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid); int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid, const char *pin); int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid, int id); int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid, const char *pin, struct wps_new_ap_settings *settings); struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s, int ndef, const char *uuid); int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s); void wpas_wps_update_config(struct wpa_supplicant *wpa_s); struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s, int ndef, const char *id_str); struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef); int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *dev_addr, const u8 *bssid, const struct wpabuf *dev_pw, u16 dev_pw_id, int p2p_group, const u8 *peer_pubkey_hash, const u8 *ssid, size_t ssid_len, int freq); int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s, const struct wpabuf *data, int forced_freq); struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s, int ndef); struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef, int cr, const char *uuid); int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s, const struct wpabuf *req, const struct wpabuf *sel); int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s, const struct wpabuf *req, const struct wpabuf *sel); void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid); #else /* CONFIG_WPS */ static inline int wpas_wps_init(struct wpa_supplicant *wpa_s) { return 0; } static inline void wpas_wps_deinit(struct wpa_supplicant *wpa_s) { } static inline int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) { return 0; } static inline u8 wpas_wps_get_req_type(struct wpa_ssid *ssid) { return 0; } static inline int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_bss *bss) { return -1; } static inline int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_bss *bss) { return 0; } static inline int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, struct wpa_bss *selected, struct wpa_ssid *ssid) { return 0; } static inline void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s) { } static inline int wpas_wps_searching(struct wpa_supplicant *wpa_s) { return 0; } static inline void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { } static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid) { } #endif /* CONFIG_WPS */ #endif /* WPS_SUPPLICANT_H */ wpa_supplicant-2.2/wpa_supplicant/Android.mk0000664000175000017500000010361712343617166017171 0ustar jmjm# # Copyright (C) 2008 The Android Open Source Project # # This software may be distributed under the terms of the BSD license. # See README for more details. # LOCAL_PATH := $(call my-dir) PKG_CONFIG ?= pkg-config ifneq ($(BOARD_WPA_SUPPLICANT_DRIVER),) CONFIG_DRIVER_$(BOARD_WPA_SUPPLICANT_DRIVER) := y else CONFIG_DRIVER_TEST := y endif include $(LOCAL_PATH)/android.config # To ignore possible wrong network configurations L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS L_CFLAGS += -DVERSION_STR_POSTFIX=\"-$(PLATFORM_VERSION)\" # Set Android log name L_CFLAGS += -DANDROID_LOG_NAME=\"wpa_supplicant\" # Disable unused parameter warnings L_CFLAGS += -Wno-unused-parameter # Set Android extended P2P functionality L_CFLAGS += -DANDROID_P2P ifeq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),) L_CFLAGS += -DANDROID_P2P_STUB endif # Disable roaming in wpa_supplicant ifdef CONFIG_NO_ROAMING L_CFLAGS += -DCONFIG_NO_ROAMING endif ifeq ($(BOARD_WLAN_DEVICE), bcmdhd) L_CFLAGS += -DP2P_CONCURRENT_SEARCH_DELAY=0 endif # Use Android specific directory for control interface sockets L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\" L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/system/wpa_supplicant\" # To force sizeof(enum) = 4 ifeq ($(TARGET_ARCH),arm) L_CFLAGS += -mabi=aapcs-linux endif INCLUDES = $(LOCAL_PATH) INCLUDES += $(LOCAL_PATH)/src INCLUDES += $(LOCAL_PATH)/src/common # INCLUDES += $(LOCAL_PATH)/src/crypto # To force proper includes INCLUDES += $(LOCAL_PATH)/src/drivers INCLUDES += $(LOCAL_PATH)/src/eap_common INCLUDES += $(LOCAL_PATH)/src/eapol_supp INCLUDES += $(LOCAL_PATH)/src/eap_peer INCLUDES += $(LOCAL_PATH)/src/eap_server INCLUDES += $(LOCAL_PATH)/src/hlr_auc_gw INCLUDES += $(LOCAL_PATH)/src/l2_packet INCLUDES += $(LOCAL_PATH)/src/radius INCLUDES += $(LOCAL_PATH)/src/rsn_supp INCLUDES += $(LOCAL_PATH)/src/tls INCLUDES += $(LOCAL_PATH)/src/utils INCLUDES += $(LOCAL_PATH)/src/wps INCLUDES += external/openssl/include INCLUDES += system/security/keystore/include ifdef CONFIG_DRIVER_NL80211 ifneq ($(wildcard external/libnl),) INCLUDES += external/libnl/include else INCLUDES += external/libnl-headers endif endif ifdef CONFIG_FIPS CONFIG_NO_RANDOM_POOL= CONFIG_OPENSSL_CMAC=y endif OBJS = config.c OBJS += notify.c OBJS += bss.c OBJS += eap_register.c OBJS += src/utils/common.c OBJS += src/utils/wpa_debug.c OBJS += src/utils/wpabuf.c OBJS_p = wpa_passphrase.c OBJS_p += src/utils/common.c OBJS_p += src/utils/wpa_debug.c OBJS_p += src/utils/wpabuf.c OBJS_c = wpa_cli.c src/common/wpa_ctrl.c OBJS_c += src/utils/wpa_debug.c OBJS_c += src/utils/common.c OBJS_d = OBJS_priv = ifndef CONFIG_OS ifdef CONFIG_NATIVE_WINDOWS CONFIG_OS=win32 else CONFIG_OS=unix endif endif ifeq ($(CONFIG_OS), internal) L_CFLAGS += -DOS_NO_C_LIB_DEFINES endif OBJS += src/utils/os_$(CONFIG_OS).c OBJS_p += src/utils/os_$(CONFIG_OS).c OBJS_c += src/utils/os_$(CONFIG_OS).c ifdef CONFIG_WPA_TRACE L_CFLAGS += -DWPA_TRACE OBJS += src/utils/trace.c OBJS_p += src/utils/trace.c OBJS_c += src/utils/trace.c LDFLAGS += -rdynamic L_CFLAGS += -funwind-tables ifdef CONFIG_WPA_TRACE_BFD L_CFLAGS += -DWPA_TRACE_BFD LIBS += -lbfd LIBS_p += -lbfd LIBS_c += -lbfd endif endif ifndef CONFIG_ELOOP CONFIG_ELOOP=eloop endif OBJS += src/utils/$(CONFIG_ELOOP).c OBJS_c += src/utils/$(CONFIG_ELOOP).c ifdef CONFIG_ELOOP_POLL L_CFLAGS += -DCONFIG_ELOOP_POLL endif ifdef CONFIG_ELOOP_EPOLL L_CFLAGS += -DCONFIG_ELOOP_EPOLL endif ifdef CONFIG_EAPOL_TEST L_CFLAGS += -Werror -DEAPOL_TEST endif ifdef CONFIG_HT_OVERRIDES L_CFLAGS += -DCONFIG_HT_OVERRIDES endif ifdef CONFIG_VHT_OVERRIDES L_CFLAGS += -DCONFIG_VHT_OVERRIDES endif ifndef CONFIG_BACKEND CONFIG_BACKEND=file endif ifeq ($(CONFIG_BACKEND), file) OBJS += config_file.c ifndef CONFIG_NO_CONFIG_BLOBS NEED_BASE64=y endif L_CFLAGS += -DCONFIG_BACKEND_FILE endif ifeq ($(CONFIG_BACKEND), winreg) OBJS += config_winreg.c endif ifeq ($(CONFIG_BACKEND), none) OBJS += config_none.c endif ifdef CONFIG_NO_CONFIG_WRITE L_CFLAGS += -DCONFIG_NO_CONFIG_WRITE endif ifdef CONFIG_NO_CONFIG_BLOBS L_CFLAGS += -DCONFIG_NO_CONFIG_BLOBS endif ifdef CONFIG_NO_SCAN_PROCESSING L_CFLAGS += -DCONFIG_NO_SCAN_PROCESSING endif ifdef CONFIG_IEEE80211W L_CFLAGS += -DCONFIG_IEEE80211W NEED_SHA256=y NEED_AES_OMAC1=y endif ifdef CONFIG_IEEE80211R L_CFLAGS += -DCONFIG_IEEE80211R OBJS += src/rsn_supp/wpa_ft.c NEED_80211_COMMON=y NEED_SHA256=y NEED_AES_OMAC1=y endif ifdef CONFIG_SAE L_CFLAGS += -DCONFIG_SAE OBJS += src/common/sae.c NEED_ECC=y NEED_DH_GROUPS=y endif ifdef CONFIG_WNM L_CFLAGS += -DCONFIG_WNM OBJS += wnm_sta.c endif ifdef CONFIG_TDLS L_CFLAGS += -DCONFIG_TDLS OBJS += src/rsn_supp/tdls.c NEED_SHA256=y NEED_AES_OMAC1=y endif ifdef CONFIG_TDLS_TESTING L_CFLAGS += -DCONFIG_TDLS_TESTING endif ifdef CONFIG_PEERKEY L_CFLAGS += -DCONFIG_PEERKEY endif ifndef CONFIG_NO_WPA OBJS += src/rsn_supp/wpa.c OBJS += src/rsn_supp/preauth.c OBJS += src/rsn_supp/pmksa_cache.c OBJS += src/rsn_supp/peerkey.c OBJS += src/rsn_supp/wpa_ie.c OBJS += src/common/wpa_common.c NEED_AES=y NEED_SHA1=y NEED_MD5=y NEED_RC4=y else L_CFLAGS += -DCONFIG_NO_WPA endif ifdef CONFIG_IBSS_RSN NEED_RSN_AUTHENTICATOR=y L_CFLAGS += -DCONFIG_IBSS_RSN OBJS += ibss_rsn.c endif ifdef CONFIG_P2P OBJS += p2p_supplicant.c OBJS += src/p2p/p2p.c OBJS += src/p2p/p2p_utils.c OBJS += src/p2p/p2p_parse.c OBJS += src/p2p/p2p_build.c OBJS += src/p2p/p2p_go_neg.c OBJS += src/p2p/p2p_sd.c OBJS += src/p2p/p2p_pd.c OBJS += src/p2p/p2p_invitation.c OBJS += src/p2p/p2p_dev_disc.c OBJS += src/p2p/p2p_group.c OBJS += src/ap/p2p_hostapd.c OBJS += src/utils/bitfield.c L_CFLAGS += -DCONFIG_P2P NEED_GAS=y NEED_OFFCHANNEL=y NEED_80211_COMMON=y CONFIG_WPS=y CONFIG_AP=y ifdef CONFIG_P2P_STRICT L_CFLAGS += -DCONFIG_P2P_STRICT endif endif ifdef CONFIG_WIFI_DISPLAY L_CFLAGS += -DCONFIG_WIFI_DISPLAY OBJS += wifi_display.c endif ifdef CONFIG_HS20 OBJS += hs20_supplicant.c L_CFLAGS += -DCONFIG_HS20 CONFIG_INTERWORKING=y NEED_AES_OMAC1=y endif ifdef CONFIG_INTERWORKING OBJS += interworking.c L_CFLAGS += -DCONFIG_INTERWORKING NEED_GAS=y endif include $(LOCAL_PATH)/src/drivers/drivers.mk ifdef CONFIG_AP OBJS_d += $(DRV_BOTH_OBJS) L_CFLAGS += $(DRV_BOTH_CFLAGS) LDFLAGS += $(DRV_BOTH_LDFLAGS) LIBS += $(DRV_BOTH_LIBS) else NEED_AP_MLME= OBJS_d += $(DRV_WPA_OBJS) L_CFLAGS += $(DRV_WPA_CFLAGS) LDFLAGS += $(DRV_WPA_LDFLAGS) LIBS += $(DRV_WPA_LIBS) endif ifndef CONFIG_L2_PACKET CONFIG_L2_PACKET=linux endif OBJS_l2 += src/l2_packet/l2_packet_$(CONFIG_L2_PACKET).c ifeq ($(CONFIG_L2_PACKET), pcap) ifdef CONFIG_WINPCAP L_CFLAGS += -DCONFIG_WINPCAP LIBS += -lwpcap -lpacket LIBS_w += -lwpcap else LIBS += -ldnet -lpcap endif endif ifeq ($(CONFIG_L2_PACKET), winpcap) LIBS += -lwpcap -lpacket LIBS_w += -lwpcap endif ifeq ($(CONFIG_L2_PACKET), freebsd) LIBS += -lpcap endif ifdef CONFIG_EAP_TLS # EAP-TLS ifeq ($(CONFIG_EAP_TLS), dyn) L_CFLAGS += -DEAP_TLS_DYNAMIC EAPDYN += src/eap_peer/eap_tls.so else L_CFLAGS += -DEAP_TLS OBJS += src/eap_peer/eap_tls.c OBJS_h += src/eap_server/eap_server_tls.c endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_UNAUTH_TLS # EAP-UNAUTH-TLS L_CFLAGS += -DEAP_UNAUTH_TLS ifndef CONFIG_EAP_UNAUTH_TLS OBJS += src/eap_peer/eap_tls.c OBJS_h += src/eap_server/eap_server_tls.c TLS_FUNCS=y endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_PEAP # EAP-PEAP ifeq ($(CONFIG_EAP_PEAP), dyn) L_CFLAGS += -DEAP_PEAP_DYNAMIC EAPDYN += src/eap_peer/eap_peap.so else L_CFLAGS += -DEAP_PEAP OBJS += src/eap_peer/eap_peap.c OBJS += src/eap_common/eap_peap_common.c OBJS_h += src/eap_server/eap_server_peap.c endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_TTLS # EAP-TTLS ifeq ($(CONFIG_EAP_TTLS), dyn) L_CFLAGS += -DEAP_TTLS_DYNAMIC EAPDYN += src/eap_peer/eap_ttls.so else L_CFLAGS += -DEAP_TTLS OBJS += src/eap_peer/eap_ttls.c OBJS_h += src/eap_server/eap_server_ttls.c endif MS_FUNCS=y TLS_FUNCS=y CHAP=y CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_MD5 # EAP-MD5 ifeq ($(CONFIG_EAP_MD5), dyn) L_CFLAGS += -DEAP_MD5_DYNAMIC EAPDYN += src/eap_peer/eap_md5.so else L_CFLAGS += -DEAP_MD5 OBJS += src/eap_peer/eap_md5.c OBJS_h += src/eap_server/eap_server_md5.c endif CHAP=y CONFIG_IEEE8021X_EAPOL=y endif # backwards compatibility for old spelling ifdef CONFIG_MSCHAPV2 ifndef CONFIG_EAP_MSCHAPV2 CONFIG_EAP_MSCHAPV2=y endif endif ifdef CONFIG_EAP_MSCHAPV2 # EAP-MSCHAPv2 ifeq ($(CONFIG_EAP_MSCHAPV2), dyn) L_CFLAGS += -DEAP_MSCHAPv2_DYNAMIC EAPDYN += src/eap_peer/eap_mschapv2.so EAPDYN += src/eap_peer/mschapv2.so else L_CFLAGS += -DEAP_MSCHAPv2 OBJS += src/eap_peer/eap_mschapv2.c OBJS += src/eap_peer/mschapv2.c OBJS_h += src/eap_server/eap_server_mschapv2.c endif MS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_GTC # EAP-GTC ifeq ($(CONFIG_EAP_GTC), dyn) L_CFLAGS += -DEAP_GTC_DYNAMIC EAPDYN += src/eap_peer/eap_gtc.so else L_CFLAGS += -DEAP_GTC OBJS += src/eap_peer/eap_gtc.c OBJS_h += src/eap_server/eap_server_gtc.c endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_OTP # EAP-OTP ifeq ($(CONFIG_EAP_OTP), dyn) L_CFLAGS += -DEAP_OTP_DYNAMIC EAPDYN += src/eap_peer/eap_otp.so else L_CFLAGS += -DEAP_OTP OBJS += src/eap_peer/eap_otp.c endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_SIM # EAP-SIM ifeq ($(CONFIG_EAP_SIM), dyn) L_CFLAGS += -DEAP_SIM_DYNAMIC EAPDYN += src/eap_peer/eap_sim.so else L_CFLAGS += -DEAP_SIM OBJS += src/eap_peer/eap_sim.c OBJS_h += src/eap_server/eap_server_sim.c endif CONFIG_IEEE8021X_EAPOL=y CONFIG_EAP_SIM_COMMON=y NEED_AES_CBC=y endif ifdef CONFIG_EAP_LEAP # EAP-LEAP ifeq ($(CONFIG_EAP_LEAP), dyn) L_CFLAGS += -DEAP_LEAP_DYNAMIC EAPDYN += src/eap_peer/eap_leap.so else L_CFLAGS += -DEAP_LEAP OBJS += src/eap_peer/eap_leap.c endif MS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_PSK # EAP-PSK ifeq ($(CONFIG_EAP_PSK), dyn) L_CFLAGS += -DEAP_PSK_DYNAMIC EAPDYN += src/eap_peer/eap_psk.so else L_CFLAGS += -DEAP_PSK OBJS += src/eap_peer/eap_psk.c src/eap_common/eap_psk_common.c OBJS_h += src/eap_server/eap_server_psk.c endif CONFIG_IEEE8021X_EAPOL=y NEED_AES=y NEED_AES_OMAC1=y NEED_AES_ENCBLOCK=y NEED_AES_EAX=y endif ifdef CONFIG_EAP_AKA # EAP-AKA ifeq ($(CONFIG_EAP_AKA), dyn) L_CFLAGS += -DEAP_AKA_DYNAMIC EAPDYN += src/eap_peer/eap_aka.so else L_CFLAGS += -DEAP_AKA OBJS += src/eap_peer/eap_aka.c OBJS_h += src/eap_server/eap_server_aka.c endif CONFIG_IEEE8021X_EAPOL=y CONFIG_EAP_SIM_COMMON=y NEED_AES_CBC=y endif ifdef CONFIG_EAP_PROXY L_CFLAGS += -DCONFIG_EAP_PROXY OBJS += src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).c include $(LOCAL_PATH)/eap_proxy_$(CONFIG_EAP_PROXY).mk CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_AKA_PRIME # EAP-AKA' ifeq ($(CONFIG_EAP_AKA_PRIME), dyn) L_CFLAGS += -DEAP_AKA_PRIME_DYNAMIC else L_CFLAGS += -DEAP_AKA_PRIME endif NEED_SHA256=y endif ifdef CONFIG_EAP_SIM_COMMON OBJS += src/eap_common/eap_sim_common.c OBJS_h += src/eap_server/eap_sim_db.c NEED_AES=y NEED_FIPS186_2_PRF=y endif ifdef CONFIG_EAP_FAST # EAP-FAST ifeq ($(CONFIG_EAP_FAST), dyn) L_CFLAGS += -DEAP_FAST_DYNAMIC EAPDYN += src/eap_peer/eap_fast.so EAPDYN += src/eap_common/eap_fast_common.c else L_CFLAGS += -DEAP_FAST OBJS += src/eap_peer/eap_fast.c src/eap_peer/eap_fast_pac.c OBJS += src/eap_common/eap_fast_common.c OBJS_h += src/eap_server/eap_server_fast.c endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y NEED_T_PRF=y endif ifdef CONFIG_EAP_PAX # EAP-PAX ifeq ($(CONFIG_EAP_PAX), dyn) L_CFLAGS += -DEAP_PAX_DYNAMIC EAPDYN += src/eap_peer/eap_pax.so else L_CFLAGS += -DEAP_PAX OBJS += src/eap_peer/eap_pax.c src/eap_common/eap_pax_common.c OBJS_h += src/eap_server/eap_server_pax.c endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_SAKE # EAP-SAKE ifeq ($(CONFIG_EAP_SAKE), dyn) L_CFLAGS += -DEAP_SAKE_DYNAMIC EAPDYN += src/eap_peer/eap_sake.so else L_CFLAGS += -DEAP_SAKE OBJS += src/eap_peer/eap_sake.c src/eap_common/eap_sake_common.c OBJS_h += src/eap_server/eap_server_sake.c endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_GPSK # EAP-GPSK ifeq ($(CONFIG_EAP_GPSK), dyn) L_CFLAGS += -DEAP_GPSK_DYNAMIC EAPDYN += src/eap_peer/eap_gpsk.so else L_CFLAGS += -DEAP_GPSK OBJS += src/eap_peer/eap_gpsk.c src/eap_common/eap_gpsk_common.c OBJS_h += src/eap_server/eap_server_gpsk.c endif CONFIG_IEEE8021X_EAPOL=y ifdef CONFIG_EAP_GPSK_SHA256 L_CFLAGS += -DEAP_GPSK_SHA256 endif NEED_SHA256=y NEED_AES_OMAC1=y endif ifdef CONFIG_EAP_PWD L_CFLAGS += -DEAP_PWD OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c OBJS_h += src/eap_server/eap_server_pwd.c CONFIG_IEEE8021X_EAPOL=y NEED_SHA256=y endif ifdef CONFIG_EAP_EKE # EAP-EKE ifeq ($(CONFIG_EAP_EKE), dyn) L_CFLAGS += -DEAP_EKE_DYNAMIC EAPDYN += src/eap_peer/eap_eke.so else L_CFLAGS += -DEAP_EKE OBJS += src/eap_peer/eap_eke.c src/eap_common/eap_eke_common.c OBJS_h += src/eap_server/eap_server_eke.c endif CONFIG_IEEE8021X_EAPOL=y NEED_DH_GROUPS=y NEED_DH_GROUPS_ALL=y NEED_SHA256=y endif ifdef CONFIG_WPS # EAP-WSC L_CFLAGS += -DCONFIG_WPS -DEAP_WSC OBJS += wps_supplicant.c OBJS += src/utils/uuid.c OBJS += src/eap_peer/eap_wsc.c src/eap_common/eap_wsc_common.c OBJS += src/wps/wps.c OBJS += src/wps/wps_common.c OBJS += src/wps/wps_attr_parse.c OBJS += src/wps/wps_attr_build.c OBJS += src/wps/wps_attr_process.c OBJS += src/wps/wps_dev_attr.c OBJS += src/wps/wps_enrollee.c OBJS += src/wps/wps_registrar.c OBJS_h += src/eap_server/eap_server_wsc.c CONFIG_IEEE8021X_EAPOL=y NEED_DH_GROUPS=y NEED_SHA256=y NEED_BASE64=y NEED_80211_COMMON=y NEED_AES_CBC=y NEED_MODEXP=y ifdef CONFIG_WPS_NFC L_CFLAGS += -DCONFIG_WPS_NFC OBJS += src/wps/ndef.c NEED_WPS_OOB=y endif ifdef NEED_WPS_OOB L_CFLAGS += -DCONFIG_WPS_OOB endif ifdef CONFIG_WPS_ER CONFIG_WPS_UPNP=y L_CFLAGS += -DCONFIG_WPS_ER OBJS += src/wps/wps_er.c OBJS += src/wps/wps_er_ssdp.c endif ifdef CONFIG_WPS_UPNP L_CFLAGS += -DCONFIG_WPS_UPNP OBJS += src/wps/wps_upnp.c OBJS += src/wps/wps_upnp_ssdp.c OBJS += src/wps/wps_upnp_web.c OBJS += src/wps/wps_upnp_event.c OBJS += src/wps/wps_upnp_ap.c OBJS += src/wps/upnp_xml.c OBJS += src/wps/httpread.c OBJS += src/wps/http_client.c OBJS += src/wps/http_server.c endif ifdef CONFIG_WPS_STRICT L_CFLAGS += -DCONFIG_WPS_STRICT OBJS += src/wps/wps_validate.c endif ifdef CONFIG_WPS_TESTING L_CFLAGS += -DCONFIG_WPS_TESTING endif ifdef CONFIG_WPS_REG_DISABLE_OPEN L_CFLAGS += -DCONFIG_WPS_REG_DISABLE_OPEN endif endif ifdef CONFIG_EAP_IKEV2 # EAP-IKEv2 ifeq ($(CONFIG_EAP_IKEV2), dyn) L_CFLAGS += -DEAP_IKEV2_DYNAMIC EAPDYN += src/eap_peer/eap_ikev2.so src/eap_peer/ikev2.c EAPDYN += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c else L_CFLAGS += -DEAP_IKEV2 OBJS += src/eap_peer/eap_ikev2.c src/eap_peer/ikev2.c OBJS += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c OBJS_h += src/eap_server/eap_server_ikev2.c OBJS_h += src/eap_server/ikev2.c endif CONFIG_IEEE8021X_EAPOL=y NEED_DH_GROUPS=y NEED_DH_GROUPS_ALL=y NEED_MODEXP=y NEED_CIPHER=y endif ifdef CONFIG_EAP_VENDOR_TEST ifeq ($(CONFIG_EAP_VENDOR_TEST), dyn) L_CFLAGS += -DEAP_VENDOR_TEST_DYNAMIC EAPDYN += src/eap_peer/eap_vendor_test.so else L_CFLAGS += -DEAP_VENDOR_TEST OBJS += src/eap_peer/eap_vendor_test.c OBJS_h += src/eap_server/eap_server_vendor_test.c endif CONFIG_IEEE8021X_EAPOL=y endif ifdef CONFIG_EAP_TNC # EAP-TNC L_CFLAGS += -DEAP_TNC OBJS += src/eap_peer/eap_tnc.c OBJS += src/eap_peer/tncc.c OBJS_h += src/eap_server/eap_server_tnc.c OBJS_h += src/eap_server/tncs.c NEED_BASE64=y ifndef CONFIG_NATIVE_WINDOWS ifndef CONFIG_DRIVER_BSD LIBS += -ldl endif endif endif ifdef CONFIG_IEEE8021X_EAPOL # IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication) L_CFLAGS += -DIEEE8021X_EAPOL OBJS += src/eapol_supp/eapol_supp_sm.c OBJS += src/eap_peer/eap.c src/eap_peer/eap_methods.c NEED_EAP_COMMON=y ifdef CONFIG_DYNAMIC_EAP_METHODS L_CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS LIBS += -ldl -rdynamic endif endif ifdef CONFIG_AP NEED_80211_COMMON=y NEED_EAP_COMMON=y NEED_RSN_AUTHENTICATOR=y L_CFLAGS += -DCONFIG_AP OBJS += ap.c L_CFLAGS += -DCONFIG_NO_RADIUS L_CFLAGS += -DCONFIG_NO_ACCOUNTING L_CFLAGS += -DCONFIG_NO_VLAN OBJS += src/ap/hostapd.c OBJS += src/ap/wpa_auth_glue.c OBJS += src/ap/utils.c OBJS += src/ap/authsrv.c OBJS += src/ap/ap_config.c OBJS += src/utils/ip_addr.c OBJS += src/ap/sta_info.c OBJS += src/ap/tkip_countermeasures.c OBJS += src/ap/ap_mlme.c OBJS += src/ap/ieee802_1x.c OBJS += src/eapol_auth/eapol_auth_sm.c OBJS += src/ap/ieee802_11_auth.c OBJS += src/ap/ieee802_11_shared.c OBJS += src/ap/drv_callbacks.c OBJS += src/ap/ap_drv_ops.c OBJS += src/ap/beacon.c OBJS += src/ap/eap_user_db.c ifdef CONFIG_IEEE80211N OBJS += src/ap/ieee802_11_ht.c ifdef CONFIG_IEEE80211AC OBJS += src/ap/ieee802_11_vht.c endif endif ifdef CONFIG_WNM OBJS += src/ap/wnm_ap.c endif ifdef CONFIG_CTRL_IFACE OBJS += src/ap/ctrl_iface_ap.c endif L_CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY OBJS += src/eap_server/eap_server.c OBJS += src/eap_server/eap_server_identity.c OBJS += src/eap_server/eap_server_methods.c ifdef CONFIG_IEEE80211N L_CFLAGS += -DCONFIG_IEEE80211N ifdef CONFIG_IEEE80211AC L_CFLAGS += -DCONFIG_IEEE80211AC endif endif ifdef NEED_AP_MLME OBJS += src/ap/wmm.c OBJS += src/ap/ap_list.c OBJS += src/ap/ieee802_11.c OBJS += src/ap/hw_features.c OBJS += src/ap/dfs.c L_CFLAGS += -DNEED_AP_MLME endif ifdef CONFIG_WPS L_CFLAGS += -DEAP_SERVER_WSC OBJS += src/ap/wps_hostapd.c OBJS += src/eap_server/eap_server_wsc.c endif ifdef CONFIG_INTERWORKING OBJS += src/ap/gas_serv.c endif ifdef CONFIG_HS20 OBJS += src/ap/hs20.c endif endif ifdef NEED_RSN_AUTHENTICATOR L_CFLAGS += -DCONFIG_NO_RADIUS NEED_AES_WRAP=y OBJS += src/ap/wpa_auth.c OBJS += src/ap/wpa_auth_ie.c OBJS += src/ap/pmksa_cache_auth.c ifdef CONFIG_IEEE80211R OBJS += src/ap/wpa_auth_ft.c endif ifdef CONFIG_PEERKEY OBJS += src/ap/peerkey_auth.c endif endif ifdef CONFIG_EAP_SERVER L_CFLAGS += -DEAP_SERVER OBJS_h += src/eap_server/eap_server.c OBJS_h += src/eap_server/eap_server_identity.c OBJS_h += src/eap_server/eap_server_methods.c endif ifdef CONFIG_RADIUS_CLIENT OBJS_h += src/utils/ip_addr.c OBJS_h += src/radius/radius.c OBJS_h += src/radius/radius_client.c endif ifdef CONFIG_AUTHENTICATOR OBJS_h += src/eapol_auth/eapol_auth_sm.c OBJS_h += src/ap/ieee802_1x.c endif ifdef CONFIG_WPA_AUTHENTICATOR OBJS_h += src/ap/wpa_auth.c OBJS_h += src/ap/wpa_auth_ie.c OBJS_h += src/ap/pmksa_cache_auth.c ifdef CONFIG_IEEE80211R OBJS_h += src/ap/wpa_auth_ft.c endif ifdef CONFIG_PEERKEY OBJS_h += src/ap/peerkey_auth.c endif endif ifdef CONFIG_PCSC # PC/SC interface for smartcards (USIM, GSM SIM) L_CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC OBJS += src/utils/pcsc_funcs.c # -lpthread may not be needed depending on how pcsc-lite was configured ifdef CONFIG_NATIVE_WINDOWS #Once MinGW gets support for WinScard, -lwinscard could be used instead of the #dynamic symbol loading that is now used in pcsc_funcs.c #LIBS += -lwinscard else LIBS += -lpcsclite -lpthread endif endif ifdef CONFIG_SIM_SIMULATOR L_CFLAGS += -DCONFIG_SIM_SIMULATOR NEED_MILENAGE=y endif ifdef CONFIG_USIM_SIMULATOR L_CFLAGS += -DCONFIG_USIM_SIMULATOR NEED_MILENAGE=y endif ifdef NEED_MILENAGE OBJS += src/crypto/milenage.c NEED_AES_ENCBLOCK=y endif ifdef CONFIG_PKCS12 L_CFLAGS += -DPKCS12_FUNCS endif ifdef CONFIG_SMARTCARD L_CFLAGS += -DCONFIG_SMARTCARD endif ifdef MS_FUNCS OBJS += src/crypto/ms_funcs.c NEED_DES=y NEED_MD4=y endif ifdef CHAP OBJS += src/eap_common/chap.c endif ifdef TLS_FUNCS NEED_DES=y # Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST) OBJS += src/eap_peer/eap_tls_common.c OBJS_h += src/eap_server/eap_server_tls_common.c ifndef CONFIG_FIPS NEED_TLS_PRF=y NEED_SHA1=y NEED_MD5=y endif endif ifndef CONFIG_TLS CONFIG_TLS=openssl endif ifdef CONFIG_TLSV11 L_CFLAGS += -DCONFIG_TLSV11 endif ifdef CONFIG_TLSV12 L_CFLAGS += -DCONFIG_TLSV12 NEED_SHA256=y endif ifeq ($(CONFIG_TLS), openssl) ifdef TLS_FUNCS L_CFLAGS += -DEAP_TLS_OPENSSL OBJS += src/crypto/tls_openssl.c LIBS += -lssl endif OBJS += src/crypto/crypto_openssl.c OBJS_p += src/crypto/crypto_openssl.c ifdef NEED_FIPS186_2_PRF OBJS += src/crypto/fips_prf_openssl.c endif LIBS += -lcrypto LIBS_p += -lcrypto ifdef CONFIG_TLS_ADD_DL LIBS += -ldl LIBS_p += -ldl endif endif ifeq ($(CONFIG_TLS), gnutls) ifdef TLS_FUNCS OBJS += src/crypto/tls_gnutls.c LIBS += -lgnutls -lgpg-error endif OBJS += src/crypto/crypto_gnutls.c OBJS_p += src/crypto/crypto_gnutls.c ifdef NEED_FIPS186_2_PRF OBJS += src/crypto/fips_prf_internal.c OBJS += src/crypto/sha1-internal.c endif LIBS += -lgcrypt LIBS_p += -lgcrypt CONFIG_INTERNAL_SHA256=y CONFIG_INTERNAL_RC4=y CONFIG_INTERNAL_DH_GROUP5=y endif ifeq ($(CONFIG_TLS), schannel) ifdef TLS_FUNCS OBJS += src/crypto/tls_schannel.c endif OBJS += src/crypto/crypto_cryptoapi.c OBJS_p += src/crypto/crypto_cryptoapi.c ifdef NEED_FIPS186_2_PRF OBJS += src/crypto/fips_prf_internal.c OBJS += src/crypto/sha1-internal.c endif CONFIG_INTERNAL_SHA256=y CONFIG_INTERNAL_RC4=y CONFIG_INTERNAL_DH_GROUP5=y endif ifeq ($(CONFIG_TLS), nss) ifdef TLS_FUNCS OBJS += src/crypto/tls_nss.c LIBS += -lssl3 endif OBJS += src/crypto/crypto_nss.c OBJS_p += src/crypto/crypto_nss.c ifdef NEED_FIPS186_2_PRF OBJS += src/crypto/fips_prf_internal.c OBJS += src/crypto/sha1-internal.c endif LIBS += -lnss3 LIBS_p += -lnss3 CONFIG_INTERNAL_MD4=y CONFIG_INTERNAL_DH_GROUP5=y endif ifeq ($(CONFIG_TLS), internal) ifndef CONFIG_CRYPTO CONFIG_CRYPTO=internal endif ifdef TLS_FUNCS OBJS += src/crypto/crypto_internal-rsa.c OBJS += src/crypto/tls_internal.c OBJS += src/tls/tlsv1_common.c OBJS += src/tls/tlsv1_record.c OBJS += src/tls/tlsv1_cred.c OBJS += src/tls/tlsv1_client.c OBJS += src/tls/tlsv1_client_write.c OBJS += src/tls/tlsv1_client_read.c OBJS += src/tls/asn1.c OBJS += src/tls/rsa.c OBJS += src/tls/x509v3.c OBJS += src/tls/pkcs1.c OBJS += src/tls/pkcs5.c OBJS += src/tls/pkcs8.c NEED_SHA256=y NEED_BASE64=y NEED_TLS_PRF=y ifdef CONFIG_TLSV12 NEED_TLS_PRF_SHA256=y endif NEED_MODEXP=y NEED_CIPHER=y L_CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT endif ifdef NEED_CIPHER NEED_DES=y OBJS += src/crypto/crypto_internal-cipher.c endif ifdef NEED_MODEXP OBJS += src/crypto/crypto_internal-modexp.c OBJS += src/tls/bignum.c endif ifeq ($(CONFIG_CRYPTO), libtomcrypt) OBJS += src/crypto/crypto_libtomcrypt.c OBJS_p += src/crypto/crypto_libtomcrypt.c LIBS += -ltomcrypt -ltfm LIBS_p += -ltomcrypt -ltfm CONFIG_INTERNAL_SHA256=y CONFIG_INTERNAL_RC4=y CONFIG_INTERNAL_DH_GROUP5=y endif ifeq ($(CONFIG_CRYPTO), internal) OBJS += src/crypto/crypto_internal.c OBJS_p += src/crypto/crypto_internal.c NEED_AES_ENC=y L_CFLAGS += -DCONFIG_CRYPTO_INTERNAL ifdef CONFIG_INTERNAL_LIBTOMMATH L_CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST L_CFLAGS += -DLTM_FAST endif else LIBS += -ltommath LIBS_p += -ltommath endif CONFIG_INTERNAL_AES=y CONFIG_INTERNAL_DES=y CONFIG_INTERNAL_SHA1=y CONFIG_INTERNAL_MD4=y CONFIG_INTERNAL_MD5=y CONFIG_INTERNAL_SHA256=y CONFIG_INTERNAL_RC4=y CONFIG_INTERNAL_DH_GROUP5=y endif ifeq ($(CONFIG_CRYPTO), cryptoapi) OBJS += src/crypto/crypto_cryptoapi.c OBJS_p += src/crypto/crypto_cryptoapi.c L_CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI CONFIG_INTERNAL_SHA256=y CONFIG_INTERNAL_RC4=y endif endif ifeq ($(CONFIG_TLS), none) ifdef TLS_FUNCS OBJS += src/crypto/tls_none.c L_CFLAGS += -DEAP_TLS_NONE CONFIG_INTERNAL_AES=y CONFIG_INTERNAL_SHA1=y CONFIG_INTERNAL_MD5=y endif OBJS += src/crypto/crypto_none.c OBJS_p += src/crypto/crypto_none.c CONFIG_INTERNAL_SHA256=y CONFIG_INTERNAL_RC4=y endif ifdef TLS_FUNCS ifdef CONFIG_SMARTCARD ifndef CONFIG_NATIVE_WINDOWS ifneq ($(CONFIG_L2_PACKET), freebsd) LIBS += -ldl endif endif endif endif ifndef TLS_FUNCS OBJS += src/crypto/tls_none.c ifeq ($(CONFIG_TLS), internal) CONFIG_INTERNAL_AES=y CONFIG_INTERNAL_SHA1=y CONFIG_INTERNAL_MD5=y CONFIG_INTERNAL_RC4=y endif endif AESOBJS = # none so far (see below) ifdef CONFIG_INTERNAL_AES AESOBJS += src/crypto/aes-internal.c src/crypto/aes-internal-dec.c endif AESOBJS += src/crypto/aes-unwrap.c ifdef NEED_AES_EAX AESOBJS += src/crypto/aes-eax.c NEED_AES_CTR=y endif ifdef NEED_AES_CTR AESOBJS += src/crypto/aes-ctr.c endif ifdef NEED_AES_ENCBLOCK AESOBJS += src/crypto/aes-encblock.c endif ifdef NEED_AES_OMAC1 NEED_AES_ENC=y ifdef CONFIG_OPENSSL_CMAC L_CFLAGS += -DCONFIG_OPENSSL_CMAC else AESOBJS += src/crypto/aes-omac1.c endif endif ifdef NEED_AES_WRAP NEED_AES_ENC=y AESOBJS += src/crypto/aes-wrap.c endif ifdef NEED_AES_CBC NEED_AES_ENC=y AESOBJS += src/crypto/aes-cbc.c endif ifdef NEED_AES_ENC ifdef CONFIG_INTERNAL_AES AESOBJS += src/crypto/aes-internal-enc.c endif endif ifdef NEED_AES OBJS += $(AESOBJS) endif SHA1OBJS = ifdef NEED_SHA1 ifneq ($(CONFIG_TLS), openssl) SHA1OBJS += src/crypto/sha1.c endif SHA1OBJS += src/crypto/sha1-prf.c ifdef CONFIG_INTERNAL_SHA1 SHA1OBJS += src/crypto/sha1-internal.c ifdef NEED_FIPS186_2_PRF SHA1OBJS += src/crypto/fips_prf_internal.c endif endif ifdef CONFIG_NO_WPA_PASSPHRASE L_CFLAGS += -DCONFIG_NO_PBKDF2 else ifneq ($(CONFIG_TLS), openssl) SHA1OBJS += src/crypto/sha1-pbkdf2.c endif endif ifdef NEED_T_PRF SHA1OBJS += src/crypto/sha1-tprf.c endif ifdef NEED_TLS_PRF SHA1OBJS += src/crypto/sha1-tlsprf.c endif endif MD5OBJS = ifndef CONFIG_FIPS MD5OBJS += src/crypto/md5.c endif ifdef NEED_MD5 ifdef CONFIG_INTERNAL_MD5 MD5OBJS += src/crypto/md5-internal.c endif OBJS += $(MD5OBJS) OBJS_p += $(MD5OBJS) endif ifdef NEED_MD4 ifdef CONFIG_INTERNAL_MD4 OBJS += src/crypto/md4-internal.c endif endif DESOBJS = # none needed when not internal ifdef NEED_DES ifdef CONFIG_INTERNAL_DES DESOBJS += src/crypto/des-internal.c endif endif ifdef NEED_RC4 ifdef CONFIG_INTERNAL_RC4 OBJS += src/crypto/rc4.c endif endif SHA256OBJS = # none by default ifdef NEED_SHA256 L_CFLAGS += -DCONFIG_SHA256 ifneq ($(CONFIG_TLS), openssl) SHA256OBJS += src/crypto/sha256.c endif SHA256OBJS += src/crypto/sha256-prf.c ifdef CONFIG_INTERNAL_SHA256 SHA256OBJS += src/crypto/sha256-internal.c endif ifdef NEED_TLS_PRF_SHA256 SHA256OBJS += src/crypto/sha256-tlsprf.c endif OBJS += $(SHA256OBJS) endif ifdef NEED_DH_GROUPS OBJS += src/crypto/dh_groups.c endif ifdef NEED_DH_GROUPS_ALL L_CFLAGS += -DALL_DH_GROUPS endif ifdef CONFIG_INTERNAL_DH_GROUP5 ifdef NEED_DH_GROUPS OBJS += src/crypto/dh_group5.c endif endif ifdef NEED_ECC L_CFLAGS += -DCONFIG_ECC endif ifdef CONFIG_NO_RANDOM_POOL L_CFLAGS += -DCONFIG_NO_RANDOM_POOL else OBJS += src/crypto/random.c endif ifdef CONFIG_CTRL_IFACE ifeq ($(CONFIG_CTRL_IFACE), y) ifdef CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE=named_pipe else CONFIG_CTRL_IFACE=unix endif endif L_CFLAGS += -DCONFIG_CTRL_IFACE ifeq ($(CONFIG_CTRL_IFACE), unix) L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX endif ifeq ($(CONFIG_CTRL_IFACE), udp) L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP endif ifeq ($(CONFIG_CTRL_IFACE), named_pipe) L_CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE endif ifeq ($(CONFIG_CTRL_IFACE), udp-remote) CONFIG_CTRL_IFACE=udp L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE endif OBJS += ctrl_iface.c ctrl_iface_$(CONFIG_CTRL_IFACE).c endif ifdef CONFIG_CTRL_IFACE_DBUS DBUS=y DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE DBUS_OBJS += dbus/dbus_old.c dbus/dbus_old_handlers.c ifdef CONFIG_WPS DBUS_OBJS += dbus/dbus_old_handlers_wps.c endif DBUS_OBJS += dbus/dbus_dict_helpers.c ifndef DBUS_LIBS DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1) endif ifndef DBUS_INCLUDE DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1) endif DBUS_CFLAGS += $(DBUS_INCLUDE) endif ifdef CONFIG_CTRL_IFACE_DBUS_NEW DBUS=y DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW DBUS_OBJS ?= dbus/dbus_dict_helpers.c DBUS_OBJS += dbus/dbus_new_helpers.c DBUS_OBJS += dbus/dbus_new.c dbus/dbus_new_handlers.c ifdef CONFIG_WPS DBUS_OBJS += dbus/dbus_new_handlers_wps.c endif ifdef CONFIG_P2P DBUS_OBJS += dbus/dbus_new_handlers_p2p.c endif ifndef DBUS_LIBS DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1) endif ifndef DBUS_INCLUDE DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1) endif ifdef CONFIG_CTRL_IFACE_DBUS_INTRO DBUS_OBJS += dbus/dbus_new_introspect.c DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO endif DBUS_CFLAGS += $(DBUS_INCLUDE) endif ifdef DBUS DBUS_CFLAGS += -DCONFIG_DBUS DBUS_OBJS += dbus/dbus_common.c endif OBJS += $(DBUS_OBJS) L_CFLAGS += $(DBUS_CFLAGS) LIBS += $(DBUS_LIBS) ifdef CONFIG_READLINE OBJS_c += src/utils/edit_readline.c LIBS_c += -lncurses -lreadline else ifdef CONFIG_WPA_CLI_EDIT OBJS_c += src/utils/edit.c else OBJS_c += src/utils/edit_simple.c endif endif ifdef CONFIG_NATIVE_WINDOWS L_CFLAGS += -DCONFIG_NATIVE_WINDOWS LIBS += -lws2_32 -lgdi32 -lcrypt32 LIBS_c += -lws2_32 LIBS_p += -lws2_32 -lgdi32 ifeq ($(CONFIG_CRYPTO), cryptoapi) LIBS_p += -lcrypt32 endif endif ifdef CONFIG_NO_STDOUT_DEBUG L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG ifndef CONFIG_CTRL_IFACE L_CFLAGS += -DCONFIG_NO_WPA_MSG endif endif ifdef CONFIG_ANDROID_LOG L_CFLAGS += -DCONFIG_ANDROID_LOG endif ifdef CONFIG_IPV6 # for eapol_test only L_CFLAGS += -DCONFIG_IPV6 endif ifdef NEED_BASE64 OBJS += src/utils/base64.c endif ifdef NEED_SME NEED_80211_COMMON=y OBJS += sme.c L_CFLAGS += -DCONFIG_SME endif ifdef NEED_80211_COMMON OBJS += src/common/ieee802_11_common.c endif ifdef NEED_EAP_COMMON OBJS += src/eap_common/eap_common.c endif ifndef CONFIG_MAIN CONFIG_MAIN=main endif ifdef CONFIG_DEBUG_SYSLOG L_CFLAGS += -DCONFIG_DEBUG_SYSLOG ifdef CONFIG_DEBUG_SYSLOG_FACILITY L_CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)" endif endif ifdef CONFIG_DEBUG_LINUX_TRACING L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING endif ifdef CONFIG_DEBUG_FILE L_CFLAGS += -DCONFIG_DEBUG_FILE endif ifdef CONFIG_DELAYED_MIC_ERROR_REPORT L_CFLAGS += -DCONFIG_DELAYED_MIC_ERROR_REPORT endif ifdef CONFIG_FIPS L_CFLAGS += -DCONFIG_FIPS endif OBJS += $(SHA1OBJS) $(DESOBJS) OBJS_p += $(SHA1OBJS) OBJS_p += $(SHA256OBJS) ifdef CONFIG_BGSCAN_SIMPLE L_CFLAGS += -DCONFIG_BGSCAN_SIMPLE OBJS += bgscan_simple.c NEED_BGSCAN=y endif ifdef CONFIG_BGSCAN_LEARN L_CFLAGS += -DCONFIG_BGSCAN_LEARN OBJS += bgscan_learn.c NEED_BGSCAN=y endif ifdef NEED_BGSCAN L_CFLAGS += -DCONFIG_BGSCAN OBJS += bgscan.c endif ifdef CONFIG_AUTOSCAN_EXPONENTIAL L_CFLAGS += -DCONFIG_AUTOSCAN_EXPONENTIAL OBJS += autoscan_exponential.c NEED_AUTOSCAN=y endif ifdef CONFIG_AUTOSCAN_PERIODIC L_CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC OBJS += autoscan_periodic.c NEED_AUTOSCAN=y endif ifdef NEED_AUTOSCAN L_CFLAGS += -DCONFIG_AUTOSCAN OBJS += autoscan.c endif ifdef CONFIG_EXT_PASSWORD_TEST OBJS += src/utils/ext_password_test.c L_CFLAGS += -DCONFIG_EXT_PASSWORD_TEST NEED_EXT_PASSWORD=y endif ifdef NEED_EXT_PASSWORD OBJS += src/utils/ext_password.c L_CFLAGS += -DCONFIG_EXT_PASSWORD endif ifdef NEED_GAS OBJS += src/common/gas.c OBJS += gas_query.c L_CFLAGS += -DCONFIG_GAS NEED_OFFCHANNEL=y endif ifdef NEED_OFFCHANNEL OBJS += offchannel.c L_CFLAGS += -DCONFIG_OFFCHANNEL endif OBJS += src/drivers/driver_common.c OBJS_wpa_rm := ctrl_iface.c ctrl_iface_unix.c OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.c ifdef CONFIG_AUTHENTICATOR OBJS_wpa += tests/link_test.c endif OBJS_wpa += $(OBJS_l2) OBJS += wpa_supplicant.c events.c blacklist.c wpas_glue.c scan.c OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.c OBJS_t += src/radius/radius_client.c OBJS_t += src/radius/radius.c ifndef CONFIG_AP OBJS_t += src/utils/ip_addr.c endif OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.c OBJS += $(CONFIG_MAIN).c ifdef CONFIG_PRIVSEP OBJS_priv += $(OBJS_d) src/drivers/drivers.c OBJS_priv += $(OBJS_l2) OBJS_priv += src/utils/os_$(CONFIG_OS).c OBJS_priv += src/utils/$(CONFIG_ELOOP).c OBJS_priv += src/utils/common.c OBJS_priv += src/utils/wpa_debug.c OBJS_priv += src/utils/wpabuf.c OBJS_priv += wpa_priv.c ifdef CONFIG_DRIVER_NL80211 OBJS_priv += src/common/ieee802_11_common.c endif ifdef CONFIG_DRIVER_TEST OBJS_priv += $(SHA1OBJS) OBJS_priv += $(MD5OBJS) ifeq ($(CONFIG_TLS), openssl) OBJS_priv += src/crypto/crypto_openssl.c endif ifeq ($(CONFIG_TLS), gnutls) OBJS_priv += src/crypto/crypto_gnutls.c endif ifeq ($(CONFIG_TLS), nss) OBJS_priv += src/crypto/crypto_nss.c endif ifeq ($(CONFIG_TLS), internal) ifeq ($(CONFIG_CRYPTO), libtomcrypt) OBJS_priv += src/crypto/crypto_libtomcrypt.c else OBJS_priv += src/crypto/crypto_internal.c endif endif endif # CONFIG_DRIVER_TEST OBJS += src/l2_packet/l2_packet_privsep.c OBJS += src/drivers/driver_privsep.c EXTRA_progs += wpa_priv else OBJS += $(OBJS_d) src/drivers/drivers.c OBJS += $(OBJS_l2) endif ifdef CONFIG_NDIS_EVENTS_INTEGRATED L_CFLAGS += -DCONFIG_NDIS_EVENTS_INTEGRATED OBJS += src/drivers/ndis_events.c EXTRALIBS += -loleaut32 -lole32 -luuid ifdef PLATFORMSDKLIB EXTRALIBS += $(PLATFORMSDKLIB)/WbemUuid.Lib else EXTRALIBS += WbemUuid.Lib endif endif ifndef LDO LDO=$(CC) endif ######################## include $(CLEAR_VARS) LOCAL_MODULE := wpa_cli LOCAL_MODULE_TAGS := debug LOCAL_SHARED_LIBRARIES := libc libcutils liblog LOCAL_CFLAGS := $(L_CFLAGS) LOCAL_SRC_FILES := $(OBJS_c) LOCAL_C_INCLUDES := $(INCLUDES) include $(BUILD_EXECUTABLE) ######################## include $(CLEAR_VARS) LOCAL_MODULE := wpa_supplicant ifdef CONFIG_DRIVER_CUSTOM LOCAL_STATIC_LIBRARIES := libCustomWifi endif ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),) LOCAL_STATIC_LIBRARIES += $(BOARD_WPA_SUPPLICANT_PRIVATE_LIB) endif LOCAL_SHARED_LIBRARIES := libc libcutils liblog ifdef CONFIG_EAP_PROXY LOCAL_STATIC_LIBRARIES += $(LIB_STATIC_EAP_PROXY) LOCAL_SHARED_LIBRARIES += $(LIB_SHARED_EAP_PROXY) endif ifeq ($(CONFIG_TLS), openssl) LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore_binder endif ifdef CONFIG_DRIVER_NL80211 ifneq ($(wildcard external/libnl),) LOCAL_SHARED_LIBRARIES += libnl else LOCAL_STATIC_LIBRARIES += libnl_2 endif endif LOCAL_CFLAGS := $(L_CFLAGS) LOCAL_SRC_FILES := $(OBJS) LOCAL_C_INCLUDES := $(INCLUDES) include $(BUILD_EXECUTABLE) ######################## # #include $(CLEAR_VARS) #LOCAL_MODULE := eapol_test #ifdef CONFIG_DRIVER_CUSTOM #LOCAL_STATIC_LIBRARIES := libCustomWifi #endif #LOCAL_SHARED_LIBRARIES := libc libcrypto libssl #LOCAL_CFLAGS := $(L_CFLAGS) #LOCAL_SRC_FILES := $(OBJS_t) #LOCAL_C_INCLUDES := $(INCLUDES) #include $(BUILD_EXECUTABLE) # ######################## # #local_target_dir := $(TARGET_OUT)/etc/wifi # #include $(CLEAR_VARS) #LOCAL_MODULE := wpa_supplicant.conf #LOCAL_MODULE_CLASS := ETC #LOCAL_MODULE_PATH := $(local_target_dir) #LOCAL_SRC_FILES := $(LOCAL_MODULE) #include $(BUILD_PREBUILT) # ######################## include $(CLEAR_VARS) LOCAL_MODULE = libwpa_client LOCAL_CFLAGS = $(L_CFLAGS) LOCAL_SRC_FILES = src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c LOCAL_C_INCLUDES = $(INCLUDES) LOCAL_SHARED_LIBRARIES := libcutils liblog LOCAL_COPY_HEADERS_TO := libwpa_client LOCAL_COPY_HEADERS := src/common/wpa_ctrl.h LOCAL_COPY_HEADERS += src/common/qca-vendor.h include $(BUILD_SHARED_LIBRARY) wpa_supplicant-2.2/wpa_supplicant/nfc_pw_token.c0000664000175000017500000000332212343617166020070 0ustar jmjm/* * nfc_pw_token - Tool for building NFC password tokens for WPS * Copyright (c) 2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include "utils/common.h" #include "crypto/random.h" #include "wpa_supplicant_i.h" #include "config.h" #include "wps_supplicant.h" static void print_bin(const char *title, const struct wpabuf *buf) { size_t i, len; const u8 *pos; if (buf == NULL) return; printf("%s=", title); pos = wpabuf_head(buf); len = wpabuf_len(buf); for (i = 0; i < len; i++) printf("%02X", *pos++); printf("\n"); } int main(int argc, char *argv[]) { struct wpa_supplicant wpa_s; int ret = -1; struct wpabuf *buf = NULL, *ndef = NULL; char txt[1000]; if (os_program_init()) return -1; random_init(NULL); os_memset(&wpa_s, 0, sizeof(wpa_s)); wpa_s.conf = os_zalloc(sizeof(*wpa_s.conf)); if (wpa_s.conf == NULL) goto fail; buf = wpas_wps_nfc_token(&wpa_s, 0); if (buf == NULL) goto fail; ndef = ndef_build_wifi(buf); if (ndef == NULL) goto fail; wpa_snprintf_hex_uppercase(txt, sizeof(txt), wpabuf_head(buf), wpabuf_len(buf)); printf("#WPS=%s\n", txt); wpa_snprintf_hex_uppercase(txt, sizeof(txt), wpabuf_head(ndef), wpabuf_len(ndef)); printf("#NDEF=%s\n", txt); printf("wps_nfc_dev_pw_id=%d\n", wpa_s.conf->wps_nfc_dev_pw_id); print_bin("wps_nfc_dh_pubkey", wpa_s.conf->wps_nfc_dh_pubkey); print_bin("wps_nfc_dh_privkey", wpa_s.conf->wps_nfc_dh_privkey); print_bin("wps_nfc_dev_pw", wpa_s.conf->wps_nfc_dev_pw); ret = 0; fail: wpabuf_free(ndef); wpabuf_free(buf); wpa_config_free(wpa_s.conf); random_deinit(); os_program_deinit(); return ret; } wpa_supplicant-2.2/wpa_supplicant/bss.c0000664000175000017500000007633412343617166016220 0ustar jmjm/* * BSS table * Copyright (c) 2009-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 "drivers/driver.h" #include "wpa_supplicant_i.h" #include "config.h" #include "notify.h" #include "scan.h" #include "bss.h" /** * WPA_BSS_EXPIRATION_PERIOD - Period of expiration run in seconds */ #define WPA_BSS_EXPIRATION_PERIOD 10 #define WPA_BSS_FREQ_CHANGED_FLAG BIT(0) #define WPA_BSS_SIGNAL_CHANGED_FLAG BIT(1) #define WPA_BSS_PRIVACY_CHANGED_FLAG BIT(2) #define WPA_BSS_MODE_CHANGED_FLAG BIT(3) #define WPA_BSS_WPAIE_CHANGED_FLAG BIT(4) #define WPA_BSS_RSNIE_CHANGED_FLAG BIT(5) #define WPA_BSS_WPS_CHANGED_FLAG BIT(6) #define WPA_BSS_RATES_CHANGED_FLAG BIT(7) #define WPA_BSS_IES_CHANGED_FLAG BIT(8) static void wpa_bss_set_hessid(struct wpa_bss *bss) { #ifdef CONFIG_INTERWORKING const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING); if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) { os_memset(bss->hessid, 0, ETH_ALEN); return; } if (ie[1] == 7) os_memcpy(bss->hessid, ie + 3, ETH_ALEN); else os_memcpy(bss->hessid, ie + 5, ETH_ALEN); #endif /* CONFIG_INTERWORKING */ } /** * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry * Returns: Allocated ANQP data structure or %NULL on failure * * The allocated ANQP data structure has its users count set to 1. It may be * shared by multiple BSS entries and each shared entry is freed with * wpa_bss_anqp_free(). */ struct wpa_bss_anqp * wpa_bss_anqp_alloc(void) { struct wpa_bss_anqp *anqp; anqp = os_zalloc(sizeof(*anqp)); if (anqp == NULL) return NULL; anqp->users = 1; return anqp; } /** * wpa_bss_anqp_clone - Clone an ANQP data structure * @anqp: ANQP data structure from wpa_bss_anqp_alloc() * Returns: Cloned ANQP data structure or %NULL on failure */ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp) { struct wpa_bss_anqp *n; n = os_zalloc(sizeof(*n)); if (n == NULL) return NULL; #define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f) #ifdef CONFIG_INTERWORKING ANQP_DUP(venue_name); ANQP_DUP(network_auth_type); ANQP_DUP(roaming_consortium); ANQP_DUP(ip_addr_type_availability); ANQP_DUP(nai_realm); ANQP_DUP(anqp_3gpp); ANQP_DUP(domain_name); #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 ANQP_DUP(hs20_operator_friendly_name); ANQP_DUP(hs20_wan_metrics); ANQP_DUP(hs20_connection_capability); ANQP_DUP(hs20_operating_class); ANQP_DUP(hs20_osu_providers_list); #endif /* CONFIG_HS20 */ #undef ANQP_DUP return n; } /** * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry * @bss: BSS entry * Returns: 0 on success, -1 on failure * * This function ensures the specific BSS entry has an ANQP data structure that * is not shared with any other BSS entry. */ int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss) { struct wpa_bss_anqp *anqp; if (bss->anqp && bss->anqp->users > 1) { /* allocated, but shared - clone an unshared copy */ anqp = wpa_bss_anqp_clone(bss->anqp); if (anqp == NULL) return -1; anqp->users = 1; bss->anqp->users--; bss->anqp = anqp; return 0; } if (bss->anqp) return 0; /* already allocated and not shared */ /* not allocated - allocate a new storage area */ bss->anqp = wpa_bss_anqp_alloc(); return bss->anqp ? 0 : -1; } /** * wpa_bss_anqp_free - Free an ANQP data structure * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone() */ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp) { if (anqp == NULL) return; anqp->users--; if (anqp->users > 0) { /* Another BSS entry holds a pointer to this ANQP info */ return; } #ifdef CONFIG_INTERWORKING wpabuf_free(anqp->venue_name); wpabuf_free(anqp->network_auth_type); wpabuf_free(anqp->roaming_consortium); wpabuf_free(anqp->ip_addr_type_availability); wpabuf_free(anqp->nai_realm); wpabuf_free(anqp->anqp_3gpp); wpabuf_free(anqp->domain_name); #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 wpabuf_free(anqp->hs20_operator_friendly_name); wpabuf_free(anqp->hs20_wan_metrics); wpabuf_free(anqp->hs20_connection_capability); wpabuf_free(anqp->hs20_operating_class); wpabuf_free(anqp->hs20_osu_providers_list); #endif /* CONFIG_HS20 */ os_free(anqp); } static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const char *reason) { if (wpa_s->last_scan_res) { unsigned int i; for (i = 0; i < wpa_s->last_scan_res_used; i++) { if (wpa_s->last_scan_res[i] == bss) { os_memmove(&wpa_s->last_scan_res[i], &wpa_s->last_scan_res[i + 1], (wpa_s->last_scan_res_used - i - 1) * sizeof(struct wpa_bss *)); wpa_s->last_scan_res_used--; break; } } } dl_list_del(&bss->list); dl_list_del(&bss->list_id); wpa_s->num_bss--; wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len), reason); wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id); wpa_bss_anqp_free(bss->anqp); os_free(bss); } /** * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID * @wpa_s: Pointer to wpa_supplicant data * @bssid: BSSID * @ssid: SSID * @ssid_len: Length of @ssid * Returns: Pointer to the BSS entry or %NULL if not found */ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid, const u8 *ssid, size_t ssid_len) { struct wpa_bss *bss; if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid)) return NULL; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && bss->ssid_len == ssid_len && os_memcmp(bss->ssid, ssid, ssid_len) == 0) return bss; } return NULL; } static void calculate_update_time(const struct os_reltime *fetch_time, unsigned int age_ms, struct os_reltime *update_time) { os_time_t usec; update_time->sec = fetch_time->sec; update_time->usec = fetch_time->usec; update_time->sec -= age_ms / 1000; usec = (age_ms % 1000) * 1000; if (update_time->usec < usec) { update_time->sec--; update_time->usec += 1000000; } update_time->usec -= usec; } static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, struct os_reltime *fetch_time) { dst->flags = src->flags; os_memcpy(dst->bssid, src->bssid, ETH_ALEN); dst->freq = src->freq; dst->beacon_int = src->beacon_int; dst->caps = src->caps; dst->qual = src->qual; dst->noise = src->noise; dst->level = src->level; dst->tsf = src->tsf; calculate_update_time(fetch_time, src->age, &dst->last_update); } static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { struct wpa_ssid *ssid; for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (ssid->ssid == NULL || ssid->ssid_len == 0) continue; if (ssid->ssid_len == bss->ssid_len && os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0) return 1; } return 0; } static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { return bss == wpa_s->current_bss || os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 || os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0; } static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (!wpa_bss_known(wpa_s, bss)) { wpa_bss_remove(wpa_s, bss, __func__); return 0; } } return -1; } static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss; /* * Remove the oldest entry that does not match with any configured * network. */ if (wpa_bss_remove_oldest_unknown(wpa_s) == 0) return 0; /* * Remove the oldest entry that isn't currently in use. */ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (!wpa_bss_in_use(wpa_s, bss)) { wpa_bss_remove(wpa_s, bss, __func__); return 0; } } return -1; } static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s, const u8 *ssid, size_t ssid_len, struct wpa_scan_res *res, struct os_reltime *fetch_time) { struct wpa_bss *bss; bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len); if (bss == NULL) return NULL; bss->id = wpa_s->bss_next_id++; bss->last_update_idx = wpa_s->bss_update_idx; wpa_bss_copy_res(bss, res, fetch_time); os_memcpy(bss->ssid, ssid, ssid_len); bss->ssid_len = ssid_len; bss->ie_len = res->ie_len; bss->beacon_ie_len = res->beacon_ie_len; os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len); wpa_bss_set_hessid(bss); if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count && wpa_bss_remove_oldest(wpa_s) != 0) { wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d " "because all BSSes are in use. We should normally " "not get here!", (int) wpa_s->num_bss + 1); wpa_s->conf->bss_max_count = wpa_s->num_bss + 1; } dl_list_add_tail(&wpa_s->bss, &bss->list); dl_list_add_tail(&wpa_s->bss_id, &bss->list_id); wpa_s->num_bss++; wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR " SSID '%s'", bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len)); wpas_notify_bss_added(wpa_s, bss->bssid, bss->id); return bss; } static int are_ies_equal(const struct wpa_bss *old, const struct wpa_scan_res *new, u32 ie) { const u8 *old_ie, *new_ie; struct wpabuf *old_ie_buff = NULL; struct wpabuf *new_ie_buff = NULL; int new_ie_len, old_ie_len, ret, is_multi; switch (ie) { case WPA_IE_VENDOR_TYPE: old_ie = wpa_bss_get_vendor_ie(old, ie); new_ie = wpa_scan_get_vendor_ie(new, ie); is_multi = 0; break; case WPS_IE_VENDOR_TYPE: old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie); new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie); is_multi = 1; break; case WLAN_EID_RSN: case WLAN_EID_SUPP_RATES: case WLAN_EID_EXT_SUPP_RATES: old_ie = wpa_bss_get_ie(old, ie); new_ie = wpa_scan_get_ie(new, ie); is_multi = 0; break; default: wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__); return 0; } if (is_multi) { /* in case of multiple IEs stored in buffer */ old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL; new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL; old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0; new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0; } else { /* in case of single IE */ old_ie_len = old_ie ? old_ie[1] + 2 : 0; new_ie_len = new_ie ? new_ie[1] + 2 : 0; } if (!old_ie || !new_ie) ret = !old_ie && !new_ie; else ret = (old_ie_len == new_ie_len && os_memcmp(old_ie, new_ie, old_ie_len) == 0); wpabuf_free(old_ie_buff); wpabuf_free(new_ie_buff); return ret; } static u32 wpa_bss_compare_res(const struct wpa_bss *old, const struct wpa_scan_res *new) { u32 changes = 0; int caps_diff = old->caps ^ new->caps; if (old->freq != new->freq) changes |= WPA_BSS_FREQ_CHANGED_FLAG; if (old->level != new->level) changes |= WPA_BSS_SIGNAL_CHANGED_FLAG; if (caps_diff & IEEE80211_CAP_PRIVACY) changes |= WPA_BSS_PRIVACY_CHANGED_FLAG; if (caps_diff & IEEE80211_CAP_IBSS) changes |= WPA_BSS_MODE_CHANGED_FLAG; if (old->ie_len == new->ie_len && os_memcmp(old + 1, new + 1, old->ie_len) == 0) return changes; changes |= WPA_BSS_IES_CHANGED_FLAG; if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE)) changes |= WPA_BSS_WPAIE_CHANGED_FLAG; if (!are_ies_equal(old, new, WLAN_EID_RSN)) changes |= WPA_BSS_RSNIE_CHANGED_FLAG; if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE)) changes |= WPA_BSS_WPS_CHANGED_FLAG; if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) || !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES)) changes |= WPA_BSS_RATES_CHANGED_FLAG; return changes; } static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes, const struct wpa_bss *bss) { if (changes & WPA_BSS_FREQ_CHANGED_FLAG) wpas_notify_bss_freq_changed(wpa_s, bss->id); if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG) wpas_notify_bss_signal_changed(wpa_s, bss->id); if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG) wpas_notify_bss_privacy_changed(wpa_s, bss->id); if (changes & WPA_BSS_MODE_CHANGED_FLAG) wpas_notify_bss_mode_changed(wpa_s, bss->id); if (changes & WPA_BSS_WPAIE_CHANGED_FLAG) wpas_notify_bss_wpaie_changed(wpa_s, bss->id); if (changes & WPA_BSS_RSNIE_CHANGED_FLAG) wpas_notify_bss_rsnie_changed(wpa_s, bss->id); if (changes & WPA_BSS_WPS_CHANGED_FLAG) wpas_notify_bss_wps_changed(wpa_s, bss->id); if (changes & WPA_BSS_IES_CHANGED_FLAG) wpas_notify_bss_ies_changed(wpa_s, bss->id); if (changes & WPA_BSS_RATES_CHANGED_FLAG) wpas_notify_bss_rates_changed(wpa_s, bss->id); } static struct wpa_bss * wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_scan_res *res, struct os_reltime *fetch_time) { u32 changes; changes = wpa_bss_compare_res(bss, res); bss->scan_miss_count = 0; bss->last_update_idx = wpa_s->bss_update_idx; wpa_bss_copy_res(bss, res, fetch_time); /* Move the entry to the end of the list */ dl_list_del(&bss->list); #ifdef CONFIG_P2P if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) && !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE)) { /* * This can happen when non-P2P station interface runs a scan * without P2P IE in the Probe Request frame. P2P GO would reply * to that with a Probe Response that does not include P2P IE. * Do not update the IEs in this BSS entry to avoid such loss of * information that may be needed for P2P operations to * determine group information. */ wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for " MACSTR " since that would remove P2P IE information", MAC2STR(bss->bssid)); } else #endif /* CONFIG_P2P */ if (bss->ie_len + bss->beacon_ie_len >= res->ie_len + res->beacon_ie_len) { os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len); bss->ie_len = res->ie_len; bss->beacon_ie_len = res->beacon_ie_len; } else { struct wpa_bss *nbss; struct dl_list *prev = bss->list_id.prev; dl_list_del(&bss->list_id); nbss = os_realloc(bss, sizeof(*bss) + res->ie_len + res->beacon_ie_len); if (nbss) { unsigned int i; for (i = 0; i < wpa_s->last_scan_res_used; i++) { if (wpa_s->last_scan_res[i] == bss) { wpa_s->last_scan_res[i] = nbss; break; } } if (wpa_s->current_bss == bss) wpa_s->current_bss = nbss; bss = nbss; os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len); bss->ie_len = res->ie_len; bss->beacon_ie_len = res->beacon_ie_len; } dl_list_add(prev, &bss->list_id); } if (changes & WPA_BSS_IES_CHANGED_FLAG) wpa_bss_set_hessid(bss); dl_list_add_tail(&wpa_s->bss, &bss->list); notify_bss_changes(wpa_s, changes, bss); return bss; } /** * wpa_bss_update_start - Start a BSS table update from scan results * @wpa_s: Pointer to wpa_supplicant data * * This function is called at the start of each BSS table update round for new * scan results. The actual scan result entries are indicated with calls to * wpa_bss_update_scan_res() and the update round is finished with a call to * wpa_bss_update_end(). */ void wpa_bss_update_start(struct wpa_supplicant *wpa_s) { wpa_s->bss_update_idx++; wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u", wpa_s->bss_update_idx); wpa_s->last_scan_res_used = 0; } /** * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result * @wpa_s: Pointer to wpa_supplicant data * @res: Scan result * @fetch_time: Time when the result was fetched from the driver * * This function updates a BSS table entry (or adds one) based on a scan result. * This is called separately for each scan result between the calls to * wpa_bss_update_start() and wpa_bss_update_end(). */ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res, struct os_reltime *fetch_time) { const u8 *ssid, *p2p; struct wpa_bss *bss; if (wpa_s->conf->ignore_old_scan_res) { struct os_reltime update; calculate_update_time(fetch_time, res->age, &update); if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) { struct os_reltime age; os_reltime_sub(&wpa_s->scan_trigger_time, &update, &age); wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS " "table entry that is %u.%06u seconds older " "than our scan trigger", (unsigned int) age.sec, (unsigned int) age.usec); return; } } ssid = wpa_scan_get_ie(res, WLAN_EID_SSID); if (ssid == NULL) { wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for " MACSTR, MAC2STR(res->bssid)); return; } if (ssid[1] > 32) { wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for " MACSTR, MAC2STR(res->bssid)); return; } p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE); #ifdef CONFIG_P2P if (p2p == NULL && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) { /* * If it's a P2P specific interface, then don't update * the scan result without a P2P IE. */ wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR " update for P2P interface", MAC2STR(res->bssid)); return; } #endif /* CONFIG_P2P */ if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN && os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0) return; /* Skip P2P listen discovery results here */ /* TODO: add option for ignoring BSSes we are not interested in * (to save memory) */ bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]); if (bss == NULL) bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time); else { bss = wpa_bss_update(wpa_s, bss, res, fetch_time); if (wpa_s->last_scan_res) { unsigned int i; for (i = 0; i < wpa_s->last_scan_res_used; i++) { if (bss == wpa_s->last_scan_res[i]) { /* Already in the list */ return; } } } } if (bss == NULL) return; if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) { struct wpa_bss **n; unsigned int siz; if (wpa_s->last_scan_res_size == 0) siz = 32; else siz = wpa_s->last_scan_res_size * 2; n = os_realloc_array(wpa_s->last_scan_res, siz, sizeof(struct wpa_bss *)); if (n == NULL) return; wpa_s->last_scan_res = n; wpa_s->last_scan_res_size = siz; } if (wpa_s->last_scan_res) wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss; } static int wpa_bss_included_in_scan(const struct wpa_bss *bss, const struct scan_info *info) { int found; size_t i; if (info == NULL) return 1; if (info->num_freqs) { found = 0; for (i = 0; i < info->num_freqs; i++) { if (bss->freq == info->freqs[i]) { found = 1; break; } } if (!found) return 0; } if (info->num_ssids) { found = 0; for (i = 0; i < info->num_ssids; i++) { const struct wpa_driver_scan_ssid *s = &info->ssids[i]; if ((s->ssid == NULL || s->ssid_len == 0) || (s->ssid_len == bss->ssid_len && os_memcmp(s->ssid, bss->ssid, bss->ssid_len) == 0)) { found = 1; break; } } if (!found) return 0; } return 1; } /** * wpa_bss_update_end - End a BSS table update from scan results * @wpa_s: Pointer to wpa_supplicant data * @info: Information about scan parameters * @new_scan: Whether this update round was based on a new scan * * This function is called at the end of each BSS table update round for new * scan results. The start of the update was indicated with a call to * wpa_bss_update_start(). */ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, int new_scan) { struct wpa_bss *bss, *n; os_get_reltime(&wpa_s->last_scan); if (!new_scan) return; /* do not expire entries without new scan */ dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { if (wpa_bss_in_use(wpa_s, bss)) continue; if (!wpa_bss_included_in_scan(bss, info)) continue; /* expire only BSSes that were scanned */ if (bss->last_update_idx < wpa_s->bss_update_idx) bss->scan_miss_count++; if (bss->scan_miss_count >= wpa_s->conf->bss_expiration_scan_count) { wpa_bss_remove(wpa_s, bss, "no match in scan"); } } wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u", wpa_s->last_scan_res_used, wpa_s->last_scan_res_size); } /** * wpa_bss_flush_by_age - Flush old BSS entries * @wpa_s: Pointer to wpa_supplicant data * @age: Maximum entry age in seconds * * Remove BSS entries that have not been updated during the last @age seconds. */ void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age) { struct wpa_bss *bss, *n; struct os_reltime t; if (dl_list_empty(&wpa_s->bss)) return; os_get_reltime(&t); t.sec -= age; dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { if (wpa_bss_in_use(wpa_s, bss)) continue; if (os_reltime_before(&bss->last_update, &t)) { wpa_bss_remove(wpa_s, bss, __func__); } else break; } } static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age); eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0, wpa_bss_timeout, wpa_s, NULL); } /** * wpa_bss_init - Initialize BSS table * @wpa_s: Pointer to wpa_supplicant data * Returns: 0 on success, -1 on failure * * This prepares BSS table lists and timer for periodic updates. The BSS table * is deinitialized with wpa_bss_deinit() once not needed anymore. */ int wpa_bss_init(struct wpa_supplicant *wpa_s) { dl_list_init(&wpa_s->bss); dl_list_init(&wpa_s->bss_id); eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0, wpa_bss_timeout, wpa_s, NULL); return 0; } /** * wpa_bss_flush - Flush all unused BSS entries * @wpa_s: Pointer to wpa_supplicant data */ void wpa_bss_flush(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss, *n; wpa_s->clear_driver_scan_cache = 1; if (wpa_s->bss.next == NULL) return; /* BSS table not yet initialized */ dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { if (wpa_bss_in_use(wpa_s, bss)) continue; wpa_bss_remove(wpa_s, bss, __func__); } } /** * wpa_bss_deinit - Deinitialize BSS table * @wpa_s: Pointer to wpa_supplicant data */ void wpa_bss_deinit(struct wpa_supplicant *wpa_s) { eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL); wpa_bss_flush(wpa_s); } /** * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID * @wpa_s: Pointer to wpa_supplicant data * @bssid: BSSID * Returns: Pointer to the BSS entry or %NULL if not found */ struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid) { struct wpa_bss *bss; if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid)) return NULL; dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) { if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) return bss; } return NULL; } /** * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID * @wpa_s: Pointer to wpa_supplicant data * @bssid: BSSID * Returns: Pointer to the BSS entry or %NULL if not found * * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to * find the entry that has the most recent update. This can help in finding the * correct entry in cases where the SSID of the AP may have changed recently * (e.g., in WPS reconfiguration cases). */ struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s, const u8 *bssid) { struct wpa_bss *bss, *found = NULL; if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid)) return NULL; dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) { if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0) continue; if (found == NULL || os_reltime_before(&found->last_update, &bss->last_update)) found = bss; } return found; } #ifdef CONFIG_P2P /** * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr * @wpa_s: Pointer to wpa_supplicant data * @dev_addr: P2P Device Address of the GO * Returns: Pointer to the BSS entry or %NULL if not found */ struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s, const u8 *dev_addr) { struct wpa_bss *bss; dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) { u8 addr[ETH_ALEN]; if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len, addr) == 0 && os_memcmp(addr, dev_addr, ETH_ALEN) == 0) return bss; } return NULL; } #endif /* CONFIG_P2P */ /** * wpa_bss_get_id - Fetch a BSS table entry based on identifier * @wpa_s: Pointer to wpa_supplicant data * @id: Unique identifier (struct wpa_bss::id) assigned for the entry * Returns: Pointer to the BSS entry or %NULL if not found */ struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id) { struct wpa_bss *bss; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (bss->id == id) return bss; } return NULL; } /** * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range * @wpa_s: Pointer to wpa_supplicant data * @idf: Smallest allowed identifier assigned for the entry * @idf: Largest allowed identifier assigned for the entry * Returns: Pointer to the BSS entry or %NULL if not found * * This function is similar to wpa_bss_get_id() but allows a BSS entry with the * smallest id value to be fetched within the specified range without the * caller having to know the exact id. */ struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s, unsigned int idf, unsigned int idl) { struct wpa_bss *bss; dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { if (bss->id >= idf && bss->id <= idl) return bss; } return NULL; } /** * wpa_bss_get_ie - Fetch a specified information element from a BSS entry * @bss: BSS table entry * @ie: Information element identitifier (WLAN_EID_*) * Returns: Pointer to the information element (id field) or %NULL if not found * * This function returns the first matching information element in the BSS * entry. */ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie) { const u8 *end, *pos; pos = (const u8 *) (bss + 1); end = pos + bss->ie_len; while (pos + 1 < end) { if (pos + 2 + pos[1] > end) break; if (pos[0] == ie) return pos; pos += 2 + pos[1]; } return NULL; } /** * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry * @bss: BSS table entry * @vendor_type: Vendor type (four octets starting the IE payload) * Returns: Pointer to the information element (id field) or %NULL if not found * * This function returns the first matching information element in the BSS * entry. */ const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type) { const u8 *end, *pos; pos = (const u8 *) (bss + 1); end = pos + bss->ie_len; while (pos + 1 < end) { if (pos + 2 + pos[1] > end) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) return pos; pos += 2 + pos[1]; } return NULL; } /** * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry * @bss: BSS table entry * @vendor_type: Vendor type (four octets starting the IE payload) * Returns: Pointer to the information element (id field) or %NULL if not found * * This function returns the first matching information element in the BSS * entry. * * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only * from Beacon frames instead of either Beacon or Probe Response frames. */ const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss, u32 vendor_type) { const u8 *end, *pos; if (bss->beacon_ie_len == 0) return NULL; pos = (const u8 *) (bss + 1); pos += bss->ie_len; end = pos + bss->beacon_ie_len; while (pos + 1 < end) { if (pos + 2 + pos[1] > end) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) return pos; pos += 2 + pos[1]; } return NULL; } /** * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry * @bss: BSS table entry * @vendor_type: Vendor type (four octets starting the IE payload) * Returns: Pointer to the information element payload or %NULL if not found * * This function returns concatenated payload of possibly fragmented vendor * specific information elements in the BSS entry. The caller is responsible for * freeing the returned buffer. */ struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss, u32 vendor_type) { struct wpabuf *buf; const u8 *end, *pos; buf = wpabuf_alloc(bss->ie_len); if (buf == NULL) return NULL; pos = (const u8 *) (bss + 1); end = pos + bss->ie_len; while (pos + 1 < end) { if (pos + 2 + pos[1] > end) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4); pos += 2 + pos[1]; } if (wpabuf_len(buf) == 0) { wpabuf_free(buf); buf = NULL; } return buf; } /** * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry * @bss: BSS table entry * @vendor_type: Vendor type (four octets starting the IE payload) * Returns: Pointer to the information element payload or %NULL if not found * * This function returns concatenated payload of possibly fragmented vendor * specific information elements in the BSS entry. The caller is responsible for * freeing the returned buffer. * * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only * from Beacon frames instead of either Beacon or Probe Response frames. */ struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss, u32 vendor_type) { struct wpabuf *buf; const u8 *end, *pos; buf = wpabuf_alloc(bss->beacon_ie_len); if (buf == NULL) return NULL; pos = (const u8 *) (bss + 1); pos += bss->ie_len; end = pos + bss->beacon_ie_len; while (pos + 1 < end) { if (pos + 2 + pos[1] > end) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4); pos += 2 + pos[1]; } if (wpabuf_len(buf) == 0) { wpabuf_free(buf); buf = NULL; } return buf; } /** * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS * @bss: BSS table entry * Returns: Maximum legacy rate in units of 500 kbps */ int wpa_bss_get_max_rate(const struct wpa_bss *bss) { int rate = 0; const u8 *ie; int i; ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES); for (i = 0; ie && i < ie[1]; i++) { if ((ie[i + 2] & 0x7f) > rate) rate = ie[i + 2] & 0x7f; } ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES); for (i = 0; ie && i < ie[1]; i++) { if ((ie[i + 2] & 0x7f) > rate) rate = ie[i + 2] & 0x7f; } return rate; } /** * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS * @bss: BSS table entry * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps) * Returns: number of legacy TX rates or -1 on failure * * The caller is responsible for freeing the returned buffer with os_free() in * case of success. */ int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates) { const u8 *ie, *ie2; int i, j; unsigned int len; u8 *r; ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES); ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES); len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0); r = os_malloc(len); if (!r) return -1; for (i = 0; ie && i < ie[1]; i++) r[i] = ie[i + 2] & 0x7f; for (j = 0; ie2 && j < ie2[1]; j++) r[i + j] = ie2[j + 2] & 0x7f; *rates = r; return len; } wpa_supplicant-2.2/wpa_supplicant/wpa_supplicant_conf.sh0000775000175000017500000000071212343617166021645 0ustar jmjm#!/bin/bash # # Copyright (C) 2010 The Android Open Source Project # # This software may be distributed under the terms of the BSD license. # See README for more details. # # Generate a wpa_supplicant.conf from the template. # $1: the template file name if [ -n "$WIFI_DRIVER_SOCKET_IFACE" ] then sed -e 's/#.*$//' -e 's/[ \t]*$//' -e '/^$/d' < $1 | sed -e "s/wlan0/$WIFI_DRIVER_SOCKET_IFACE/" else sed -e 's/#.*$//' -e 's/[ \t]*$//' -e '/^$/d' < $1 fi wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/0000775000175000017500000000000012343617166017411 5ustar jmjmwpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/addinterface.h0000664000175000017500000000133312343617166022173 0ustar jmjm/* * wpa_gui - AddInterface class * Copyright (c) 2008, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef ADDINTERFACE_H #define ADDINTERFACE_H #include #include #include #include class WpaGui; class AddInterface : public QDialog { Q_OBJECT public: AddInterface(WpaGui *_wpagui, QWidget *parent = 0); public slots: virtual void interfaceSelected(QTreeWidgetItem *sel); private: void addInterfaces(); bool addRegistryInterface(const QString &ifname); QVBoxLayout *vboxLayout; QTreeWidget *interfaceWidget; WpaGui *wpagui; }; #endif /* ADDINTERFACE_H */ wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/peers.ui0000664000175000017500000000173512343617166021074 0ustar jmjm Peers 0 0 400 300 Peers 0 0 true QAbstractItemView::NoEditTriggers QListView::IconMode wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/eventhistory.h0000664000175000017500000000242112343617166022324 0ustar jmjm/* * wpa_gui - EventHistory class * Copyright (c) 2005-2006, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef EVENTHISTORY_H #define EVENTHISTORY_H #include #include "ui_eventhistory.h" class EventListModel : public QAbstractTableModel { Q_OBJECT public: EventListModel(QObject *parent = 0) : QAbstractTableModel(parent) {} int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; void addEvent(QString time, QString msg); private: QStringList timeList; QStringList msgList; }; class EventHistory : public QDialog, public Ui::EventHistory { Q_OBJECT public: EventHistory(QWidget *parent = 0, const char *name = 0, bool modal = false, Qt::WFlags fl = 0); ~EventHistory(); public slots: virtual void addEvents(WpaMsgList msgs); virtual void addEvent(WpaMsg msg); protected slots: virtual void languageChange(); private: EventListModel *elm; }; #endif /* EVENTHISTORY_H */ wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/peers.cpp0000664000175000017500000013212212343617166021234 0ustar jmjm/* * wpa_gui - Peers class * Copyright (c) 2009-2010, Atheros Communications * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include #include #include #include "common/wpa_ctrl.h" #include "wpagui.h" #include "stringquery.h" #include "peers.h" enum { peer_role_address = Qt::UserRole + 1, peer_role_type, peer_role_uuid, peer_role_details, peer_role_ifname, peer_role_pri_dev_type, peer_role_ssid, peer_role_config_methods, peer_role_dev_passwd_id, peer_role_bss_id, peer_role_selected_method, peer_role_selected_pin, peer_role_requested_method, peer_role_network_id }; enum selected_method { SEL_METHOD_NONE, SEL_METHOD_PIN_PEER_DISPLAY, SEL_METHOD_PIN_LOCAL_DISPLAY }; /* * TODO: * - add current AP info (e.g., from WPS) in station mode */ enum peer_type { PEER_TYPE_ASSOCIATED_STATION, PEER_TYPE_AP, PEER_TYPE_AP_WPS, PEER_TYPE_WPS_PIN_NEEDED, PEER_TYPE_P2P, PEER_TYPE_P2P_CLIENT, PEER_TYPE_P2P_GROUP, PEER_TYPE_P2P_PERSISTENT_GROUP_GO, PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT, PEER_TYPE_P2P_INVITATION, PEER_TYPE_WPS_ER_AP, PEER_TYPE_WPS_ER_AP_UNCONFIGURED, PEER_TYPE_WPS_ER_ENROLLEE, PEER_TYPE_WPS_ENROLLEE }; Peers::Peers(QWidget *parent, const char *, bool, Qt::WFlags) : QDialog(parent) { setupUi(this); if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) { default_icon = new QIcon(":/icons/wpa_gui.svg"); ap_icon = new QIcon(":/icons/ap.svg"); laptop_icon = new QIcon(":/icons/laptop.svg"); group_icon = new QIcon(":/icons/group.svg"); invitation_icon = new QIcon(":/icons/invitation.svg"); } else { default_icon = new QIcon(":/icons/wpa_gui.png"); ap_icon = new QIcon(":/icons/ap.png"); laptop_icon = new QIcon(":/icons/laptop.png"); group_icon = new QIcon(":/icons/group.png"); invitation_icon = new QIcon(":/icons/invitation.png"); } peers->setModel(&model); peers->setResizeMode(QListView::Adjust); peers->setDragEnabled(false); peers->setSelectionMode(QAbstractItemView::NoSelection); peers->setContextMenuPolicy(Qt::CustomContextMenu); connect(peers, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(context_menu(const QPoint &))); wpagui = NULL; hide_ap = false; } void Peers::setWpaGui(WpaGui *_wpagui) { wpagui = _wpagui; update_peers(); } Peers::~Peers() { delete default_icon; delete ap_icon; delete laptop_icon; delete group_icon; delete invitation_icon; } void Peers::languageChange() { retranslateUi(this); } QString Peers::ItemType(int type) { QString title; switch (type) { case PEER_TYPE_ASSOCIATED_STATION: title = tr("Associated station"); break; case PEER_TYPE_AP: title = tr("AP"); break; case PEER_TYPE_AP_WPS: title = tr("WPS AP"); break; case PEER_TYPE_WPS_PIN_NEEDED: title = tr("WPS PIN needed"); break; case PEER_TYPE_P2P: title = tr("P2P Device"); break; case PEER_TYPE_P2P_CLIENT: title = tr("P2P Device (group client)"); break; case PEER_TYPE_P2P_GROUP: title = tr("P2P Group"); break; case PEER_TYPE_P2P_PERSISTENT_GROUP_GO: title = tr("P2P Persistent Group (GO)"); break; case PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT: title = tr("P2P Persistent Group (client)"); break; case PEER_TYPE_P2P_INVITATION: title = tr("P2P Invitation"); break; case PEER_TYPE_WPS_ER_AP: title = tr("ER: WPS AP"); break; case PEER_TYPE_WPS_ER_AP_UNCONFIGURED: title = tr("ER: WPS AP (Unconfigured)"); break; case PEER_TYPE_WPS_ER_ENROLLEE: title = tr("ER: WPS Enrollee"); break; case PEER_TYPE_WPS_ENROLLEE: title = tr("WPS Enrollee"); break; } return title; } void Peers::context_menu(const QPoint &pos) { QMenu *menu = new QMenu; if (menu == NULL) return; QModelIndex idx = peers->indexAt(pos); if (idx.isValid()) { ctx_item = model.itemFromIndex(idx); int type = ctx_item->data(peer_role_type).toInt(); menu->addAction(Peers::ItemType(type))->setEnabled(false); menu->addSeparator(); int config_methods = -1; QVariant var = ctx_item->data(peer_role_config_methods); if (var.isValid()) config_methods = var.toInt(); enum selected_method method = SEL_METHOD_NONE; var = ctx_item->data(peer_role_selected_method); if (var.isValid()) method = (enum selected_method) var.toInt(); if ((type == PEER_TYPE_ASSOCIATED_STATION || type == PEER_TYPE_AP_WPS || type == PEER_TYPE_WPS_PIN_NEEDED || type == PEER_TYPE_WPS_ER_ENROLLEE || type == PEER_TYPE_WPS_ENROLLEE) && (config_methods == -1 || (config_methods & 0x010c))) { menu->addAction(tr("Enter WPS PIN"), this, SLOT(enter_pin())); } if (type == PEER_TYPE_P2P || type == PEER_TYPE_P2P_CLIENT) { menu->addAction(tr("P2P Connect"), this, SLOT(ctx_p2p_connect())); if (method == SEL_METHOD_NONE && config_methods > -1 && config_methods & 0x0080 /* PBC */ && config_methods != 0x0080) menu->addAction(tr("P2P Connect (PBC)"), this, SLOT(connect_pbc())); if (method == SEL_METHOD_NONE) { menu->addAction(tr("P2P Request PIN"), this, SLOT(ctx_p2p_req_pin())); menu->addAction(tr("P2P Show PIN"), this, SLOT(ctx_p2p_show_pin())); } if (config_methods > -1 && (config_methods & 0x0100)) { /* Peer has Keypad */ menu->addAction(tr("P2P Display PIN"), this, SLOT(ctx_p2p_display_pin())); } if (config_methods > -1 && (config_methods & 0x000c)) { /* Peer has Label or Display */ menu->addAction(tr("P2P Enter PIN"), this, SLOT(ctx_p2p_enter_pin())); } } if (type == PEER_TYPE_P2P_GROUP) { menu->addAction(tr("Show passphrase"), this, SLOT(ctx_p2p_show_passphrase())); menu->addAction(tr("Remove P2P Group"), this, SLOT(ctx_p2p_remove_group())); } if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO || type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT || type == PEER_TYPE_P2P_INVITATION) { menu->addAction(tr("Start group"), this, SLOT(ctx_p2p_start_persistent())); } if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO || type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT) { menu->addAction(tr("Invite"), this, SLOT(ctx_p2p_invite())); } if (type == PEER_TYPE_P2P_INVITATION) { menu->addAction(tr("Ignore"), this, SLOT(ctx_p2p_delete())); } if (type == PEER_TYPE_AP_WPS) { menu->addAction(tr("Connect (PBC)"), this, SLOT(connect_pbc())); } if ((type == PEER_TYPE_ASSOCIATED_STATION || type == PEER_TYPE_WPS_ER_ENROLLEE || type == PEER_TYPE_WPS_ENROLLEE) && config_methods >= 0 && (config_methods & 0x0080)) { menu->addAction(tr("Enroll (PBC)"), this, SLOT(connect_pbc())); } if (type == PEER_TYPE_WPS_ER_AP) { menu->addAction(tr("Learn Configuration"), this, SLOT(learn_ap_config())); } menu->addAction(tr("Properties"), this, SLOT(properties())); } else { ctx_item = NULL; menu->addAction(QString(tr("Refresh")), this, SLOT(ctx_refresh())); menu->addAction(tr("Start P2P discovery"), this, SLOT(ctx_p2p_start())); menu->addAction(tr("Stop P2P discovery"), this, SLOT(ctx_p2p_stop())); menu->addAction(tr("P2P listen only"), this, SLOT(ctx_p2p_listen())); menu->addAction(tr("Start P2P group"), this, SLOT(ctx_p2p_start_group())); if (hide_ap) menu->addAction(tr("Show AP entries"), this, SLOT(ctx_show_ap())); else menu->addAction(tr("Hide AP entries"), this, SLOT(ctx_hide_ap())); } menu->exec(peers->mapToGlobal(pos)); } void Peers::enter_pin() { if (ctx_item == NULL) return; int peer_type = ctx_item->data(peer_role_type).toInt(); QString uuid; QString addr; addr = ctx_item->data(peer_role_address).toString(); if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) uuid = ctx_item->data(peer_role_uuid).toString(); StringQuery input(tr("PIN:")); input.setWindowTitle(tr("PIN for ") + ctx_item->text()); if (input.exec() != QDialog::Accepted) return; char cmd[100]; char reply[100]; size_t reply_len; if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) { snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s", uuid.toAscii().constData(), input.get_string().toAscii().constData(), addr.toAscii().constData()); } else { snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", addr.toAscii().constData(), input.get_string().toAscii().constData()); } reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText(tr("Failed to set the WPS PIN.")); msg.exec(); } } void Peers::ctx_refresh() { update_peers(); } void Peers::ctx_p2p_start() { char reply[20]; size_t reply_len; reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest("P2P_FIND", reply, &reply_len) < 0 || memcmp(reply, "FAIL", 4) == 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText("Failed to start P2P discovery."); msg.exec(); } } void Peers::ctx_p2p_stop() { char reply[20]; size_t reply_len; reply_len = sizeof(reply) - 1; wpagui->ctrlRequest("P2P_STOP_FIND", reply, &reply_len); } void Peers::ctx_p2p_listen() { char reply[20]; size_t reply_len; reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest("P2P_LISTEN 3600", reply, &reply_len) < 0 || memcmp(reply, "FAIL", 4) == 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText("Failed to start P2P listen."); msg.exec(); } } void Peers::ctx_p2p_start_group() { char reply[20]; size_t reply_len; reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest("P2P_GROUP_ADD", reply, &reply_len) < 0 || memcmp(reply, "FAIL", 4) == 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText("Failed to start P2P group."); msg.exec(); } } void Peers::add_station(QString info) { QStringList lines = info.split(QRegExp("\\n")); QString name; for (QStringList::Iterator it = lines.begin(); it != lines.end(); it++) { int pos = (*it).indexOf('=') + 1; if (pos < 1) continue; if ((*it).startsWith("wpsDeviceName=")) name = (*it).mid(pos); else if ((*it).startsWith("p2p_device_name=")) name = (*it).mid(pos); } if (name.isEmpty()) name = lines[0]; QStandardItem *item = new QStandardItem(*laptop_icon, name); if (item) { /* Remove WPS enrollee entry if one is still pending */ if (model.rowCount() > 0) { QModelIndexList lst = model.match(model.index(0, 0), peer_role_address, lines[0]); for (int i = 0; i < lst.size(); i++) { QStandardItem *item; item = model.itemFromIndex(lst[i]); if (item == NULL) continue; int type = item->data(peer_role_type).toInt(); if (type == PEER_TYPE_WPS_ENROLLEE) { model.removeRow(lst[i].row()); break; } } } item->setData(lines[0], peer_role_address); item->setData(PEER_TYPE_ASSOCIATED_STATION, peer_role_type); item->setData(info, peer_role_details); item->setToolTip(ItemType(PEER_TYPE_ASSOCIATED_STATION)); model.appendRow(item); } } void Peers::add_stations() { char reply[2048]; size_t reply_len; char cmd[30]; int res; reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest("STA-FIRST", reply, &reply_len) < 0) return; do { reply[reply_len] = '\0'; QString info(reply); char *txt = reply; while (*txt != '\0' && *txt != '\n') txt++; *txt++ = '\0'; if (strncmp(reply, "FAIL", 4) == 0 || strncmp(reply, "UNKNOWN", 7) == 0) break; add_station(info); reply_len = sizeof(reply) - 1; snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply); res = wpagui->ctrlRequest(cmd, reply, &reply_len); } while (res >= 0); } void Peers::add_single_station(const char *addr) { char reply[2048]; size_t reply_len; char cmd[30]; reply_len = sizeof(reply) - 1; snprintf(cmd, sizeof(cmd), "STA %s", addr); if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) return; reply[reply_len] = '\0'; QString info(reply); char *txt = reply; while (*txt != '\0' && *txt != '\n') txt++; *txt++ = '\0'; if (strncmp(reply, "FAIL", 4) == 0 || strncmp(reply, "UNKNOWN", 7) == 0) return; add_station(info); } void Peers::add_p2p_group_client(QStandardItem * /*parent*/, QString params) { /* * dev=02:b5:64:63:30:63 iface=02:b5:64:63:30:63 dev_capab=0x0 * dev_type=1-0050f204-1 dev_name='Wireless Client' * config_methods=0x8c */ QStringList items = params.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)")); QString addr = ""; QString name = ""; int config_methods = 0; QString dev_type; for (int i = 0; i < items.size(); i++) { QString str = items.at(i); int pos = str.indexOf('=') + 1; if (str.startsWith("dev_name='")) name = str.section('\'', 1, -2); else if (str.startsWith("config_methods=")) config_methods = str.section('=', 1).toInt(0, 0); else if (str.startsWith("dev=")) addr = str.mid(pos); else if (str.startsWith("dev_type=") && dev_type.isEmpty()) dev_type = str.mid(pos); } QStandardItem *item = find_addr(addr); if (item) return; item = new QStandardItem(*default_icon, name); if (item) { /* TODO: indicate somehow the relationship to the group owner * (parent) */ item->setData(addr, peer_role_address); item->setData(config_methods, peer_role_config_methods); item->setData(PEER_TYPE_P2P_CLIENT, peer_role_type); if (!dev_type.isEmpty()) item->setData(dev_type, peer_role_pri_dev_type); item->setData(items.join(QString("\n")), peer_role_details); item->setToolTip(ItemType(PEER_TYPE_P2P_CLIENT)); model.appendRow(item); } } void Peers::remove_bss(int id) { if (model.rowCount() == 0) return; QModelIndexList lst = model.match(model.index(0, 0), peer_role_bss_id, id); if (lst.size() == 0) return; model.removeRow(lst[0].row()); } bool Peers::add_bss(const char *cmd) { char reply[2048]; size_t reply_len; if (hide_ap) return false; reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) return false; reply[reply_len] = '\0'; QString bss(reply); if (bss.isEmpty() || bss.startsWith("FAIL")) return false; QString ssid, bssid, flags, wps_name, pri_dev_type; int id = -1; QStringList lines = bss.split(QRegExp("\\n")); for (QStringList::Iterator it = lines.begin(); it != lines.end(); it++) { int pos = (*it).indexOf('=') + 1; if (pos < 1) continue; if ((*it).startsWith("bssid=")) bssid = (*it).mid(pos); else if ((*it).startsWith("id=")) id = (*it).mid(pos).toInt(); else if ((*it).startsWith("flags=")) flags = (*it).mid(pos); else if ((*it).startsWith("ssid=")) ssid = (*it).mid(pos); else if ((*it).startsWith("wps_device_name=")) wps_name = (*it).mid(pos); else if ((*it).startsWith("wps_primary_device_type=")) pri_dev_type = (*it).mid(pos); } QString name = wps_name; if (name.isEmpty()) name = ssid + "\n" + bssid; QStandardItem *item = new QStandardItem(*ap_icon, name); if (item) { item->setData(bssid, peer_role_address); if (id >= 0) item->setData(id, peer_role_bss_id); int type; if (flags.contains("[WPS")) type = PEER_TYPE_AP_WPS; else type = PEER_TYPE_AP; item->setData(type, peer_role_type); for (int i = 0; i < lines.size(); i++) { if (lines[i].length() > 60) { lines[i].remove(60, lines[i].length()); lines[i] += ".."; } } item->setToolTip(ItemType(type)); item->setData(lines.join("\n"), peer_role_details); if (!pri_dev_type.isEmpty()) item->setData(pri_dev_type, peer_role_pri_dev_type); if (!ssid.isEmpty()) item->setData(ssid, peer_role_ssid); model.appendRow(item); lines = bss.split(QRegExp("\\n")); for (QStringList::Iterator it = lines.begin(); it != lines.end(); it++) { if ((*it).startsWith("p2p_group_client:")) add_p2p_group_client(item, (*it).mid(18)); } } return true; } void Peers::add_scan_results() { int index; char cmd[20]; index = 0; while (wpagui) { snprintf(cmd, sizeof(cmd), "BSS %d", index++); if (index > 1000) break; if (!add_bss(cmd)) break; } } void Peers::add_persistent(int id, const char *ssid, const char *bssid) { char cmd[100]; char reply[100]; size_t reply_len; int mode; snprintf(cmd, sizeof(cmd), "GET_NETWORK %d mode", id); if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) return; reply[reply_len] = '\0'; mode = atoi(reply); QString name = ssid; name = '[' + name + ']'; QStandardItem *item = new QStandardItem(*group_icon, name); if (!item) return; int type; if (mode == 3) type = PEER_TYPE_P2P_PERSISTENT_GROUP_GO; else type = PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT; item->setData(type, peer_role_type); item->setToolTip(ItemType(type)); item->setData(ssid, peer_role_ssid); if (bssid && strcmp(bssid, "any") == 0) bssid = NULL; if (bssid) item->setData(bssid, peer_role_address); item->setData(id, peer_role_network_id); item->setBackground(Qt::BDiagPattern); model.appendRow(item); } void Peers::add_persistent_groups() { char buf[2048], *start, *end, *id, *ssid, *bssid, *flags; size_t len; len = sizeof(buf) - 1; if (wpagui->ctrlRequest("LIST_NETWORKS", buf, &len) < 0) return; buf[len] = '\0'; start = strchr(buf, '\n'); if (start == NULL) return; start++; while (*start) { bool last = false; end = strchr(start, '\n'); if (end == NULL) { last = true; end = start; while (end[0] && end[1]) end++; } *end = '\0'; id = start; ssid = strchr(id, '\t'); if (ssid == NULL) break; *ssid++ = '\0'; bssid = strchr(ssid, '\t'); if (bssid == NULL) break; *bssid++ = '\0'; flags = strchr(bssid, '\t'); if (flags == NULL) break; *flags++ = '\0'; if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) add_persistent(atoi(id), ssid, bssid); if (last) break; start = end + 1; } } void Peers::update_peers() { model.clear(); if (wpagui == NULL) return; char reply[20]; size_t replylen = sizeof(reply) - 1; wpagui->ctrlRequest("WPS_ER_START", reply, &replylen); add_stations(); add_scan_results(); add_persistent_groups(); } QStandardItem * Peers::find_addr(QString addr) { if (model.rowCount() == 0) return NULL; QModelIndexList lst = model.match(model.index(0, 0), peer_role_address, addr); if (lst.size() == 0) return NULL; return model.itemFromIndex(lst[0]); } QStandardItem * Peers::find_addr_type(QString addr, int type) { if (model.rowCount() == 0) return NULL; QModelIndexList lst = model.match(model.index(0, 0), peer_role_address, addr); for (int i = 0; i < lst.size(); i++) { QStandardItem *item = model.itemFromIndex(lst[i]); if (item->data(peer_role_type).toInt() == type) return item; } return NULL; } QStandardItem * Peers::find_uuid(QString uuid) { if (model.rowCount() == 0) return NULL; QModelIndexList lst = model.match(model.index(0, 0), peer_role_uuid, uuid); if (lst.size() == 0) return NULL; return model.itemFromIndex(lst[0]); } void Peers::event_notify(WpaMsg msg) { QString text = msg.getMsg(); if (text.startsWith(WPS_EVENT_PIN_NEEDED)) { /* * WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7 * 02:2a:c4:18:5b:f3 * [Wireless Client|Company|cmodel|123|12345|1-0050F204-1] */ QStringList items = text.split(' '); QString uuid = items[1]; QString addr = items[2]; QString name = ""; QStandardItem *item = find_addr(addr); if (item) return; int pos = text.indexOf('['); if (pos >= 0) { int pos2 = text.lastIndexOf(']'); if (pos2 >= pos) { items = text.mid(pos + 1, pos2 - pos - 1). split('|'); name = items[0]; items.append(addr); } } item = new QStandardItem(*laptop_icon, name); if (item) { item->setData(addr, peer_role_address); item->setData(PEER_TYPE_WPS_PIN_NEEDED, peer_role_type); item->setToolTip(ItemType(PEER_TYPE_WPS_PIN_NEEDED)); item->setData(items.join("\n"), peer_role_details); item->setData(items[5], peer_role_pri_dev_type); model.appendRow(item); } return; } if (text.startsWith(AP_STA_CONNECTED)) { /* AP-STA-CONNECTED 02:2a:c4:18:5b:f3 */ QStringList items = text.split(' '); QString addr = items[1]; QStandardItem *item = find_addr(addr); if (item == NULL || item->data(peer_role_type).toInt() != PEER_TYPE_ASSOCIATED_STATION) add_single_station(addr.toAscii().constData()); return; } if (text.startsWith(AP_STA_DISCONNECTED)) { /* AP-STA-DISCONNECTED 02:2a:c4:18:5b:f3 */ QStringList items = text.split(' '); QString addr = items[1]; if (model.rowCount() == 0) return; QModelIndexList lst = model.match(model.index(0, 0), peer_role_address, addr, -1); for (int i = 0; i < lst.size(); i++) { QStandardItem *item = model.itemFromIndex(lst[i]); if (item && item->data(peer_role_type).toInt() == PEER_TYPE_ASSOCIATED_STATION) { model.removeRow(lst[i].row()); break; } } return; } if (text.startsWith(P2P_EVENT_DEVICE_FOUND)) { /* * P2P-DEVICE-FOUND 02:b5:64:63:30:63 * p2p_dev_addr=02:b5:64:63:30:63 pri_dev_type=1-0050f204-1 * name='Wireless Client' config_methods=0x84 dev_capab=0x21 * group_capab=0x0 */ QStringList items = text.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)")); QString addr = items[1]; QString name = ""; QString pri_dev_type; int config_methods = 0; for (int i = 0; i < items.size(); i++) { QString str = items.at(i); if (str.startsWith("name='")) name = str.section('\'', 1, -2); else if (str.startsWith("config_methods=")) config_methods = str.section('=', 1).toInt(0, 0); else if (str.startsWith("pri_dev_type=")) pri_dev_type = str.section('=', 1); } QStandardItem *item = find_addr(addr); if (item) { int type = item->data(peer_role_type).toInt(); if (type == PEER_TYPE_P2P) return; } item = new QStandardItem(*default_icon, name); if (item) { item->setData(addr, peer_role_address); item->setData(config_methods, peer_role_config_methods); item->setData(PEER_TYPE_P2P, peer_role_type); if (!pri_dev_type.isEmpty()) item->setData(pri_dev_type, peer_role_pri_dev_type); item->setData(items.join(QString("\n")), peer_role_details); item->setToolTip(ItemType(PEER_TYPE_P2P)); model.appendRow(item); } item = find_addr_type(addr, PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT); if (item) item->setBackground(Qt::NoBrush); } if (text.startsWith(P2P_EVENT_GROUP_STARTED)) { /* P2P-GROUP-STARTED wlan0-p2p-0 GO ssid="DIRECT-3F" * passphrase="YOyTkxID" go_dev_addr=02:40:61:c2:f3:b7 * [PERSISTENT] */ QStringList items = text.split(' '); if (items.size() < 4) return; int pos = text.indexOf(" ssid=\""); if (pos < 0) return; QString ssid = text.mid(pos + 7); pos = ssid.indexOf(" passphrase=\""); if (pos < 0) pos = ssid.indexOf(" psk="); if (pos >= 0) ssid.truncate(pos); pos = ssid.lastIndexOf('"'); if (pos >= 0) ssid.truncate(pos); QStandardItem *item = new QStandardItem(*group_icon, ssid); if (item) { item->setData(PEER_TYPE_P2P_GROUP, peer_role_type); item->setData(items[1], peer_role_ifname); QString details; if (items[2] == "GO") { details = tr("P2P GO for interface ") + items[1]; } else { details = tr("P2P client for interface ") + items[1]; } if (text.contains(" [PERSISTENT]")) details += "\nPersistent group"; item->setData(details, peer_role_details); item->setToolTip(ItemType(PEER_TYPE_P2P_GROUP)); model.appendRow(item); } } if (text.startsWith(P2P_EVENT_GROUP_REMOVED)) { /* P2P-GROUP-REMOVED wlan0-p2p-0 GO */ QStringList items = text.split(' '); if (items.size() < 2) return; if (model.rowCount() == 0) return; QModelIndexList lst = model.match(model.index(0, 0), peer_role_ifname, items[1]); for (int i = 0; i < lst.size(); i++) model.removeRow(lst[i].row()); return; } if (text.startsWith(P2P_EVENT_PROV_DISC_SHOW_PIN)) { /* P2P-PROV-DISC-SHOW-PIN 02:40:61:c2:f3:b7 12345670 */ QStringList items = text.split(' '); if (items.size() < 3) return; QString addr = items[1]; QString pin = items[2]; QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P); if (item == NULL) return; item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY, peer_role_selected_method); item->setData(pin, peer_role_selected_pin); QVariant var = item->data(peer_role_requested_method); if (var.isValid() && var.toInt() == SEL_METHOD_PIN_LOCAL_DISPLAY) { ctx_item = item; ctx_p2p_display_pin_pd(); } return; } if (text.startsWith(P2P_EVENT_PROV_DISC_ENTER_PIN)) { /* P2P-PROV-DISC-ENTER-PIN 02:40:61:c2:f3:b7 */ QStringList items = text.split(' '); if (items.size() < 2) return; QString addr = items[1]; QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P); if (item == NULL) return; item->setData(SEL_METHOD_PIN_PEER_DISPLAY, peer_role_selected_method); QVariant var = item->data(peer_role_requested_method); if (var.isValid() && var.toInt() == SEL_METHOD_PIN_PEER_DISPLAY) { ctx_item = item; ctx_p2p_connect(); } return; } if (text.startsWith(P2P_EVENT_INVITATION_RECEIVED)) { /* P2P-INVITATION-RECEIVED sa=02:f0:bc:44:87:62 persistent=4 */ QStringList items = text.split(' '); if (items.size() < 3) return; if (!items[1].startsWith("sa=") || !items[2].startsWith("persistent=")) return; QString addr = items[1].mid(3); int id = items[2].mid(11).toInt(); char cmd[100]; char reply[100]; size_t reply_len; snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) return; reply[reply_len] = '\0'; QString name; char *pos = strrchr(reply, '"'); if (pos && reply[0] == '"') { *pos = '\0'; name = reply + 1; } else name = reply; QStandardItem *item; item = find_addr_type(addr, PEER_TYPE_P2P_INVITATION); if (item) model.removeRow(item->row()); item = new QStandardItem(*invitation_icon, name); if (!item) return; item->setData(PEER_TYPE_P2P_INVITATION, peer_role_type); item->setToolTip(ItemType(PEER_TYPE_P2P_INVITATION)); item->setData(addr, peer_role_address); item->setData(id, peer_role_network_id); model.appendRow(item); enable_persistent(id); return; } if (text.startsWith(P2P_EVENT_INVITATION_RESULT)) { /* P2P-INVITATION-RESULT status=1 */ /* TODO */ return; } if (text.startsWith(WPS_EVENT_ER_AP_ADD)) { /* * WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002 * 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1 * |Very friendly name|Company|Long description of the model| * WAP|http://w1.fi/|http://w1.fi/hostapd/ */ QStringList items = text.split(' '); if (items.size() < 5) return; QString uuid = items[1]; QString addr = items[2]; QString pri_dev_type = items[3].mid(13); int wps_state = items[4].mid(10).toInt(); int pos = text.indexOf('|'); if (pos < 0) return; items = text.mid(pos + 1).split('|'); if (items.size() < 1) return; QStandardItem *item = find_uuid(uuid); if (item) return; item = new QStandardItem(*ap_icon, items[0]); if (item) { item->setData(uuid, peer_role_uuid); item->setData(addr, peer_role_address); int type = wps_state == 2 ? PEER_TYPE_WPS_ER_AP: PEER_TYPE_WPS_ER_AP_UNCONFIGURED; item->setData(type, peer_role_type); item->setToolTip(ItemType(type)); item->setData(pri_dev_type, peer_role_pri_dev_type); item->setData(items.join(QString("\n")), peer_role_details); model.appendRow(item); } return; } if (text.startsWith(WPS_EVENT_ER_AP_REMOVE)) { /* WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002 */ QStringList items = text.split(' '); if (items.size() < 2) return; if (model.rowCount() == 0) return; QModelIndexList lst = model.match(model.index(0, 0), peer_role_uuid, items[1]); for (int i = 0; i < lst.size(); i++) { QStandardItem *item = model.itemFromIndex(lst[i]); if (item && (item->data(peer_role_type).toInt() == PEER_TYPE_WPS_ER_AP || item->data(peer_role_type).toInt() == PEER_TYPE_WPS_ER_AP_UNCONFIGURED)) model.removeRow(lst[i].row()); } return; } if (text.startsWith(WPS_EVENT_ER_ENROLLEE_ADD)) { /* * WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333 * 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0 * pri_dev_type=1-0050F204-1 * |Wireless Client|Company|cmodel|123|12345| */ QStringList items = text.split(' '); if (items.size() < 3) return; QString uuid = items[1]; QString addr = items[2]; QString pri_dev_type = items[6].mid(13); int config_methods = -1; int dev_passwd_id = -1; for (int i = 3; i < items.size(); i++) { int pos = items[i].indexOf('=') + 1; if (pos < 1) continue; QString val = items[i].mid(pos); if (items[i].startsWith("config_methods=")) { config_methods = val.toInt(0, 0); } else if (items[i].startsWith("dev_passwd_id=")) { dev_passwd_id = val.toInt(); } } int pos = text.indexOf('|'); if (pos < 0) return; items = text.mid(pos + 1).split('|'); if (items.size() < 1) return; QString name = items[0]; if (name.length() == 0) name = addr; remove_enrollee_uuid(uuid); QStandardItem *item; item = new QStandardItem(*laptop_icon, name); if (item) { item->setData(uuid, peer_role_uuid); item->setData(addr, peer_role_address); item->setData(PEER_TYPE_WPS_ER_ENROLLEE, peer_role_type); item->setToolTip(ItemType(PEER_TYPE_WPS_ER_ENROLLEE)); item->setData(items.join(QString("\n")), peer_role_details); item->setData(pri_dev_type, peer_role_pri_dev_type); if (config_methods >= 0) item->setData(config_methods, peer_role_config_methods); if (dev_passwd_id >= 0) item->setData(dev_passwd_id, peer_role_dev_passwd_id); model.appendRow(item); } return; } if (text.startsWith(WPS_EVENT_ER_ENROLLEE_REMOVE)) { /* * WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333 * 02:66:a0:ee:17:27 */ QStringList items = text.split(' '); if (items.size() < 2) return; remove_enrollee_uuid(items[1]); return; } if (text.startsWith(WPS_EVENT_ENROLLEE_SEEN)) { /* TODO: need to time out this somehow or remove on successful * WPS run, etc. */ /* * WPS-ENROLLEE-SEEN 02:00:00:00:01:00 * 572cf82f-c957-5653-9b16-b5cfb298abf1 1-0050F204-1 0x80 4 1 * [Wireless Client] * (MAC addr, UUID-E, pri dev type, config methods, * dev passwd id, request type, [dev name]) */ QStringList items = text.split(' '); if (items.size() < 7) return; QString addr = items[1]; QString uuid = items[2]; QString pri_dev_type = items[3]; int config_methods = items[4].toInt(0, 0); int dev_passwd_id = items[5].toInt(); QString name; QStandardItem *item = find_addr(addr); if (item) { int type = item->data(peer_role_type).toInt(); if (type == PEER_TYPE_ASSOCIATED_STATION) return; /* already associated */ } int pos = text.indexOf('['); if (pos >= 0) { int pos2 = text.lastIndexOf(']'); if (pos2 >= pos) { QStringList items2 = text.mid(pos + 1, pos2 - pos - 1). split('|'); name = items2[0]; } } if (name.isEmpty()) name = addr; item = find_uuid(uuid); if (item) { QVariant var = item->data(peer_role_config_methods); QVariant var2 = item->data(peer_role_dev_passwd_id); if ((var.isValid() && config_methods != var.toInt()) || (var2.isValid() && dev_passwd_id != var2.toInt())) remove_enrollee_uuid(uuid); else return; } item = new QStandardItem(*laptop_icon, name); if (item) { item->setData(uuid, peer_role_uuid); item->setData(addr, peer_role_address); item->setData(PEER_TYPE_WPS_ENROLLEE, peer_role_type); item->setToolTip(ItemType(PEER_TYPE_WPS_ENROLLEE)); item->setData(items.join(QString("\n")), peer_role_details); item->setData(pri_dev_type, peer_role_pri_dev_type); item->setData(config_methods, peer_role_config_methods); item->setData(dev_passwd_id, peer_role_dev_passwd_id); model.appendRow(item); } return; } if (text.startsWith(WPA_EVENT_BSS_ADDED)) { /* CTRL-EVENT-BSS-ADDED 34 00:11:22:33:44:55 */ QStringList items = text.split(' '); if (items.size() < 2) return; char cmd[20]; snprintf(cmd, sizeof(cmd), "BSS ID-%d", items[1].toInt()); add_bss(cmd); return; } if (text.startsWith(WPA_EVENT_BSS_REMOVED)) { /* CTRL-EVENT-BSS-REMOVED 34 00:11:22:33:44:55 */ QStringList items = text.split(' '); if (items.size() < 2) return; remove_bss(items[1].toInt()); return; } } void Peers::ctx_p2p_connect() { if (ctx_item == NULL) return; QString addr = ctx_item->data(peer_role_address).toString(); QString arg; int config_methods = ctx_item->data(peer_role_config_methods).toInt(); enum selected_method method = SEL_METHOD_NONE; QVariant var = ctx_item->data(peer_role_selected_method); if (var.isValid()) method = (enum selected_method) var.toInt(); if (method == SEL_METHOD_PIN_LOCAL_DISPLAY) { arg = ctx_item->data(peer_role_selected_pin).toString(); char cmd[100]; char reply[100]; size_t reply_len; snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display", addr.toAscii().constData(), arg.toAscii().constData()); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText("Failed to initiate P2P connect."); msg.exec(); return; } QMessageBox::information(this, tr("PIN for ") + ctx_item->text(), tr("Enter the following PIN on the\n" "peer device: ") + arg); } else if (method == SEL_METHOD_PIN_PEER_DISPLAY) { StringQuery input(tr("PIN from peer display:")); input.setWindowTitle(tr("PIN for ") + ctx_item->text()); if (input.exec() != QDialog::Accepted) return; arg = input.get_string(); } else if (config_methods == 0x0080 /* PBC */) { arg = "pbc"; } else { StringQuery input(tr("PIN:")); input.setWindowTitle(tr("PIN for ") + ctx_item->text()); if (input.exec() != QDialog::Accepted) return; arg = input.get_string(); } char cmd[100]; char reply[100]; size_t reply_len; snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s", addr.toAscii().constData(), arg.toAscii().constData()); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText("Failed to initiate P2P connect."); msg.exec(); } } void Peers::ctx_p2p_req_pin() { if (ctx_item == NULL) return; QString addr = ctx_item->data(peer_role_address).toString(); ctx_item->setData(SEL_METHOD_PIN_PEER_DISPLAY, peer_role_requested_method); char cmd[100]; char reply[100]; size_t reply_len; snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s display", addr.toAscii().constData()); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText(tr("Failed to request PIN from peer.")); msg.exec(); } } void Peers::ctx_p2p_show_pin() { if (ctx_item == NULL) return; QString addr = ctx_item->data(peer_role_address).toString(); ctx_item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY, peer_role_requested_method); char cmd[100]; char reply[100]; size_t reply_len; snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s keypad", addr.toAscii().constData()); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText(tr("Failed to request peer to enter PIN.")); msg.exec(); } } void Peers::ctx_p2p_display_pin() { if (ctx_item == NULL) return; QString addr = ctx_item->data(peer_role_address).toString(); char cmd[100]; char reply[100]; size_t reply_len; snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pin", addr.toAscii().constData()); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText("Failed to initiate P2P connect."); msg.exec(); return; } reply[reply_len] = '\0'; QMessageBox::information(this, tr("PIN for ") + ctx_item->text(), tr("Enter the following PIN on the\n" "peer device: ") + reply); } void Peers::ctx_p2p_display_pin_pd() { if (ctx_item == NULL) return; QString addr = ctx_item->data(peer_role_address).toString(); QString arg = ctx_item->data(peer_role_selected_pin).toString(); char cmd[100]; char reply[100]; size_t reply_len; snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display", addr.toAscii().constData(), arg.toAscii().constData()); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText("Failed to initiate P2P connect."); msg.exec(); return; } reply[reply_len] = '\0'; QMessageBox::information(this, tr("PIN for ") + ctx_item->text(), tr("Enter the following PIN on the\n" "peer device: ") + arg); } void Peers::ctx_p2p_enter_pin() { if (ctx_item == NULL) return; QString addr = ctx_item->data(peer_role_address).toString(); QString arg; StringQuery input(tr("PIN from peer:")); input.setWindowTitle(tr("PIN for ") + ctx_item->text()); if (input.exec() != QDialog::Accepted) return; arg = input.get_string(); char cmd[100]; char reply[100]; size_t reply_len; snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s keypad", addr.toAscii().constData(), arg.toAscii().constData()); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText("Failed to initiate P2P connect."); msg.exec(); } } void Peers::ctx_p2p_remove_group() { if (ctx_item == NULL) return; char cmd[100]; char reply[100]; size_t reply_len; snprintf(cmd, sizeof(cmd), "P2P_GROUP_REMOVE %s", ctx_item->data(peer_role_ifname).toString().toAscii(). constData()); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText("Failed to remove P2P Group."); msg.exec(); } } void Peers::closeEvent(QCloseEvent *) { if (wpagui) { char reply[20]; size_t replylen = sizeof(reply) - 1; wpagui->ctrlRequest("WPS_ER_STOP", reply, &replylen); } } void Peers::done(int r) { QDialog::done(r); close(); } void Peers::remove_enrollee_uuid(QString uuid) { if (model.rowCount() == 0) return; QModelIndexList lst = model.match(model.index(0, 0), peer_role_uuid, uuid); for (int i = 0; i < lst.size(); i++) { QStandardItem *item = model.itemFromIndex(lst[i]); if (item == NULL) continue; int type = item->data(peer_role_type).toInt(); if (type == PEER_TYPE_WPS_ER_ENROLLEE || type == PEER_TYPE_WPS_ENROLLEE) model.removeRow(lst[i].row()); } } void Peers::properties() { if (ctx_item == NULL) return; QMessageBox msg(this); msg.setStandardButtons(QMessageBox::Ok); msg.setDefaultButton(QMessageBox::Ok); msg.setEscapeButton(QMessageBox::Ok); msg.setWindowTitle(tr("Peer Properties")); int type = ctx_item->data(peer_role_type).toInt(); QString title = Peers::ItemType(type); msg.setText(title + QString("\n") + tr("Name: ") + ctx_item->text()); QVariant var; QString info; var = ctx_item->data(peer_role_address); if (var.isValid()) info += tr("Address: ") + var.toString() + QString("\n"); var = ctx_item->data(peer_role_uuid); if (var.isValid()) info += tr("UUID: ") + var.toString() + QString("\n"); var = ctx_item->data(peer_role_pri_dev_type); if (var.isValid()) info += tr("Primary Device Type: ") + var.toString() + QString("\n"); var = ctx_item->data(peer_role_ssid); if (var.isValid()) info += tr("SSID: ") + var.toString() + QString("\n"); var = ctx_item->data(peer_role_config_methods); if (var.isValid()) { int methods = var.toInt(); info += tr("Configuration Methods: "); if (methods & 0x0001) info += tr("[USBA]"); if (methods & 0x0002) info += tr("[Ethernet]"); if (methods & 0x0004) info += tr("[Label]"); if (methods & 0x0008) info += tr("[Display]"); if (methods & 0x0010) info += tr("[Ext. NFC Token]"); if (methods & 0x0020) info += tr("[Int. NFC Token]"); if (methods & 0x0040) info += tr("[NFC Interface]"); if (methods & 0x0080) info += tr("[Push Button]"); if (methods & 0x0100) info += tr("[Keypad]"); info += "\n"; } var = ctx_item->data(peer_role_selected_method); if (var.isValid()) { enum selected_method method = (enum selected_method) var.toInt(); switch (method) { case SEL_METHOD_NONE: break; case SEL_METHOD_PIN_PEER_DISPLAY: info += tr("Selected Method: PIN on peer display\n"); break; case SEL_METHOD_PIN_LOCAL_DISPLAY: info += tr("Selected Method: PIN on local display\n"); break; } } var = ctx_item->data(peer_role_selected_pin); if (var.isValid()) { info += tr("PIN to enter on peer: ") + var.toString() + "\n"; } var = ctx_item->data(peer_role_dev_passwd_id); if (var.isValid()) { info += tr("Device Password ID: ") + var.toString(); switch (var.toInt()) { case 0: info += tr(" (Default PIN)"); break; case 1: info += tr(" (User-specified PIN)"); break; case 2: info += tr(" (Machine-specified PIN)"); break; case 3: info += tr(" (Rekey)"); break; case 4: info += tr(" (Push Button)"); break; case 5: info += tr(" (Registrar-specified)"); break; } info += "\n"; } msg.setInformativeText(info); var = ctx_item->data(peer_role_details); if (var.isValid()) msg.setDetailedText(var.toString()); msg.exec(); } void Peers::connect_pbc() { if (ctx_item == NULL) return; char cmd[100]; char reply[100]; size_t reply_len; int peer_type = ctx_item->data(peer_role_type).toInt(); if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) { snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s", ctx_item->data(peer_role_uuid).toString().toAscii(). constData()); } else if (peer_type == PEER_TYPE_P2P || peer_type == PEER_TYPE_P2P_CLIENT) { snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pbc", ctx_item->data(peer_role_address).toString(). toAscii().constData()); } else { snprintf(cmd, sizeof(cmd), "WPS_PBC"); } reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText(tr("Failed to start WPS PBC.")); msg.exec(); } } void Peers::learn_ap_config() { if (ctx_item == NULL) return; QString uuid = ctx_item->data(peer_role_uuid).toString(); StringQuery input(tr("AP PIN:")); input.setWindowTitle(tr("AP PIN for ") + ctx_item->text()); if (input.exec() != QDialog::Accepted) return; char cmd[100]; char reply[100]; size_t reply_len; snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s", uuid.toAscii().constData(), input.get_string().toAscii().constData()); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText(tr("Failed to start learning AP configuration.")); msg.exec(); } } void Peers::ctx_hide_ap() { hide_ap = true; if (model.rowCount() == 0) return; do { QModelIndexList lst; lst = model.match(model.index(0, 0), peer_role_type, PEER_TYPE_AP); if (lst.size() == 0) { lst = model.match(model.index(0, 0), peer_role_type, PEER_TYPE_AP_WPS); if (lst.size() == 0) break; } model.removeRow(lst[0].row()); } while (1); } void Peers::ctx_show_ap() { hide_ap = false; add_scan_results(); } void Peers::ctx_p2p_show_passphrase() { char reply[64]; size_t reply_len; reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest("P2P_GET_PASSPHRASE", reply, &reply_len) < 0 || memcmp(reply, "FAIL", 4) == 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText("Failed to get P2P group passphrase."); msg.exec(); } else { reply[reply_len] = '\0'; QMessageBox::information(this, tr("Passphrase"), tr("P2P group passphrase:\n") + reply); } } void Peers::ctx_p2p_start_persistent() { if (ctx_item == NULL) return; char cmd[100]; char reply[100]; size_t reply_len; snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD persistent=%d", ctx_item->data(peer_role_network_id).toInt()); if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 || memcmp(reply, "FAIL", 4) == 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText(tr("Failed to start persistent P2P Group.")); msg.exec(); } else if (ctx_item->data(peer_role_type).toInt() == PEER_TYPE_P2P_INVITATION) model.removeRow(ctx_item->row()); } void Peers::ctx_p2p_invite() { if (ctx_item == NULL) return; char cmd[100]; char reply[100]; size_t reply_len; snprintf(cmd, sizeof(cmd), "P2P_INVITE persistent=%d", ctx_item->data(peer_role_network_id).toInt()); if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 || memcmp(reply, "FAIL", 4) == 0) { QMessageBox msg; msg.setIcon(QMessageBox::Warning); msg.setText(tr("Failed to invite peer to start persistent " "P2P Group.")); msg.exec(); } } void Peers::ctx_p2p_delete() { if (ctx_item == NULL) return; model.removeRow(ctx_item->row()); } void Peers::enable_persistent(int id) { if (model.rowCount() == 0) return; QModelIndexList lst = model.match(model.index(0, 0), peer_role_network_id, id); for (int i = 0; i < lst.size(); i++) { QStandardItem *item = model.itemFromIndex(lst[i]); int type = item->data(peer_role_type).toInt(); if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO || type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT) item->setBackground(Qt::NoBrush); } } wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp0000664000175000017500000000451712343617166022667 0ustar jmjm/* * wpa_gui - EventHistory class * Copyright (c) 2005-2006, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include #include #include "eventhistory.h" int EventListModel::rowCount(const QModelIndex &) const { return msgList.count(); } int EventListModel::columnCount(const QModelIndex &) const { return 2; } QVariant EventListModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (role == Qt::DisplayRole) if (index.column() == 0) { if (index.row() >= timeList.size()) return QVariant(); return timeList.at(index.row()); } else { if (index.row() >= msgList.size()) return QVariant(); return msgList.at(index.row()); } else return QVariant(); } QVariant EventListModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); if (orientation == Qt::Horizontal) { switch (section) { case 0: return QString(tr("Timestamp")); case 1: return QString(tr("Message")); default: return QVariant(); } } else return QString("%1").arg(section); } void EventListModel::addEvent(QString time, QString msg) { beginInsertRows(QModelIndex(), msgList.size(), msgList.size() + 1); timeList << time; msgList << msg; endInsertRows(); } EventHistory::EventHistory(QWidget *parent, const char *, bool, Qt::WFlags) : QDialog(parent) { setupUi(this); connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); eventListView->setItemsExpandable(FALSE); eventListView->setRootIsDecorated(FALSE); elm = new EventListModel(parent); eventListView->setModel(elm); } EventHistory::~EventHistory() { destroy(); delete elm; } void EventHistory::languageChange() { retranslateUi(this); } void EventHistory::addEvents(WpaMsgList msgs) { WpaMsgList::iterator it; for (it = msgs.begin(); it != msgs.end(); it++) addEvent(*it); } void EventHistory::addEvent(WpaMsg msg) { bool scroll = true; if (eventListView->verticalScrollBar()->value() < eventListView->verticalScrollBar()->maximum()) scroll = false; elm->addEvent(msg.getTimestamp().toString("yyyy-MM-dd hh:mm:ss.zzz"), msg.getMsg()); if (scroll) eventListView->scrollToBottom(); } wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/main.cpp0000664000175000017500000000300412343617166021036 0ustar jmjm/* * wpa_gui - Application startup * Copyright (c) 2005-2006, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifdef CONFIG_NATIVE_WINDOWS #include #endif /* CONFIG_NATIVE_WINDOWS */ #include #include #include #include "wpagui.h" class WpaGuiApp : public QApplication { public: WpaGuiApp(int &argc, char **argv); #ifndef QT_NO_SESSIONMANAGER virtual void saveState(QSessionManager &manager); #endif WpaGui *w; }; WpaGuiApp::WpaGuiApp(int &argc, char **argv) : QApplication(argc, argv) { } #ifndef QT_NO_SESSIONMANAGER void WpaGuiApp::saveState(QSessionManager &manager) { QApplication::saveState(manager); w->saveState(); } #endif int main(int argc, char *argv[]) { WpaGuiApp app(argc, argv); QTranslator translator; QString locale; QString resourceDir; int ret; locale = QLocale::system().name(); resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); if (!translator.load("wpa_gui_" + locale, resourceDir)) translator.load("wpa_gui_" + locale, "lang"); app.installTranslator(&translator); WpaGui w(&app); #ifdef CONFIG_NATIVE_WINDOWS WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { /* printf("Could not find a usable WinSock.dll\n"); */ return -1; } #endif /* CONFIG_NATIVE_WINDOWS */ app.w = &w; ret = app.exec(); #ifdef CONFIG_NATIVE_WINDOWS WSACleanup(); #endif /* CONFIG_NATIVE_WINDOWS */ return ret; } wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/peers.h0000664000175000017500000000442212343617166020702 0ustar jmjm/* * wpa_gui - Peers class * Copyright (c) 2009-2010, Atheros Communications * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef PEERS_H #define PEERS_H #include #include #include "wpamsg.h" #include "ui_peers.h" class WpaGui; class Peers : public QDialog, public Ui::Peers { Q_OBJECT public: Peers(QWidget *parent = 0, const char *name = 0, bool modal = false, Qt::WFlags fl = 0); ~Peers(); void setWpaGui(WpaGui *_wpagui); void event_notify(WpaMsg msg); public slots: virtual void context_menu(const QPoint &pos); virtual void enter_pin(); virtual void connect_pbc(); virtual void learn_ap_config(); virtual void ctx_refresh(); virtual void ctx_p2p_start(); virtual void ctx_p2p_stop(); virtual void ctx_p2p_listen(); virtual void ctx_p2p_start_group(); virtual void ctx_p2p_remove_group(); virtual void ctx_p2p_connect(); virtual void ctx_p2p_req_pin(); virtual void ctx_p2p_show_pin(); virtual void ctx_p2p_display_pin(); virtual void ctx_p2p_display_pin_pd(); virtual void ctx_p2p_enter_pin(); virtual void properties(); virtual void ctx_hide_ap(); virtual void ctx_show_ap(); virtual void ctx_p2p_show_passphrase(); virtual void ctx_p2p_start_persistent(); virtual void ctx_p2p_invite(); virtual void ctx_p2p_delete(); protected slots: virtual void languageChange(); virtual void closeEvent(QCloseEvent *event); private: void add_station(QString info); void add_stations(); void add_single_station(const char *addr); bool add_bss(const char *cmd); void remove_bss(int id); void add_scan_results(); void add_persistent(int id, const char *ssid, const char *bssid); void add_persistent_groups(); void update_peers(); QStandardItem * find_addr(QString addr); QStandardItem * find_addr_type(QString addr, int type); void add_p2p_group_client(QStandardItem *parent, QString params); QStandardItem * find_uuid(QString uuid); void done(int r); void remove_enrollee_uuid(QString uuid); QString ItemType(int type); void enable_persistent(int id); WpaGui *wpagui; QStandardItemModel model; QIcon *default_icon; QIcon *ap_icon; QIcon *laptop_icon; QIcon *group_icon; QIcon *invitation_icon; QStandardItem *ctx_item; bool hide_ap; }; #endif /* PEERS_H */ wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/icons_png.qrc0000664000175000017500000000062712343617166022104 0ustar jmjm icons/hicolor/16x16/apps/wpa_gui.png icons/hicolor/32x32/apps/ap.png icons/hicolor/32x32/apps/laptop.png icons/hicolor/32x32/apps/group.png icons/hicolor/32x32/apps/invitation.png wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/wpagui.cpp0000664000175000017500000011615012343617166021415 0ustar jmjm/* * wpa_gui - WpaGui class * Copyright (c) 2005-2011, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifdef CONFIG_NATIVE_WINDOWS #include #endif /* CONFIG_NATIVE_WINDOWS */ #include #include #include #include #include #include #include "wpagui.h" #include "dirent.h" #include "common/wpa_ctrl.h" #include "userdatarequest.h" #include "networkconfig.h" #if 1 /* Silence stdout */ #define printf wpagui_printf static int wpagui_printf(const char *, ...) { return 0; } #endif WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, Qt::WFlags) : QMainWindow(parent), app(_app) { setupUi(this); #ifdef CONFIG_NATIVE_WINDOWS fileStopServiceAction = new QAction(this); fileStopServiceAction->setObjectName("Stop Service"); fileStopServiceAction->setIconText(tr("Stop Service")); fileMenu->insertAction(actionWPS, fileStopServiceAction); fileStartServiceAction = new QAction(this); fileStartServiceAction->setObjectName("Start Service"); fileStartServiceAction->setIconText(tr("Start Service")); fileMenu->insertAction(fileStopServiceAction, fileStartServiceAction); connect(fileStartServiceAction, SIGNAL(triggered()), this, SLOT(startService())); connect(fileStopServiceAction, SIGNAL(triggered()), this, SLOT(stopService())); addInterfaceAction = new QAction(this); addInterfaceAction->setIconText(tr("Add Interface")); fileMenu->insertAction(fileStartServiceAction, addInterfaceAction); connect(addInterfaceAction, SIGNAL(triggered()), this, SLOT(addInterface())); #endif /* CONFIG_NATIVE_WINDOWS */ (void) statusBar(); /* * Disable WPS tab by default; it will be enabled if wpa_supplicant is * built with WPS support. */ wpsTab->setEnabled(false); wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), false); connect(fileEventHistoryAction, SIGNAL(triggered()), this, SLOT(eventHistory())); connect(fileSaveConfigAction, SIGNAL(triggered()), this, SLOT(saveConfig())); connect(actionWPS, SIGNAL(triggered()), this, SLOT(wpsDialog())); connect(actionPeers, SIGNAL(triggered()), this, SLOT(peersDialog())); connect(fileExitAction, SIGNAL(triggered()), qApp, SLOT(quit())); connect(networkAddAction, SIGNAL(triggered()), this, SLOT(addNetwork())); connect(networkEditAction, SIGNAL(triggered()), this, SLOT(editSelectedNetwork())); connect(networkRemoveAction, SIGNAL(triggered()), this, SLOT(removeSelectedNetwork())); connect(networkEnableAllAction, SIGNAL(triggered()), this, SLOT(enableAllNetworks())); connect(networkDisableAllAction, SIGNAL(triggered()), this, SLOT(disableAllNetworks())); connect(networkRemoveAllAction, SIGNAL(triggered()), this, SLOT(removeAllNetworks())); connect(helpIndexAction, SIGNAL(triggered()), this, SLOT(helpIndex())); connect(helpContentsAction, SIGNAL(triggered()), this, SLOT(helpContents())); connect(helpAboutAction, SIGNAL(triggered()), this, SLOT(helpAbout())); connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect())); connect(scanButton, SIGNAL(clicked()), this, SLOT(scan())); connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB())); connect(adapterSelect, SIGNAL(activated(const QString&)), this, SLOT(selectAdapter(const QString&))); connect(networkSelect, SIGNAL(activated(const QString&)), this, SLOT(selectNetwork(const QString&))); connect(addNetworkButton, SIGNAL(clicked()), this, SLOT(addNetwork())); connect(editNetworkButton, SIGNAL(clicked()), this, SLOT(editListedNetwork())); connect(removeNetworkButton, SIGNAL(clicked()), this, SLOT(removeListedNetwork())); connect(networkList, SIGNAL(itemSelectionChanged()), this, SLOT(updateNetworkDisabledStatus())); connect(enableRadioButton, SIGNAL(toggled(bool)), this, SLOT(enableListedNetwork(bool))); connect(disableRadioButton, SIGNAL(toggled(bool)), this, SLOT(disableListedNetwork(bool))); connect(scanNetworkButton, SIGNAL(clicked()), this, SLOT(scan())); connect(networkList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(editListedNetwork())); connect(wpaguiTab, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int))); connect(wpsPbcButton, SIGNAL(clicked()), this, SLOT(wpsPbc())); connect(wpsPinButton, SIGNAL(clicked()), this, SLOT(wpsGeneratePin())); connect(wpsApPinEdit, SIGNAL(textChanged(const QString &)), this, SLOT(wpsApPinChanged(const QString &))); connect(wpsApPinButton, SIGNAL(clicked()), this, SLOT(wpsApPin())); eh = NULL; scanres = NULL; peers = NULL; add_iface = NULL; udr = NULL; tray_icon = NULL; startInTray = false; ctrl_iface = NULL; ctrl_conn = NULL; monitor_conn = NULL; msgNotifier = NULL; ctrl_iface_dir = strdup("/var/run/wpa_supplicant"); parse_argv(); #ifndef QT_NO_SESSIONMANAGER if (app->isSessionRestored()) { QSettings settings("wpa_supplicant", "wpa_gui"); settings.beginGroup("state"); if (app->sessionId().compare(settings.value("session_id"). toString()) == 0) startInTray = settings.value("in_tray").toBool(); settings.endGroup(); } #endif if (QSystemTrayIcon::isSystemTrayAvailable()) createTrayIcon(startInTray); else show(); connectedToService = false; textStatus->setText(tr("connecting to wpa_supplicant")); timer = new QTimer(this); connect(timer, SIGNAL(timeout()), SLOT(ping())); timer->setSingleShot(FALSE); timer->start(1000); if (openCtrlConnection(ctrl_iface) < 0) { printf("Failed to open control connection to " "wpa_supplicant.\n"); } updateStatus(); networkMayHaveChanged = true; updateNetworks(); } WpaGui::~WpaGui() { delete msgNotifier; if (monitor_conn) { wpa_ctrl_detach(monitor_conn); wpa_ctrl_close(monitor_conn); monitor_conn = NULL; } if (ctrl_conn) { wpa_ctrl_close(ctrl_conn); ctrl_conn = NULL; } if (eh) { eh->close(); delete eh; eh = NULL; } if (scanres) { scanres->close(); delete scanres; scanres = NULL; } if (peers) { peers->close(); delete peers; peers = NULL; } if (add_iface) { add_iface->close(); delete add_iface; add_iface = NULL; } if (udr) { udr->close(); delete udr; udr = NULL; } free(ctrl_iface); ctrl_iface = NULL; free(ctrl_iface_dir); ctrl_iface_dir = NULL; } void WpaGui::languageChange() { retranslateUi(this); } void WpaGui::parse_argv() { int c; for (;;) { c = getopt(qApp->argc(), qApp->argv(), "i:p:t"); if (c < 0) break; switch (c) { case 'i': free(ctrl_iface); ctrl_iface = strdup(optarg); break; case 'p': free(ctrl_iface_dir); ctrl_iface_dir = strdup(optarg); break; case 't': startInTray = true; break; } } } int WpaGui::openCtrlConnection(const char *ifname) { char *cfile; int flen; char buf[2048], *pos, *pos2; size_t len; if (ifname) { if (ifname != ctrl_iface) { free(ctrl_iface); ctrl_iface = strdup(ifname); } } else { #ifdef CONFIG_CTRL_IFACE_UDP free(ctrl_iface); ctrl_iface = strdup("udp"); #endif /* CONFIG_CTRL_IFACE_UDP */ #ifdef CONFIG_CTRL_IFACE_UNIX struct dirent *dent; DIR *dir = opendir(ctrl_iface_dir); free(ctrl_iface); ctrl_iface = NULL; if (dir) { while ((dent = readdir(dir))) { #ifdef _DIRENT_HAVE_D_TYPE /* Skip the file if it is not a socket. * Also accept DT_UNKNOWN (0) in case * the C library or underlying file * system does not support d_type. */ if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN) continue; #endif /* _DIRENT_HAVE_D_TYPE */ if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; printf("Selected interface '%s'\n", dent->d_name); ctrl_iface = strdup(dent->d_name); break; } closedir(dir); } #endif /* CONFIG_CTRL_IFACE_UNIX */ #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE struct wpa_ctrl *ctrl; int ret; free(ctrl_iface); ctrl_iface = NULL; ctrl = wpa_ctrl_open(NULL); if (ctrl) { len = sizeof(buf) - 1; ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL); if (ret >= 0) { connectedToService = true; buf[len] = '\0'; pos = strchr(buf, '\n'); if (pos) *pos = '\0'; ctrl_iface = strdup(buf); } wpa_ctrl_close(ctrl); } #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ } if (ctrl_iface == NULL) { #ifdef CONFIG_NATIVE_WINDOWS static bool first = true; if (first && !serviceRunning()) { first = false; if (QMessageBox::warning( this, qAppName(), tr("wpa_supplicant service is not " "running.\n" "Do you want to start it?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) startService(); } #endif /* CONFIG_NATIVE_WINDOWS */ return -1; } #ifdef CONFIG_CTRL_IFACE_UNIX flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2; cfile = (char *) malloc(flen); if (cfile == NULL) return -1; snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface); #else /* CONFIG_CTRL_IFACE_UNIX */ flen = strlen(ctrl_iface) + 1; cfile = (char *) malloc(flen); if (cfile == NULL) return -1; snprintf(cfile, flen, "%s", ctrl_iface); #endif /* CONFIG_CTRL_IFACE_UNIX */ if (ctrl_conn) { wpa_ctrl_close(ctrl_conn); ctrl_conn = NULL; } if (monitor_conn) { delete msgNotifier; msgNotifier = NULL; wpa_ctrl_detach(monitor_conn); wpa_ctrl_close(monitor_conn); monitor_conn = NULL; } printf("Trying to connect to '%s'\n", cfile); ctrl_conn = wpa_ctrl_open(cfile); if (ctrl_conn == NULL) { free(cfile); return -1; } monitor_conn = wpa_ctrl_open(cfile); free(cfile); if (monitor_conn == NULL) { wpa_ctrl_close(ctrl_conn); return -1; } if (wpa_ctrl_attach(monitor_conn)) { printf("Failed to attach to wpa_supplicant\n"); wpa_ctrl_close(monitor_conn); monitor_conn = NULL; wpa_ctrl_close(ctrl_conn); ctrl_conn = NULL; return -1; } #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn), QSocketNotifier::Read, this); connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs())); #endif adapterSelect->clear(); adapterSelect->addItem(ctrl_iface); adapterSelect->setCurrentIndex(0); len = sizeof(buf) - 1; if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= 0) { buf[len] = '\0'; pos = buf; while (*pos) { pos2 = strchr(pos, '\n'); if (pos2) *pos2 = '\0'; if (strcmp(pos, ctrl_iface) != 0) adapterSelect->addItem(pos); if (pos2) pos = pos2 + 1; else break; } } len = sizeof(buf) - 1; if (wpa_ctrl_request(ctrl_conn, "GET_CAPABILITY eap", 18, buf, &len, NULL) >= 0) { buf[len] = '\0'; QString res(buf); QStringList types = res.split(QChar(' ')); bool wps = types.contains("WSC"); actionWPS->setEnabled(wps); wpsTab->setEnabled(wps); wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), wps); } return 0; } int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen) { int ret; if (ctrl_conn == NULL) return -3; ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, NULL); if (ret == -2) printf("'%s' command timed out.\n", cmd); else if (ret < 0) printf("'%s' command failed.\n", cmd); return ret; } QString WpaGui::wpaStateTranslate(char *state) { if (!strcmp(state, "DISCONNECTED")) return tr("Disconnected"); else if (!strcmp(state, "INACTIVE")) return tr("Inactive"); else if (!strcmp(state, "SCANNING")) return tr("Scanning"); else if (!strcmp(state, "AUTHENTICATING")) return tr("Authenticating"); else if (!strcmp(state, "ASSOCIATING")) return tr("Associating"); else if (!strcmp(state, "ASSOCIATED")) return tr("Associated"); else if (!strcmp(state, "4WAY_HANDSHAKE")) return tr("4-Way Handshake"); else if (!strcmp(state, "GROUP_HANDSHAKE")) return tr("Group Handshake"); else if (!strcmp(state, "COMPLETED")) return tr("Completed"); else return tr("Unknown"); } void WpaGui::updateStatus() { char buf[2048], *start, *end, *pos; size_t len; pingsToStatusUpdate = 10; len = sizeof(buf) - 1; if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) { textStatus->setText(tr("Could not get status from " "wpa_supplicant")); textAuthentication->clear(); textEncryption->clear(); textSsid->clear(); textBssid->clear(); textIpAddress->clear(); #ifdef CONFIG_NATIVE_WINDOWS static bool first = true; if (first && connectedToService && (ctrl_iface == NULL || *ctrl_iface == '\0')) { first = false; if (QMessageBox::information( this, qAppName(), tr("No network interfaces in use.\n" "Would you like to add one?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) addInterface(); } #endif /* CONFIG_NATIVE_WINDOWS */ return; } buf[len] = '\0'; bool auth_updated = false, ssid_updated = false; bool bssid_updated = false, ipaddr_updated = false; bool status_updated = false; char *pairwise_cipher = NULL, *group_cipher = NULL; char *mode = NULL; start = buf; while (*start) { bool last = false; end = strchr(start, '\n'); if (end == NULL) { last = true; end = start; while (end[0] && end[1]) end++; } *end = '\0'; pos = strchr(start, '='); if (pos) { *pos++ = '\0'; if (strcmp(start, "bssid") == 0) { bssid_updated = true; textBssid->setText(pos); } else if (strcmp(start, "ssid") == 0) { ssid_updated = true; textSsid->setText(pos); } else if (strcmp(start, "ip_address") == 0) { ipaddr_updated = true; textIpAddress->setText(pos); } else if (strcmp(start, "wpa_state") == 0) { status_updated = true; textStatus->setText(wpaStateTranslate(pos)); } else if (strcmp(start, "key_mgmt") == 0) { auth_updated = true; textAuthentication->setText(pos); /* TODO: could add EAP status to this */ } else if (strcmp(start, "pairwise_cipher") == 0) { pairwise_cipher = pos; } else if (strcmp(start, "group_cipher") == 0) { group_cipher = pos; } else if (strcmp(start, "mode") == 0) { mode = pos; } } if (last) break; start = end + 1; } if (status_updated && mode) textStatus->setText(textStatus->text() + " (" + mode + ")"); if (pairwise_cipher || group_cipher) { QString encr; if (pairwise_cipher && group_cipher && strcmp(pairwise_cipher, group_cipher) != 0) { encr.append(pairwise_cipher); encr.append(" + "); encr.append(group_cipher); } else if (pairwise_cipher) { encr.append(pairwise_cipher); } else { encr.append(group_cipher); encr.append(" [group key only]"); } textEncryption->setText(encr); } else textEncryption->clear(); if (!status_updated) textStatus->clear(); if (!auth_updated) textAuthentication->clear(); if (!ssid_updated) textSsid->clear(); if (!bssid_updated) textBssid->clear(); if (!ipaddr_updated) textIpAddress->clear(); } void WpaGui::updateNetworks() { char buf[2048], *start, *end, *id, *ssid, *bssid, *flags; size_t len; int first_active = -1; int was_selected = -1; bool current = false; if (!networkMayHaveChanged) return; if (networkList->currentRow() >= 0) was_selected = networkList->currentRow(); networkSelect->clear(); networkList->clear(); if (ctrl_conn == NULL) return; len = sizeof(buf) - 1; if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0) return; buf[len] = '\0'; start = strchr(buf, '\n'); if (start == NULL) return; start++; while (*start) { bool last = false; end = strchr(start, '\n'); if (end == NULL) { last = true; end = start; while (end[0] && end[1]) end++; } *end = '\0'; id = start; ssid = strchr(id, '\t'); if (ssid == NULL) break; *ssid++ = '\0'; bssid = strchr(ssid, '\t'); if (bssid == NULL) break; *bssid++ = '\0'; flags = strchr(bssid, '\t'); if (flags == NULL) break; *flags++ = '\0'; if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) { if (last) break; start = end + 1; continue; } QString network(id); network.append(": "); network.append(ssid); networkSelect->addItem(network); networkList->addItem(network); if (strstr(flags, "[CURRENT]")) { networkSelect->setCurrentIndex(networkSelect->count() - 1); current = true; } else if (first_active < 0 && strstr(flags, "[DISABLED]") == NULL) first_active = networkSelect->count() - 1; if (last) break; start = end + 1; } if (networkSelect->count() > 1) networkSelect->addItem(tr("Select any network")); if (!current && first_active >= 0) networkSelect->setCurrentIndex(first_active); if (was_selected >= 0 && networkList->count() > 0) { if (was_selected < networkList->count()) networkList->setCurrentRow(was_selected); else networkList->setCurrentRow(networkList->count() - 1); } else networkList->setCurrentRow(networkSelect->currentIndex()); networkMayHaveChanged = false; } void WpaGui::helpIndex() { printf("helpIndex\n"); } void WpaGui::helpContents() { printf("helpContents\n"); } void WpaGui::helpAbout() { QMessageBox::about(this, "wpa_gui for wpa_supplicant", "Copyright (c) 2003-2013,\n" "Jouni Malinen \n" "and contributors.\n" "\n" "This software may be distributed under\n" "the terms of the BSD license.\n" "See README for more details.\n" "\n" "This product includes software developed\n" "by the OpenSSL Project for use in the\n" "OpenSSL Toolkit (http://www.openssl.org/)\n"); } void WpaGui::disconnect() { char reply[10]; size_t reply_len = sizeof(reply); ctrlRequest("DISCONNECT", reply, &reply_len); stopWpsRun(false); } void WpaGui::scan() { if (scanres) { scanres->close(); delete scanres; } scanres = new ScanResults(); if (scanres == NULL) return; scanres->setWpaGui(this); scanres->show(); scanres->exec(); } void WpaGui::eventHistory() { if (eh) { eh->close(); delete eh; } eh = new EventHistory(); if (eh == NULL) return; eh->addEvents(msgs); eh->show(); eh->exec(); } void WpaGui::ping() { char buf[10]; size_t len; #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE /* * QSocketNotifier cannot be used with Windows named pipes, so use a * timer to check for received messages for now. This could be * optimized be doing something specific to named pipes or Windows * events, but it is not clear what would be the best way of doing that * in Qt. */ receiveMsgs(); #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ if (scanres && !scanres->isVisible()) { delete scanres; scanres = NULL; } if (eh && !eh->isVisible()) { delete eh; eh = NULL; } if (udr && !udr->isVisible()) { delete udr; udr = NULL; } len = sizeof(buf) - 1; if (ctrlRequest("PING", buf, &len) < 0) { printf("PING failed - trying to reconnect\n"); if (openCtrlConnection(ctrl_iface) >= 0) { printf("Reconnected successfully\n"); pingsToStatusUpdate = 0; } } pingsToStatusUpdate--; if (pingsToStatusUpdate <= 0) { updateStatus(); updateNetworks(); } #ifndef CONFIG_CTRL_IFACE_NAMED_PIPE /* Use less frequent pings and status updates when the main window is * hidden (running in taskbar). */ int interval = isHidden() ? 5000 : 1000; if (timer->interval() != interval) timer->setInterval(interval); #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ } static int str_match(const char *a, const char *b) { return strncmp(a, b, strlen(b)) == 0; } void WpaGui::processMsg(char *msg) { char *pos = msg, *pos2; int priority = 2; if (*pos == '<') { /* skip priority */ pos++; priority = atoi(pos); pos = strchr(pos, '>'); if (pos) pos++; else pos = msg; } WpaMsg wm(pos, priority); if (eh) eh->addEvent(wm); if (peers) peers->event_notify(wm); msgs.append(wm); while (msgs.count() > 100) msgs.pop_front(); /* Update last message with truncated version of the event */ if (strncmp(pos, "CTRL-", 5) == 0) { pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' '); if (pos2) pos2++; else pos2 = pos; } else pos2 = pos; QString lastmsg = pos2; lastmsg.truncate(40); textLastMessage->setText(lastmsg); pingsToStatusUpdate = 0; networkMayHaveChanged = true; if (str_match(pos, WPA_CTRL_REQ)) processCtrlReq(pos + strlen(WPA_CTRL_REQ)); else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres) scanres->updateResults(); else if (str_match(pos, WPA_EVENT_DISCONNECTED)) showTrayMessage(QSystemTrayIcon::Information, 3, tr("Disconnected from network.")); else if (str_match(pos, WPA_EVENT_CONNECTED)) { showTrayMessage(QSystemTrayIcon::Information, 3, tr("Connection to network established.")); QTimer::singleShot(5 * 1000, this, SLOT(showTrayStatus())); stopWpsRun(true); } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PBC)) { wpsStatusText->setText(tr("WPS AP in active PBC mode found")); if (textStatus->text() == "INACTIVE" || textStatus->text() == "DISCONNECTED") wpaguiTab->setCurrentWidget(wpsTab); wpsInstructions->setText(tr("Press the PBC button on the " "screen to start registration")); } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PIN)) { wpsStatusText->setText(tr("WPS AP with recently selected " "registrar")); if (textStatus->text() == "INACTIVE" || textStatus->text() == "DISCONNECTED") wpaguiTab->setCurrentWidget(wpsTab); } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_AUTH)) { showTrayMessage(QSystemTrayIcon::Information, 3, "Wi-Fi Protected Setup (WPS) AP\n" "indicating this client is authorized."); wpsStatusText->setText("WPS AP indicating this client is " "authorized"); if (textStatus->text() == "INACTIVE" || textStatus->text() == "DISCONNECTED") wpaguiTab->setCurrentWidget(wpsTab); } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) { wpsStatusText->setText(tr("WPS AP detected")); } else if (str_match(pos, WPS_EVENT_OVERLAP)) { wpsStatusText->setText(tr("PBC mode overlap detected")); wpsInstructions->setText(tr("More than one AP is currently in " "active WPS PBC mode. Wait couple " "of minutes and try again")); wpaguiTab->setCurrentWidget(wpsTab); } else if (str_match(pos, WPS_EVENT_CRED_RECEIVED)) { wpsStatusText->setText(tr("Network configuration received")); wpaguiTab->setCurrentWidget(wpsTab); } else if (str_match(pos, WPA_EVENT_EAP_METHOD)) { if (strstr(pos, "(WSC)")) wpsStatusText->setText(tr("Registration started")); } else if (str_match(pos, WPS_EVENT_M2D)) { wpsStatusText->setText(tr("Registrar does not yet know PIN")); } else if (str_match(pos, WPS_EVENT_FAIL)) { wpsStatusText->setText(tr("Registration failed")); } else if (str_match(pos, WPS_EVENT_SUCCESS)) { wpsStatusText->setText(tr("Registration succeeded")); } } void WpaGui::processCtrlReq(const char *req) { if (udr) { udr->close(); delete udr; } udr = new UserDataRequest(); if (udr == NULL) return; if (udr->setParams(this, req) < 0) { delete udr; udr = NULL; return; } udr->show(); udr->exec(); } void WpaGui::receiveMsgs() { char buf[256]; size_t len; while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) { len = sizeof(buf) - 1; if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) { buf[len] = '\0'; processMsg(buf); } } } void WpaGui::connectB() { char reply[10]; size_t reply_len = sizeof(reply); ctrlRequest("REASSOCIATE", reply, &reply_len); } void WpaGui::selectNetwork( const QString &sel ) { QString cmd(sel); char reply[10]; size_t reply_len = sizeof(reply); if (cmd.contains(QRegExp("^\\d+:"))) cmd.truncate(cmd.indexOf(':')); else cmd = "any"; cmd.prepend("SELECT_NETWORK "); ctrlRequest(cmd.toAscii().constData(), reply, &reply_len); triggerUpdate(); stopWpsRun(false); } void WpaGui::enableNetwork(const QString &sel) { QString cmd(sel); char reply[10]; size_t reply_len = sizeof(reply); if (cmd.contains(QRegExp("^\\d+:"))) cmd.truncate(cmd.indexOf(':')); else if (!cmd.startsWith("all")) { printf("Invalid editNetwork '%s'\n", cmd.toAscii().constData()); return; } cmd.prepend("ENABLE_NETWORK "); ctrlRequest(cmd.toAscii().constData(), reply, &reply_len); triggerUpdate(); } void WpaGui::disableNetwork(const QString &sel) { QString cmd(sel); char reply[10]; size_t reply_len = sizeof(reply); if (cmd.contains(QRegExp("^\\d+:"))) cmd.truncate(cmd.indexOf(':')); else if (!cmd.startsWith("all")) { printf("Invalid editNetwork '%s'\n", cmd.toAscii().constData()); return; } cmd.prepend("DISABLE_NETWORK "); ctrlRequest(cmd.toAscii().constData(), reply, &reply_len); triggerUpdate(); } void WpaGui::editNetwork(const QString &sel) { QString cmd(sel); int id = -1; if (cmd.contains(QRegExp("^\\d+:"))) { cmd.truncate(cmd.indexOf(':')); id = cmd.toInt(); } NetworkConfig *nc = new NetworkConfig(); if (nc == NULL) return; nc->setWpaGui(this); if (id >= 0) nc->paramsFromConfig(id); else nc->newNetwork(); nc->show(); nc->exec(); } void WpaGui::editSelectedNetwork() { if (networkSelect->count() < 1) { QMessageBox::information( this, tr("No Networks"), tr("There are no networks to edit.\n")); return; } QString sel(networkSelect->currentText()); editNetwork(sel); } void WpaGui::editListedNetwork() { if (networkList->currentRow() < 0) { QMessageBox::information(this, tr("Select A Network"), tr("Select a network from the list to" " edit it.\n")); return; } QString sel(networkList->currentItem()->text()); editNetwork(sel); } void WpaGui::triggerUpdate() { updateStatus(); networkMayHaveChanged = true; updateNetworks(); } void WpaGui::addNetwork() { NetworkConfig *nc = new NetworkConfig(); if (nc == NULL) return; nc->setWpaGui(this); nc->newNetwork(); nc->show(); nc->exec(); } void WpaGui::removeNetwork(const QString &sel) { QString cmd(sel); char reply[10]; size_t reply_len = sizeof(reply); if (cmd.contains(QRegExp("^\\d+:"))) cmd.truncate(cmd.indexOf(':')); else if (!cmd.startsWith("all")) { printf("Invalid editNetwork '%s'\n", cmd.toAscii().constData()); return; } cmd.prepend("REMOVE_NETWORK "); ctrlRequest(cmd.toAscii().constData(), reply, &reply_len); triggerUpdate(); } void WpaGui::removeSelectedNetwork() { if (networkSelect->count() < 1) { QMessageBox::information(this, tr("No Networks"), tr("There are no networks to remove." "\n")); return; } QString sel(networkSelect->currentText()); removeNetwork(sel); } void WpaGui::removeListedNetwork() { if (networkList->currentRow() < 0) { QMessageBox::information(this, tr("Select A Network"), tr("Select a network from the list " "to remove it.\n")); return; } QString sel(networkList->currentItem()->text()); removeNetwork(sel); } void WpaGui::enableAllNetworks() { QString sel("all"); enableNetwork(sel); } void WpaGui::disableAllNetworks() { QString sel("all"); disableNetwork(sel); } void WpaGui::removeAllNetworks() { QString sel("all"); removeNetwork(sel); } int WpaGui::getNetworkDisabled(const QString &sel) { QString cmd(sel); char reply[10]; size_t reply_len = sizeof(reply) - 1; int pos = cmd.indexOf(':'); if (pos < 0) { printf("Invalid getNetworkDisabled '%s'\n", cmd.toAscii().constData()); return -1; } cmd.truncate(pos); cmd.prepend("GET_NETWORK "); cmd.append(" disabled"); if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) >= 0 && reply_len >= 1) { reply[reply_len] = '\0'; if (!str_match(reply, "FAIL")) return atoi(reply); } return -1; } void WpaGui::updateNetworkDisabledStatus() { if (networkList->currentRow() < 0) return; QString sel(networkList->currentItem()->text()); switch (getNetworkDisabled(sel)) { case 0: if (!enableRadioButton->isChecked()) enableRadioButton->setChecked(true); return; case 1: if (!disableRadioButton->isChecked()) disableRadioButton->setChecked(true); return; } } void WpaGui::enableListedNetwork(bool enabled) { if (networkList->currentRow() < 0 || !enabled) return; QString sel(networkList->currentItem()->text()); if (getNetworkDisabled(sel) == 1) enableNetwork(sel); } void WpaGui::disableListedNetwork(bool disabled) { if (networkList->currentRow() < 0 || !disabled) return; QString sel(networkList->currentItem()->text()); if (getNetworkDisabled(sel) == 0) disableNetwork(sel); } void WpaGui::saveConfig() { char buf[10]; size_t len; len = sizeof(buf) - 1; ctrlRequest("SAVE_CONFIG", buf, &len); buf[len] = '\0'; if (str_match(buf, "FAIL")) QMessageBox::warning( this, tr("Failed to save configuration"), tr("The configuration could not be saved.\n" "\n" "The update_config=1 configuration option\n" "must be used for configuration saving to\n" "be permitted.\n")); else QMessageBox::information( this, tr("Saved configuration"), tr("The current configuration was saved." "\n")); } void WpaGui::selectAdapter( const QString & sel ) { if (openCtrlConnection(sel.toAscii().constData()) < 0) printf("Failed to open control connection to " "wpa_supplicant.\n"); updateStatus(); updateNetworks(); } void WpaGui::createTrayIcon(bool trayOnly) { QApplication::setQuitOnLastWindowClosed(false); tray_icon = new QSystemTrayIcon(this); tray_icon->setToolTip(qAppName() + tr(" - wpa_supplicant user interface")); if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg")); else tray_icon->setIcon(QIcon(":/icons/wpa_gui.png")); connect(tray_icon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason))); ackTrayIcon = false; tray_menu = new QMenu(this); disconnectAction = new QAction(tr("&Disconnect"), this); reconnectAction = new QAction(tr("Re&connect"), this); connect(disconnectAction, SIGNAL(triggered()), this, SLOT(disconnect())); connect(reconnectAction, SIGNAL(triggered()), this, SLOT(connectB())); tray_menu->addAction(disconnectAction); tray_menu->addAction(reconnectAction); tray_menu->addSeparator(); eventAction = new QAction(tr("&Event History"), this); scanAction = new QAction(tr("Scan &Results"), this); statAction = new QAction(tr("S&tatus"), this); connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory())); connect(scanAction, SIGNAL(triggered()), this, SLOT(scan())); connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus())); tray_menu->addAction(eventAction); tray_menu->addAction(scanAction); tray_menu->addAction(statAction); tray_menu->addSeparator(); showAction = new QAction(tr("&Show Window"), this); hideAction = new QAction(tr("&Hide Window"), this); quitAction = new QAction(tr("&Quit"), this); connect(showAction, SIGNAL(triggered()), this, SLOT(show())); connect(hideAction, SIGNAL(triggered()), this, SLOT(hide())); connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); tray_menu->addAction(showAction); tray_menu->addAction(hideAction); tray_menu->addSeparator(); tray_menu->addAction(quitAction); tray_icon->setContextMenu(tray_menu); tray_icon->show(); if (!trayOnly) show(); inTray = trayOnly; } void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec, const QString & msg) { if (!QSystemTrayIcon::supportsMessages()) return; if (isVisible() || !tray_icon || !tray_icon->isVisible()) return; tray_icon->showMessage(qAppName(), msg, type, sec * 1000); } void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how) { switch (how) { /* use close() here instead of hide() and allow the * custom closeEvent handler take care of children */ case QSystemTrayIcon::Trigger: ackTrayIcon = true; if (isVisible()) { close(); inTray = true; } else { show(); inTray = false; } break; case QSystemTrayIcon::MiddleClick: showTrayStatus(); break; default: break; } } void WpaGui::showTrayStatus() { char buf[2048]; size_t len; len = sizeof(buf) - 1; if (ctrlRequest("STATUS", buf, &len) < 0) return; buf[len] = '\0'; QString msg, status(buf); QStringList lines = status.split(QRegExp("\\n")); for (QStringList::Iterator it = lines.begin(); it != lines.end(); it++) { int pos = (*it).indexOf('=') + 1; if (pos < 1) continue; if ((*it).startsWith("bssid=")) msg.append("BSSID:\t" + (*it).mid(pos) + "\n"); else if ((*it).startsWith("ssid=")) msg.append("SSID: \t" + (*it).mid(pos) + "\n"); else if ((*it).startsWith("pairwise_cipher=")) msg.append("PAIR: \t" + (*it).mid(pos) + "\n"); else if ((*it).startsWith("group_cipher=")) msg.append("GROUP:\t" + (*it).mid(pos) + "\n"); else if ((*it).startsWith("key_mgmt=")) msg.append("AUTH: \t" + (*it).mid(pos) + "\n"); else if ((*it).startsWith("wpa_state=")) msg.append("STATE:\t" + (*it).mid(pos) + "\n"); else if ((*it).startsWith("ip_address=")) msg.append("IP: \t" + (*it).mid(pos) + "\n"); else if ((*it).startsWith("Supplicant PAE state=")) msg.append("PAE: \t" + (*it).mid(pos) + "\n"); else if ((*it).startsWith("EAP state=")) msg.append("EAP: \t" + (*it).mid(pos) + "\n"); } if (!msg.isEmpty()) showTrayMessage(QSystemTrayIcon::Information, 10, msg); } void WpaGui::closeEvent(QCloseEvent *event) { if (eh) { eh->close(); delete eh; eh = NULL; } if (scanres) { scanres->close(); delete scanres; scanres = NULL; } if (peers) { peers->close(); delete peers; peers = NULL; } if (udr) { udr->close(); delete udr; udr = NULL; } if (tray_icon && !ackTrayIcon) { /* give user a visual hint that the tray icon exists */ if (QSystemTrayIcon::supportsMessages()) { hide(); showTrayMessage(QSystemTrayIcon::Information, 3, qAppName() + tr(" will keep running in " "the system tray.")); } else { QMessageBox::information(this, qAppName() + tr(" systray"), tr("The program will keep " "running in the system " "tray.")); } ackTrayIcon = true; } event->accept(); } void WpaGui::wpsDialog() { wpaguiTab->setCurrentWidget(wpsTab); } void WpaGui::peersDialog() { if (peers) { peers->close(); delete peers; } peers = new Peers(); if (peers == NULL) return; peers->setWpaGui(this); peers->show(); peers->exec(); } void WpaGui::tabChanged(int index) { if (index != 2) return; if (wpsRunning) return; wpsApPinEdit->setEnabled(!bssFromScan.isEmpty()); if (bssFromScan.isEmpty()) wpsApPinButton->setEnabled(false); } void WpaGui::wpsPbc() { char reply[20]; size_t reply_len = sizeof(reply); if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0) return; wpsPinEdit->setEnabled(false); if (wpsStatusText->text().compare(tr("WPS AP in active PBC mode found"))) { wpsInstructions->setText(tr("Press the push button on the AP to " "start the PBC mode.")); } else { wpsInstructions->setText(tr("If you have not yet done so, press " "the push button on the AP to start " "the PBC mode.")); } wpsStatusText->setText(tr("Waiting for Registrar")); wpsRunning = true; } void WpaGui::wpsGeneratePin() { char reply[20]; size_t reply_len = sizeof(reply) - 1; if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0) return; reply[reply_len] = '\0'; wpsPinEdit->setText(reply); wpsPinEdit->setEnabled(true); wpsInstructions->setText(tr("Enter the generated PIN into the Registrar " "(either the internal one in the AP or an " "external one).")); wpsStatusText->setText(tr("Waiting for Registrar")); wpsRunning = true; } void WpaGui::setBssFromScan(const QString &bssid) { bssFromScan = bssid; wpsApPinEdit->setEnabled(!bssFromScan.isEmpty()); wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8); wpsStatusText->setText(tr("WPS AP selected from scan results")); wpsInstructions->setText(tr("If you want to use an AP device PIN, e.g., " "from a label in the device, enter the eight " "digit AP PIN and click Use AP PIN button.")); } void WpaGui::wpsApPinChanged(const QString &text) { wpsApPinButton->setEnabled(text.length() == 8); } void WpaGui::wpsApPin() { char reply[20]; size_t reply_len = sizeof(reply); QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text()); if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) < 0) return; wpsStatusText->setText(tr("Waiting for AP/Enrollee")); wpsRunning = true; } void WpaGui::stopWpsRun(bool success) { if (wpsRunning) wpsStatusText->setText(success ? tr("Connected to the network") : tr("Stopped")); else wpsStatusText->setText(""); wpsPinEdit->setEnabled(false); wpsInstructions->setText(""); wpsRunning = false; bssFromScan = ""; wpsApPinEdit->setEnabled(false); wpsApPinButton->setEnabled(false); } #ifdef CONFIG_NATIVE_WINDOWS #ifndef WPASVC_NAME #define WPASVC_NAME TEXT("wpasvc") #endif class ErrorMsg : public QMessageBox { public: ErrorMsg(QWidget *parent, DWORD last_err = GetLastError()); void showMsg(QString msg); private: DWORD err; }; ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) : QMessageBox(parent), err(last_err) { setWindowTitle(tr("wpa_gui error")); setIcon(QMessageBox::Warning); } void ErrorMsg::showMsg(QString msg) { LPTSTR buf; setText(msg); if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, (LPTSTR) (void *) &buf, 0, NULL) > 0) { QString msg = QString::fromWCharArray(buf); setInformativeText(QString("[%1] %2").arg(err).arg(msg)); LocalFree(buf); } else { setInformativeText(QString("[%1]").arg(err)); } exec(); } void WpaGui::startService() { SC_HANDLE svc, scm; scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); if (!scm) { ErrorMsg(this).showMsg(tr("OpenSCManager failed")); return; } svc = OpenService(scm, WPASVC_NAME, SERVICE_START); if (!svc) { ErrorMsg(this).showMsg(tr("OpenService failed")); CloseServiceHandle(scm); return; } if (!StartService(svc, 0, NULL)) { ErrorMsg(this).showMsg(tr("Failed to start wpa_supplicant " "service")); } CloseServiceHandle(svc); CloseServiceHandle(scm); } void WpaGui::stopService() { SC_HANDLE svc, scm; SERVICE_STATUS status; scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); if (!scm) { ErrorMsg(this).showMsg(tr("OpenSCManager failed")); return; } svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP); if (!svc) { ErrorMsg(this).showMsg(tr("OpenService failed")); CloseServiceHandle(scm); return; } if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) { ErrorMsg(this).showMsg(tr("Failed to stop wpa_supplicant " "service")); } CloseServiceHandle(svc); CloseServiceHandle(scm); } bool WpaGui::serviceRunning() { SC_HANDLE svc, scm; SERVICE_STATUS status; bool running = false; scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); if (!scm) { printf("OpenSCManager failed: %d\n", (int) GetLastError()); return false; } svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS); if (!svc) { printf("OpenService failed: %d\n\n", (int) GetLastError()); CloseServiceHandle(scm); return false; } if (QueryServiceStatus(svc, &status)) { if (status.dwCurrentState != SERVICE_STOPPED) running = true; } CloseServiceHandle(svc); CloseServiceHandle(scm); return running; } #endif /* CONFIG_NATIVE_WINDOWS */ void WpaGui::addInterface() { if (add_iface) { add_iface->close(); delete add_iface; } add_iface = new AddInterface(this, this); add_iface->show(); add_iface->exec(); } #ifndef QT_NO_SESSIONMANAGER void WpaGui::saveState() { QSettings settings("wpa_supplicant", "wpa_gui"); settings.beginGroup("state"); settings.setValue("session_id", app->sessionId()); settings.setValue("in_tray", inTray); settings.endGroup(); } #endif wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/addinterface.cpp0000664000175000017500000001266212343617166022535 0ustar jmjm/* * wpa_gui - AddInterface class * Copyright (c) 2008, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include #include "common/wpa_ctrl.h" #include #include "wpagui.h" #include "addinterface.h" #ifdef CONFIG_NATIVE_WINDOWS #include #ifndef WPA_KEY_ROOT #define WPA_KEY_ROOT HKEY_LOCAL_MACHINE #endif #ifndef WPA_KEY_PREFIX #define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant") #endif #endif /* CONFIG_NATIVE_WINDOWS */ AddInterface::AddInterface(WpaGui *_wpagui, QWidget *parent) : QDialog(parent), wpagui(_wpagui) { setWindowTitle(tr("Select network interface to add")); resize(400, 200); vboxLayout = new QVBoxLayout(this); interfaceWidget = new QTreeWidget(this); interfaceWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); interfaceWidget->setUniformRowHeights(true); interfaceWidget->setSortingEnabled(true); interfaceWidget->setColumnCount(3); interfaceWidget->headerItem()->setText(0, tr("driver")); interfaceWidget->headerItem()->setText(1, tr("interface")); interfaceWidget->headerItem()->setText(2, tr("description")); interfaceWidget->setItemsExpandable(FALSE); interfaceWidget->setRootIsDecorated(FALSE); vboxLayout->addWidget(interfaceWidget); connect(interfaceWidget, SIGNAL(itemActivated(QTreeWidgetItem *, int)), this, SLOT(interfaceSelected(QTreeWidgetItem *))); addInterfaces(); } void AddInterface::addInterfaces() { #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE struct wpa_ctrl *ctrl; int ret; char buf[2048]; size_t len; ctrl = wpa_ctrl_open(NULL); if (ctrl == NULL) return; len = sizeof(buf) - 1; ret = wpa_ctrl_request(ctrl, "INTERFACE_LIST", 14, buf, &len, NULL); if (ret < 0) { wpa_ctrl_close(ctrl); return; } buf[len] = '\0'; wpa_ctrl_close(ctrl); QString ifaces(buf); QStringList lines = ifaces.split(QRegExp("\\n")); for (QStringList::Iterator it = lines.begin(); it != lines.end(); it++) { QStringList arg = (*it).split(QChar('\t')); if (arg.size() < 3) continue; QTreeWidgetItem *item = new QTreeWidgetItem(interfaceWidget); if (!item) break; item->setText(0, arg[0]); item->setText(1, arg[1]); item->setText(2, arg[2]); } interfaceWidget->resizeColumnToContents(0); interfaceWidget->resizeColumnToContents(1); interfaceWidget->resizeColumnToContents(2); #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ } #ifdef CONFIG_NATIVE_WINDOWS bool AddInterface::addRegistryInterface(const QString &ifname) { HKEY hk, ihk; LONG ret; int id, tmp; TCHAR name[10]; DWORD val, i; ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX TEXT("\\interfaces"), 0, KEY_ENUMERATE_SUB_KEYS | KEY_CREATE_SUB_KEY, &hk); if (ret != ERROR_SUCCESS) return false; id = -1; for (i = 0; ; i++) { TCHAR name[255]; DWORD namelen; namelen = 255; ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL, NULL); if (ret == ERROR_NO_MORE_ITEMS) break; if (ret != ERROR_SUCCESS) break; if (namelen >= 255) namelen = 255 - 1; name[namelen] = '\0'; #ifdef UNICODE QString s((QChar *) name, namelen); #else /* UNICODE */ QString s(name); #endif /* UNICODE */ tmp = s.toInt(); if (tmp > id) id = tmp; } id += 1; #ifdef UNICODE wsprintf(name, L"%04d", id); #else /* UNICODE */ os_snprintf(name, sizeof(name), "%04d", id); #endif /* UNICODE */ ret = RegCreateKeyEx(hk, name, 0, NULL, 0, KEY_WRITE, NULL, &ihk, NULL); RegCloseKey(hk); if (ret != ERROR_SUCCESS) return false; #ifdef UNICODE RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ, (LPBYTE) ifname.unicode(), (ifname.length() + 1) * sizeof(TCHAR)); #else /* UNICODE */ RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ, (LPBYTE) ifname.toLocal8Bit(), ifname.length() + 1); #endif /* UNICODE */ RegSetValueEx(ihk, TEXT("config"), 0, REG_SZ, (LPBYTE) TEXT("default"), 8 * sizeof(TCHAR)); RegSetValueEx(ihk, TEXT("ctrl_interface"), 0, REG_SZ, (LPBYTE) TEXT(""), 1 * sizeof(TCHAR)); val = 1; RegSetValueEx(ihk, TEXT("skip_on_error"), 0, REG_DWORD, (LPBYTE) &val, sizeof(val)); RegCloseKey(ihk); return true; } #endif /* CONFIG_NATIVE_WINDOWS */ void AddInterface::interfaceSelected(QTreeWidgetItem *sel) { if (!sel) return; #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE struct wpa_ctrl *ctrl; int ret; char buf[20], cmd[256]; size_t len; /* * INTERFACE_ADD TABTABTABTAB * TAB */ snprintf(cmd, sizeof(cmd), "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s", sel->text(1).toAscii().constData(), "default", sel->text(0).toAscii().constData(), "yes", "", ""); cmd[sizeof(cmd) - 1] = '\0'; ctrl = wpa_ctrl_open(NULL); if (ctrl == NULL) return; len = sizeof(buf) - 1; ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, NULL); wpa_ctrl_close(ctrl); if (ret < 0) { QMessageBox::warning(this, "wpa_gui", tr("Add interface command could not be " "completed.")); return; } buf[len] = '\0'; if (buf[0] != 'O' || buf[1] != 'K') { QMessageBox::warning(this, "wpa_gui", tr("Failed to add the interface.")); return; } #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ #ifdef CONFIG_NATIVE_WINDOWS if (!addRegistryInterface(sel->text(1))) { QMessageBox::information(this, "wpa_gui", tr("Failed to add the interface into " "registry.")); } #endif /* CONFIG_NATIVE_WINDOWS */ wpagui->selectAdapter(sel->text(1)); close(); } wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/networkconfig.h0000664000175000017500000000244512343617166022446 0ustar jmjm/* * wpa_gui - NetworkConfig class * Copyright (c) 2005-2006, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef NETWORKCONFIG_H #define NETWORKCONFIG_H #include #include "ui_networkconfig.h" class WpaGui; class NetworkConfig : public QDialog, public Ui::NetworkConfig { Q_OBJECT public: NetworkConfig(QWidget *parent = 0, const char *name = 0, bool modal = false, Qt::WFlags fl = 0); ~NetworkConfig(); virtual void paramsFromScanResults(QTreeWidgetItem *sel); virtual void setWpaGui(WpaGui *_wpagui); virtual int setNetworkParam(int id, const char *field, const char *value, bool quote); virtual void paramsFromConfig(int network_id); virtual void newNetwork(); public slots: virtual void authChanged(int sel); virtual void addNetwork(); virtual void encrChanged(const QString &sel); virtual void writeWepKey(int network_id, QLineEdit *edit, int id); virtual void removeNetwork(); virtual void eapChanged(int sel); virtual void useWps(); protected slots: virtual void languageChange(); private: WpaGui *wpagui; int edit_network_id; bool new_network; QString bssid; virtual void wepEnabled(bool enabled); virtual void getEapCapa(); }; #endif /* NETWORKCONFIG_H */ wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/icons.qrc0000664000175000017500000000047012343617166021234 0ustar jmjm icons/wpa_gui.svg icons/ap.svg icons/laptop.svg icons/group.svg icons/invitation.svg wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/icons/0000775000175000017500000000000012343617166020524 5ustar jmjmwpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg0000664000175000017500000002200312343617166022675 0ustar jmjm image/svg+xml wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/icons/invitation.svg0000664000175000017500000003474312343617166023444 0ustar jmjm image/svg+xml Green Unknown 2005-11-01 Jean-Victor Balin jean.victor.balin@gmail.com icon wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/icons/laptop.svg0000664000175000017500000110174012343617166022550 0ustar jmjm image/svg+xml wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/icons/Makefile0000664000175000017500000000142412343617166022165 0ustar jmjm#!/usr/bin/make -f NAMES := wpa_gui ap laptop group invitation SIZES := 16x16 22x22 32x32 48x48 64x64 128x128 ICONS := $(addsuffix .png, $(foreach name, $(NAMES), $(foreach size, $(SIZES), $(size)/$(name)))) ICONS += $(addsuffix .xpm, $(NAMES)) all: $(ICONS) %.png: mkdir -p hicolor/$(word 1, $(subst /, ,$(@)))/apps/ inkscape $(subst .png,.svg, $(word 2, $(subst /, , $(@)))) --without-gui \ --export-width=$(word 1, $(subst x, , $(@))) \ --export-height=$(word 2, $(subst x, , $(subst /, , $(@)))) \ --export-png=hicolor/$(word 1, $(subst /, ,$(@)))/apps/$(word 2, $(subst /, , $@)) %.xpm: mkdir -p pixmaps/ convert hicolor/16x16/apps/$(@:.xpm=.png) pixmaps/$(@:.xpm=-16.xpm) convert hicolor/32x32/apps/$(@:.xpm=.png) pixmaps/$@ clean: $(RM) -r pixmaps hicolor wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/icons/group.svg0000664000175000017500000013744512343617166022417 0ustar jmjm Etiquette Icons hash filesystem computer icons Andy Fitzsimon Andy Fitzsimon Andy Fitzsimon image/svg+xml en wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/icons/README0000664000175000017500000000267212343617166021413 0ustar jmjmwpa_gui icon files To convert the svg icons to other formats, make sure inkscape and imagemagick are installed and use `make' to create various sized png and xpm icons. wpa_gui.svg ----------- Copyright (c) 2008 Bernard Gray The wpa_gui icon is licensed under the GPL version 2. Alternatively, the icon may be distributed under the terms of BSD license. ap.svg ------ mystica_Wireless_Router.svg http://openclipart.org/media/files/mystica/8390 Wireless Router by: mystica last change: April 20, 2008 10:32 pm (File added) date: April 20, 2008 10:31 pm license: PD laptop.svg ---------- metalmarious_Laptop.svg http://openclipart.org/media/files/metalmarious/4056 Laptop by: metalmarious last change: May 18, 2008 07:04 pm (File added) date: August 27, 2007 04:44 am license: PD group.svg --------- http://www.openclipart.org/detail/25428 http://www.openclipart.org/people/Anonymous/Anonymous_Network.svg Uploader: Anonymous Drawn by: Andrew Fitzsimon / Anonymous Created: 2009-04-29 04:07:37 Description: A network icon by Andrew Fitzsimon. Etiquette Icon set. From 0.18 OCAL database. Public Domain invitation.svg -------------- http://www.openclipart.org/detail/974 http://www.openclipart.org/people/jean_victor_balin/jean_victor_balin_unknown_green.svg Uploader: jean_victor_balin Drawn by: jean_victor_balin Created: 2006-10-27 02:12:13 Description: Public Domain wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/icons/ap.svg0000664000175000017500000020611612343617166021653 0ustar jmjm image/svg+xml wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/lang/0000775000175000017500000000000012343617166020332 5ustar jmjmwpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts0000664000175000017500000013062312343617166023012 0ustar jmjm AddInterface Select network interface to add Wähle die Netzwerkschnittstelle zum hinzufügen aus driver Treiber interface Schnittstelle description Beschreibung Add interface command could not be completed. Das Schnittstellen hinzufügen Kommando konnte nicht abgeschlossen werden. Failed to add the interface. Fehler beim hinzufügen der Schnittstelle. Failed to add the interface into registry. Fehler beim hinzufügen der Schnittstelle in die Registry. ErrorMsg wpa_gui error wpa_gui Fehler EventHistory Event history Ereignis Historie Close Schließen EventListModel Timestamp Zeit Message Meldung NetworkConfig NetworkConfig Cancel Abbrechen SSID SSID Network name (Service Set IDentifier) Netzwerkname (Service Set IDentifier) Authentication Authentifizierung Plaintext (open / no authentication) Plaintext (offen / keine Authentifizierung) Static WEP (no authentication) Static WEP (keine Authentifizierung) Static WEP (Shared Key authentication) IEEE 802.1X WPA-Personal (PSK) WPA-Enterprise (EAP) WPA2-Personal (PSK) WPA2-Enterprise (EAP) Encryption Verschlüsselung None Keine WEP TKIP CCMP PSK WPA/WPA2 pre-shared key or passphrase WPA/WPA2 Pre-Shared Key oder Passphrase EAP method EAP Verfahren Identity Identität Username/Identity for EAP methods Nutzername/Identitär für die EAP Verfahren Password Passwort Password for EAP methods Passwort für die EAP Verfahren CA certificate CA Zertifikat WEP keys WEP Schlüssel key 0 Schlüssel 0 key 1 Schlüssel 1 key 3 Schlüssel 3 key 2 Schlüssel 2 Optional Settings Optionale Einstellungen Network Identification String Netzwerk Indentifikations Zeichenfolge Network Priority Netzwerk Priorität IDString Priority Priorität Inner auth Geheime Auth Add Hinzufügen Remove Entfernen WPS WPA Pre-Shared Key Error WPA Pre Shared Key Fehler WPA-PSK requires a passphrase of 8 to 63 characters or 64 hex digit PSK WPA PSK benötigt ein Passphrase mit 8 bis 63 Zeichen oder 64 hexadezimal stelligen PSK Network ID Error Netzwerk ID Fehler Network ID String contains non-word characters. It must be a simple string, without spaces, containing only characters in this range: [A-Za-z0-9_-] Netzwerk ID Zeichnfolge beinhaltet ungültige Zeichen. Es muss eine einfache Zeichnfolge aus [A-Za-z0-9_] ohne Leerzeichen sein Failed to add network to wpa_supplicant configuration. Hinzufügen des Netzwerks in die wpa_supplicant Konfiguration fehlgeschlagen. Failed to enable network in wpa_supplicant configuration. Aktivieren des Netzwerks in der wpa_supplicant Konfiguration fehlgeschlagen. This will permanently remove the network from the configuration. Do you really want to remove this network? Dies wird das Netzwerk permanent aus der Konfiguration entfernen. Möchtest du das Netzwerk wirklich entfernen? Yes Ja No Nein Failed to remove network from wpa_supplicant configuration. Entfernen des Netzwerks aus der wpa_supplicant Konfiguration fehlgeschlagen. Peers Peers Associated station Verbundene Stationen AP WPS AP WPS PIN needed WPS PIN wird benötigt ER: WPS AP ER: WPS AP (Unconfigured) ER: WPS AP (nicht konfiguriert) ER: WPS Enrollee WPS Enrollee Enter WPS PIN WPS PIN Eingabe Connect (PBC) Verbinden (PBC) Enroll (PBC) Anmelden (PBC) Learn Configuration Konfiguration lernen Properties Eigenschaften Refresh Aktualisieren PIN: PIN for Pin für Failed to set the WPS PIN. Setzten des WPS PIN fehlgeschlagen. Peer Properties Peer Eigenschaften Name: Address: UUID: Primary Device Type: Primärer Geräte Typ: SSID: Configuration Methods: Konfigurationsverfahren: [USBA] [Ethernet] [Label] [Display] [Ext. NFC Token] [Int. NFC Token] [NFC Interface] [Push Button] [Keypad] Device Password ID: Geräte Passwort ID: (Default PIN) (User-specified PIN) (Machine-specified PIN) (Rekey) (Push Button) (Registrar-specified) Failed to start WPS PBC. Starten von WPS PBC fehlgeschlagen. AP PIN: AP PIN for AP PIN für Failed to start learning AP configuration. Fehler beim erkennen der AP Konfiguration. ScanResults Scan results Scan Ergebnisse SSID BSSID frequency Frequenz signal Signal flags Flags Scan Scannen Close Schließen UserDataRequest Authentication credentials required Authentifzierungs Beglaubigung nötig &OK &Cancel Password: Passwort: New password: Neues Passwort: Identity: Identität: Private key passphrase: Privater Key Passphrase: WpaGui wpa_gui Adapter: Network: Netzwerk: Current Status Aktueller Status Status: Last message: Letzte Meldung: Authentication: Authentifizierung: Encryption: Verschlüsselung: SSID: BSSID: IP address: IP Adresse: Connect Verbinden Disconnect Trennen Scan Scannen Manage Networks Netzwerke verwalten Enabled Aktiviert Edit Bearbeiten Remove Entfernen Disabled Deaktiviert Add Hinzufügen WPS PBC - push button PBC - Taste Generate PIN PIN erzeugen PIN: Use AP PIN AP PIN verwenden AP PIN: &File &Datei &Network &Netzwerk &Help &Hilfe Event &History Ereignis &Historie &Save Configuration Konfiguration &Speichern Ctrl+S E&xit &Beenden Ctrl+Q &Add &Hinzufügen &Edit &Bearbeiten &Remove &Entfernen E&nable All Alle &aktivieren &Disable All Alle &deaktivieren Re&move All Alle &entfernen &Contents... &Inhalt... &Index... &About &Über &Wi-Fi Protected Setup &Peers Stop Service Dienst stoppen Start Service Dienst starten Add Interface Schnittstelle hinzufügen connecting to wpa_supplicant Verbindungsaufbau zu wpa_supplicant wpa_supplicant service is not running. Do you want to start it? wpa_supplicant ist nicht gestartet. Möchtest du ihn starten? Disconnected Getrennt Inactive Inaktiv Scanning Scannen Authenticating Authentifizieren Associating Assoziieren Associated Assoziiert 4-Way Handshake 4-Wege Handshake Group Handshake Gruppen Handshake Completed Abgeschlossen Unknown Unbekannt Could not get status from wpa_supplicant Status konnte nicht von wpa_supplicant abgerufen werden No network interfaces in use. Would you like to add one? Es ist keine Netzwerkschnittstelle in verwendung. Möchtest du eine hinzufügen? Select any network Wähle beliebiges Netzwerk Disconnected from network. Getrennt vom Netzwerk. Connection to network established. Verbindung zum Netzwerk wurde aufgebaut. WPS AP in active PBC mode found WPS AP im aktiven PBC Modus gefunden Press the PBC button on the screen to start registration Drücke den PBC Knopf auf dem Bildschirm um die Registrierung zu starten WPS AP with recently selected registrar WPS AP mit kürzlich ausgewähltem Registrator WPS AP detected WPS AP erkannt PBC mode overlap detected PBC Modus Overlap erkannt More than one AP is currently in active WPS PBC mode. Wait couple of minutes and try again Mehr als ein AP ist momentan im aktiven WPS PBC Modus. Versuch es in ein paar Minuten nochmal Network configuration received Netzwerk Konfiguration empfangen Registration started Registrierung gestartet Registrar does not yet know PIN Registrator kennt den PIN noch nicht Registration failed Registrierung fehlgeschlagen Registration succeeded Registrierung erfolgreich No Networks Keine Netzwerke There are no networks to edit. Keine Netzwerke zum bearbeiten. Select A Network Wähle ein Netzwerk Select a network from the list to edit it. Wähle ein Netzwerk aus der Liste zum bearbeiten. There are no networks to remove. Es sind keine Netzwerke zum entfernen vorhanden. Select a network from the list to remove it. Wähle ein Netzwerk aus der Liste zum entfernen. Failed to save configuration Speichern der Konfiguration fehlgeschlagen The configuration could not be saved. The update_config=1 configuration option must be used for configuration saving to be permitted. Die Konfiguration konnte nicht gespeichert werden. Die Einstellung update_config=1 muss gesetzt sein, damit Konfigurationen gespeichert werden können. Saved configuration Konfiguration gespeichert The current configuration was saved. Die aktuelle Konfiguration wurde gespeichert. - wpa_supplicant user interface - wpa_supplicant Benutzerschnittstelle &Disconnect &Trennen Re&connect &Wiederverbinden &Event History &Ereignis Historie Scan &Results Scan E&rgebnisse S&tatus &Show Window &Fenster anzeigen &Hide Window &Fenster ausblenden &Quit &Beenden will keep running in the system tray. wird weiterhin in der System Ablage laufen. systray System Ablage The program will keep running in the system tray. Das Programm wird weiterhin in der System Ablage laufen. Press the push button on the AP to start the PBC mode. Drücke die Taste am AP um den PBC Modus zu starten. If you have not yet done so, press the push button on the AP to start the PBC mode. Wenn Sie es noch nicht getan haben, so drücken Sie die Taste am AP um den PBC Modus zu starten. Waiting for Registrar Warte auf Registrator Enter the generated PIN into the Registrar (either the internal one in the AP or an external one). Geben Sie den generierten PIN in der Registrierungsstelle ein (entweder der interne oder der externe im AP). WPS AP selected from scan results WPS AP ausgewählt aus Scan Ergebnissen If you want to use an AP device PIN, e.g., from a label in the device, enter the eight digit AP PIN and click Use AP PIN button. Wenn Sie einen AP Geräte PIN verwenden möchten, z.B.: von einem Aufkleber am Gerät, geben Sie denn acht stelligen AP PIN ein und klicken Sie auf den AP PIN Knopf. Waiting for AP/Enrollee Warte auf AP/Bewerber Connected to the network Verbunden zum Netzwerk Stopped Gestoppt OpenSCManager failed OpenSCManager fehlgeschlagen OpenService failed OpenService fehlgeschlagen Failed to start wpa_supplicant service Starten des wpa_supplicant Dienstes fehlgeschlagen Failed to stop wpa_supplicant service Stoppen des wpa_supplicant Dienstes fehlgeschlagen OpenSCManager failed: %d OpenSCManager fehlgeschlagen: %d OpenService failed: %d OpenService fehlgeschlagen: %d wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/lang/.gitignore0000664000175000017500000000000512343617166022315 0ustar jmjm*.qm wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/signalbar.h0000664000175000017500000000105312343617166021523 0ustar jmjm/* * wpa_gui - SignalBar class * Copyright (c) 2011, Kel Modderman * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef SIGNALBAR_H #define SIGNALBAR_H #include #include class SignalBar : public QStyledItemDelegate { Q_OBJECT public: SignalBar(QObject *parent = 0); ~SignalBar(); virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const ; }; #endif /* SIGNALBAR_H */ wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/scanresults.h0000664000175000017500000000144712343617166022136 0ustar jmjm/* * wpa_gui - ScanResults class * Copyright (c) 2005-2006, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef SCANRESULTS_H #define SCANRESULTS_H #include #include "ui_scanresults.h" class WpaGui; class ScanResults : public QDialog, public Ui::ScanResults { Q_OBJECT public: ScanResults(QWidget *parent = 0, const char *name = 0, bool modal = false, Qt::WFlags fl = 0); ~ScanResults(); public slots: virtual void setWpaGui(WpaGui *_wpagui); virtual void updateResults(); virtual void scanRequest(); virtual void getResults(); virtual void bssSelected(QTreeWidgetItem *sel); protected slots: virtual void languageChange(); private: WpaGui *wpagui; }; #endif /* SCANRESULTS_H */ wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/stringquery.cpp0000664000175000017500000000113512343617166022511 0ustar jmjm/* * wpa_gui - StringQuery class * Copyright (c) 2009, Atheros Communications * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include #include #include "stringquery.h" StringQuery::StringQuery(QString label) { edit = new QLineEdit; edit->setFocus(); QGridLayout *layout = new QGridLayout; layout->addWidget(new QLabel(label), 0, 0); layout->addWidget(edit, 0, 1); setLayout(layout); connect(edit, SIGNAL(returnPressed()), this, SLOT(accept())); } QString StringQuery::get_string() { return edit->text(); } wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/stringquery.h0000664000175000017500000000072412343617166022161 0ustar jmjm/* * wpa_gui - StringQuery class * Copyright (c) 2009, Atheros Communications * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef STRINGQUERY_H #define STRINGQUERY_H #include #include #include class StringQuery : public QDialog { Q_OBJECT public: StringQuery(QString label); QString get_string(); private: QLineEdit *edit; }; #endif /* STRINGQUERY_H */ wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop0000664000175000017500000000033012343617166022433 0ustar jmjm[Desktop Entry] Version=1.0 Name=wpa_gui Comment=Graphical user interface for wpa_supplicant Exec=wpa_gui Icon=wpa_gui GenericName=wpa_supplicant user interface Terminal=false Type=Application Categories=Qt;Network; wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/signalbar.cpp0000664000175000017500000000217012343617166022057 0ustar jmjm/* * wpa_gui - SignalBar class * Copyright (c) 2011, Kel Modderman * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include #include #include "signalbar.h" SignalBar::SignalBar(QObject *parent) : QStyledItemDelegate(parent) { } SignalBar::~SignalBar() { } void SignalBar::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionProgressBar opts; int signal; if (index.column() != 3) { QStyledItemDelegate::paint(painter, option, index); return; } if (index.data().toInt() > 0) signal = 0 - (256 - index.data().toInt()); else signal = index.data().toInt(); opts.minimum = -95; opts.maximum = -35; if (signal < opts.minimum) opts.progress = opts.minimum; else if (signal > opts.maximum) opts.progress = opts.maximum; else opts.progress = signal; opts.text = QString::number(signal) + " dBm"; opts.textVisible = true; opts.rect = option.rect; QApplication::style()->drawControl(QStyle::CE_ProgressBar, &opts, painter); } wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/scanresults.ui0000664000175000017500000000417412343617166022324 0ustar jmjm ScanResults 0 0 452 244 Scan results QAbstractItemView::NoEditTriggers true true 5 SSID BSSID frequency signal flags Qt::Horizontal 40 20 Scan Close wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp0000664000175000017500000005257612343617166023013 0ustar jmjm/* * wpa_gui - NetworkConfig class * Copyright (c) 2005-2006, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include #include #include "networkconfig.h" #include "wpagui.h" enum { AUTH_NONE_OPEN, AUTH_NONE_WEP, AUTH_NONE_WEP_SHARED, AUTH_IEEE8021X, AUTH_WPA_PSK, AUTH_WPA_EAP, AUTH_WPA2_PSK, AUTH_WPA2_EAP }; #define WPA_GUI_KEY_DATA "[key is configured]" NetworkConfig::NetworkConfig(QWidget *parent, const char *, bool, Qt::WFlags) : QDialog(parent) { setupUi(this); encrSelect->setEnabled(false); connect(authSelect, SIGNAL(activated(int)), this, SLOT(authChanged(int))); connect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); connect(addButton, SIGNAL(clicked()), this, SLOT(addNetwork())); connect(encrSelect, SIGNAL(activated(const QString &)), this, SLOT(encrChanged(const QString &))); connect(removeButton, SIGNAL(clicked()), this, SLOT(removeNetwork())); connect(eapSelect, SIGNAL(activated(int)), this, SLOT(eapChanged(int))); connect(useWpsButton, SIGNAL(clicked()), this, SLOT(useWps())); wpagui = NULL; new_network = false; } NetworkConfig::~NetworkConfig() { } void NetworkConfig::languageChange() { retranslateUi(this); } void NetworkConfig::paramsFromScanResults(QTreeWidgetItem *sel) { new_network = true; /* SSID BSSID frequency signal flags */ setWindowTitle(sel->text(0)); ssidEdit->setText(sel->text(0)); QString flags = sel->text(4); int auth, encr = 0; if (flags.indexOf("[WPA2-EAP") >= 0) auth = AUTH_WPA2_EAP; else if (flags.indexOf("[WPA-EAP") >= 0) auth = AUTH_WPA_EAP; else if (flags.indexOf("[WPA2-PSK") >= 0) auth = AUTH_WPA2_PSK; else if (flags.indexOf("[WPA-PSK") >= 0) auth = AUTH_WPA_PSK; else auth = AUTH_NONE_OPEN; if (flags.indexOf("-CCMP") >= 0) encr = 1; else if (flags.indexOf("-TKIP") >= 0) encr = 0; else if (flags.indexOf("WEP") >= 0) { encr = 1; if (auth == AUTH_NONE_OPEN) auth = AUTH_NONE_WEP; } else encr = 0; authSelect->setCurrentIndex(auth); authChanged(auth); encrSelect->setCurrentIndex(encr); wepEnabled(auth == AUTH_NONE_WEP); getEapCapa(); if (flags.indexOf("[WPS") >= 0) useWpsButton->setEnabled(true); bssid = sel->text(1); } void NetworkConfig::authChanged(int sel) { encrSelect->setEnabled(sel != AUTH_NONE_OPEN && sel != AUTH_NONE_WEP && sel != AUTH_NONE_WEP_SHARED); pskEdit->setEnabled(sel == AUTH_WPA_PSK || sel == AUTH_WPA2_PSK); bool eap = sel == AUTH_IEEE8021X || sel == AUTH_WPA_EAP || sel == AUTH_WPA2_EAP; eapSelect->setEnabled(eap); identityEdit->setEnabled(eap); passwordEdit->setEnabled(eap); cacertEdit->setEnabled(eap); phase2Select->setEnabled(eap); if (eap) eapChanged(eapSelect->currentIndex()); while (encrSelect->count()) encrSelect->removeItem(0); if (sel == AUTH_NONE_OPEN || sel == AUTH_NONE_WEP || sel == AUTH_NONE_WEP_SHARED || sel == AUTH_IEEE8021X) { encrSelect->addItem("None"); encrSelect->addItem("WEP"); encrSelect->setCurrentIndex(sel == AUTH_NONE_OPEN ? 0 : 1); } else { encrSelect->addItem("TKIP"); encrSelect->addItem("CCMP"); encrSelect->setCurrentIndex((sel == AUTH_WPA2_PSK || sel == AUTH_WPA2_EAP) ? 1 : 0); } wepEnabled(sel == AUTH_NONE_WEP || sel == AUTH_NONE_WEP_SHARED); } void NetworkConfig::eapChanged(int sel) { QString prev_val = phase2Select->currentText(); while (phase2Select->count()) phase2Select->removeItem(0); QStringList inner; inner << "PEAP" << "TTLS" << "FAST"; if (!inner.contains(eapSelect->itemText(sel))) return; phase2Select->addItem("[ any ]"); /* Add special cases based on outer method */ if (eapSelect->currentText().compare("TTLS") == 0) { phase2Select->addItem("PAP"); phase2Select->addItem("CHAP"); phase2Select->addItem("MSCHAP"); phase2Select->addItem("MSCHAPv2"); } else if (eapSelect->currentText().compare("FAST") == 0) phase2Select->addItem("GTC(auth) + MSCHAPv2(prov)"); /* Add all enabled EAP methods that can be used in the tunnel */ int i; QStringList allowed; allowed << "MSCHAPV2" << "MD5" << "GTC" << "TLS" << "OTP" << "SIM" << "AKA"; for (i = 0; i < eapSelect->count(); i++) { if (allowed.contains(eapSelect->itemText(i))) { phase2Select->addItem("EAP-" + eapSelect->itemText(i)); } } for (i = 0; i < phase2Select->count(); i++) { if (phase2Select->itemText(i).compare(prev_val) == 0) { phase2Select->setCurrentIndex(i); break; } } } void NetworkConfig::addNetwork() { char reply[10], cmd[256]; size_t reply_len; int id; int psklen = pskEdit->text().length(); int auth = authSelect->currentIndex(); if (auth == AUTH_WPA_PSK || auth == AUTH_WPA2_PSK) { if (psklen < 8 || psklen > 64) { QMessageBox::warning( this, tr("WPA Pre-Shared Key Error"), tr("WPA-PSK requires a passphrase of 8 to 63 " "characters\n" "or 64 hex digit PSK")); pskEdit->setFocus(); return; } } if (idstrEdit->isEnabled() && !idstrEdit->text().isEmpty()) { QRegExp rx("^(\\w|-)+$"); if (rx.indexIn(idstrEdit->text()) < 0) { QMessageBox::warning( this, tr("Network ID Error"), tr("Network ID String contains non-word " "characters.\n" "It must be a simple string, " "without spaces, containing\n" "only characters in this range: " "[A-Za-z0-9_-]\n")); idstrEdit->setFocus(); return; } } if (wpagui == NULL) return; memset(reply, 0, sizeof(reply)); reply_len = sizeof(reply) - 1; if (new_network) { wpagui->ctrlRequest("ADD_NETWORK", reply, &reply_len); if (reply[0] == 'F') { QMessageBox::warning(this, "wpa_gui", tr("Failed to add " "network to wpa_supplicant\n" "configuration.")); return; } id = atoi(reply); } else id = edit_network_id; setNetworkParam(id, "ssid", ssidEdit->text().toAscii().constData(), true); const char *key_mgmt = NULL, *proto = NULL, *pairwise = NULL; switch (auth) { case AUTH_NONE_OPEN: case AUTH_NONE_WEP: case AUTH_NONE_WEP_SHARED: key_mgmt = "NONE"; break; case AUTH_IEEE8021X: key_mgmt = "IEEE8021X"; break; case AUTH_WPA_PSK: key_mgmt = "WPA-PSK"; proto = "WPA"; break; case AUTH_WPA_EAP: key_mgmt = "WPA-EAP"; proto = "WPA"; break; case AUTH_WPA2_PSK: key_mgmt = "WPA-PSK"; proto = "WPA2"; break; case AUTH_WPA2_EAP: key_mgmt = "WPA-EAP"; proto = "WPA2"; break; } if (auth == AUTH_NONE_WEP_SHARED) setNetworkParam(id, "auth_alg", "SHARED", false); else setNetworkParam(id, "auth_alg", "OPEN", false); if (auth == AUTH_WPA_PSK || auth == AUTH_WPA_EAP || auth == AUTH_WPA2_PSK || auth == AUTH_WPA2_EAP) { int encr = encrSelect->currentIndex(); if (encr == 0) pairwise = "TKIP"; else pairwise = "CCMP"; } if (proto) setNetworkParam(id, "proto", proto, false); if (key_mgmt) setNetworkParam(id, "key_mgmt", key_mgmt, false); if (pairwise) { setNetworkParam(id, "pairwise", pairwise, false); setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false); } if (pskEdit->isEnabled() && strcmp(pskEdit->text().toAscii().constData(), WPA_GUI_KEY_DATA) != 0) setNetworkParam(id, "psk", pskEdit->text().toAscii().constData(), psklen != 64); if (eapSelect->isEnabled()) { const char *eap = eapSelect->currentText().toAscii().constData(); setNetworkParam(id, "eap", eap, false); if (strcmp(eap, "SIM") == 0 || strcmp(eap, "AKA") == 0) setNetworkParam(id, "pcsc", "", true); else setNetworkParam(id, "pcsc", "NULL", false); } if (phase2Select->isEnabled()) { QString eap = eapSelect->currentText(); QString inner = phase2Select->currentText(); char phase2[32]; phase2[0] = '\0'; if (eap.compare("PEAP") == 0) { if (inner.startsWith("EAP-")) snprintf(phase2, sizeof(phase2), "auth=%s", inner.right(inner.size() - 4). toAscii().constData()); } else if (eap.compare("TTLS") == 0) { if (inner.startsWith("EAP-")) snprintf(phase2, sizeof(phase2), "autheap=%s", inner.right(inner.size() - 4). toAscii().constData()); else snprintf(phase2, sizeof(phase2), "auth=%s", inner.toAscii().constData()); } else if (eap.compare("FAST") == 0) { const char *provisioning = NULL; if (inner.startsWith("EAP-")) { snprintf(phase2, sizeof(phase2), "auth=%s", inner.right(inner.size() - 4). toAscii().constData()); provisioning = "fast_provisioning=2"; } else if (inner.compare("GTC(auth) + MSCHAPv2(prov)") == 0) { snprintf(phase2, sizeof(phase2), "auth=GTC auth=MSCHAPV2"); provisioning = "fast_provisioning=1"; } else provisioning = "fast_provisioning=3"; if (provisioning) { char blob[32]; setNetworkParam(id, "phase1", provisioning, true); snprintf(blob, sizeof(blob), "blob://fast-pac-%d", id); setNetworkParam(id, "pac_file", blob, true); } } if (phase2[0]) setNetworkParam(id, "phase2", phase2, true); else setNetworkParam(id, "phase2", "NULL", false); } else setNetworkParam(id, "phase2", "NULL", false); if (identityEdit->isEnabled() && identityEdit->text().length() > 0) setNetworkParam(id, "identity", identityEdit->text().toAscii().constData(), true); else setNetworkParam(id, "identity", "NULL", false); if (passwordEdit->isEnabled() && passwordEdit->text().length() > 0 && strcmp(passwordEdit->text().toAscii().constData(), WPA_GUI_KEY_DATA) != 0) setNetworkParam(id, "password", passwordEdit->text().toAscii().constData(), true); else if (passwordEdit->text().length() == 0) setNetworkParam(id, "password", "NULL", false); if (cacertEdit->isEnabled() && cacertEdit->text().length() > 0) setNetworkParam(id, "ca_cert", cacertEdit->text().toAscii().constData(), true); else setNetworkParam(id, "ca_cert", "NULL", false); writeWepKey(id, wep0Edit, 0); writeWepKey(id, wep1Edit, 1); writeWepKey(id, wep2Edit, 2); writeWepKey(id, wep3Edit, 3); if (wep0Radio->isEnabled() && wep0Radio->isChecked()) setNetworkParam(id, "wep_tx_keyidx", "0", false); else if (wep1Radio->isEnabled() && wep1Radio->isChecked()) setNetworkParam(id, "wep_tx_keyidx", "1", false); else if (wep2Radio->isEnabled() && wep2Radio->isChecked()) setNetworkParam(id, "wep_tx_keyidx", "2", false); else if (wep3Radio->isEnabled() && wep3Radio->isChecked()) setNetworkParam(id, "wep_tx_keyidx", "3", false); if (idstrEdit->isEnabled() && idstrEdit->text().length() > 0) setNetworkParam(id, "id_str", idstrEdit->text().toAscii().constData(), true); else setNetworkParam(id, "id_str", "NULL", false); if (prioritySpinBox->isEnabled()) { QString prio; prio = prio.setNum(prioritySpinBox->value()); setNetworkParam(id, "priority", prio.toAscii().constData(), false); } snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %d", id); reply_len = sizeof(reply); wpagui->ctrlRequest(cmd, reply, &reply_len); if (strncmp(reply, "OK", 2) != 0) { QMessageBox::warning(this, "wpa_gui", tr("Failed to enable " "network in wpa_supplicant\n" "configuration.")); /* Network was added, so continue anyway */ } wpagui->triggerUpdate(); wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len); close(); } void NetworkConfig::setWpaGui(WpaGui *_wpagui) { wpagui = _wpagui; } int NetworkConfig::setNetworkParam(int id, const char *field, const char *value, bool quote) { char reply[10], cmd[256]; size_t reply_len; snprintf(cmd, sizeof(cmd), "SET_NETWORK %d %s %s%s%s", id, field, quote ? "\"" : "", value, quote ? "\"" : ""); reply_len = sizeof(reply); wpagui->ctrlRequest(cmd, reply, &reply_len); return strncmp(reply, "OK", 2) == 0 ? 0 : -1; } void NetworkConfig::encrChanged(const QString &) { } void NetworkConfig::wepEnabled(bool enabled) { wep0Edit->setEnabled(enabled); wep1Edit->setEnabled(enabled); wep2Edit->setEnabled(enabled); wep3Edit->setEnabled(enabled); wep0Radio->setEnabled(enabled); wep1Radio->setEnabled(enabled); wep2Radio->setEnabled(enabled); wep3Radio->setEnabled(enabled); } void NetworkConfig::writeWepKey(int network_id, QLineEdit *edit, int id) { char buf[10]; bool hex; const char *txt, *pos; size_t len; if (!edit->isEnabled() || edit->text().isEmpty()) return; /* * Assume hex key if only hex characters are present and length matches * with 40, 104, or 128-bit key */ txt = edit->text().toAscii().constData(); if (strcmp(txt, WPA_GUI_KEY_DATA) == 0) return; len = strlen(txt); if (len == 0) return; pos = txt; hex = true; while (*pos) { if (!((*pos >= '0' && *pos <= '9') || (*pos >= 'a' && *pos <= 'f') || (*pos >= 'A' && *pos <= 'F'))) { hex = false; break; } pos++; } if (hex && len != 10 && len != 26 && len != 32) hex = false; snprintf(buf, sizeof(buf), "wep_key%d", id); setNetworkParam(network_id, buf, txt, !hex); } static int key_value_isset(const char *reply, size_t reply_len) { return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0); } void NetworkConfig::paramsFromConfig(int network_id) { int i, res; edit_network_id = network_id; getEapCapa(); char reply[1024], cmd[256], *pos; size_t reply_len; snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 && reply[0] == '"') { reply[reply_len] = '\0'; pos = strchr(reply + 1, '"'); if (pos) *pos = '\0'; ssidEdit->setText(reply + 1); } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id); reply_len = sizeof(reply) - 1; int wpa = 0; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { reply[reply_len] = '\0'; if (strstr(reply, "RSN") || strstr(reply, "WPA2")) wpa = 2; else if (strstr(reply, "WPA")) wpa = 1; } int auth = AUTH_NONE_OPEN, encr = 0; snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { reply[reply_len] = '\0'; if (strstr(reply, "WPA-EAP")) auth = wpa & 2 ? AUTH_WPA2_EAP : AUTH_WPA_EAP; else if (strstr(reply, "WPA-PSK")) auth = wpa & 2 ? AUTH_WPA2_PSK : AUTH_WPA_PSK; else if (strstr(reply, "IEEE8021X")) { auth = AUTH_IEEE8021X; encr = 1; } } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { reply[reply_len] = '\0'; if (strstr(reply, "CCMP") && auth != AUTH_NONE_OPEN && auth != AUTH_NONE_WEP && auth != AUTH_NONE_WEP_SHARED) encr = 1; else if (strstr(reply, "TKIP")) encr = 0; else if (strstr(reply, "WEP")) encr = 1; else encr = 0; } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id); reply_len = sizeof(reply) - 1; res = wpagui->ctrlRequest(cmd, reply, &reply_len); if (res >= 0 && reply_len >= 2 && reply[0] == '"') { reply[reply_len] = '\0'; pos = strchr(reply + 1, '"'); if (pos) *pos = '\0'; pskEdit->setText(reply + 1); } else if (res >= 0 && key_value_isset(reply, reply_len)) { pskEdit->setText(WPA_GUI_KEY_DATA); } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 && reply[0] == '"') { reply[reply_len] = '\0'; pos = strchr(reply + 1, '"'); if (pos) *pos = '\0'; identityEdit->setText(reply + 1); } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id); reply_len = sizeof(reply) - 1; res = wpagui->ctrlRequest(cmd, reply, &reply_len); if (res >= 0 && reply_len >= 2 && reply[0] == '"') { reply[reply_len] = '\0'; pos = strchr(reply + 1, '"'); if (pos) *pos = '\0'; passwordEdit->setText(reply + 1); } else if (res >= 0 && key_value_isset(reply, reply_len)) { passwordEdit->setText(WPA_GUI_KEY_DATA); } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 && reply[0] == '"') { reply[reply_len] = '\0'; pos = strchr(reply + 1, '"'); if (pos) *pos = '\0'; cacertEdit->setText(reply + 1); } enum { NO_INNER, PEAP_INNER, TTLS_INNER, FAST_INNER } eap = NO_INNER; snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) { reply[reply_len] = '\0'; for (i = 0; i < eapSelect->count(); i++) { if (eapSelect->itemText(i).compare(reply) == 0) { eapSelect->setCurrentIndex(i); if (strcmp(reply, "PEAP") == 0) eap = PEAP_INNER; else if (strcmp(reply, "TTLS") == 0) eap = TTLS_INNER; else if (strcmp(reply, "FAST") == 0) eap = FAST_INNER; break; } } } if (eap != NO_INNER) { snprintf(cmd, sizeof(cmd), "GET_NETWORK %d phase2", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) { reply[reply_len] = '\0'; eapChanged(eapSelect->currentIndex()); } else eap = NO_INNER; } char *val; val = reply + 1; while (*(val + 1)) val++; if (*val == '"') *val = '\0'; switch (eap) { case PEAP_INNER: if (strncmp(reply, "\"auth=", 6)) break; val = reply + 2; memcpy(val, "EAP-", 4); break; case TTLS_INNER: if (strncmp(reply, "\"autheap=", 9) == 0) { val = reply + 5; memcpy(val, "EAP-", 4); } else if (strncmp(reply, "\"auth=", 6) == 0) val = reply + 6; break; case FAST_INNER: if (strncmp(reply, "\"auth=", 6)) break; if (strcmp(reply + 6, "GTC auth=MSCHAPV2") == 0) { val = (char *) "GTC(auth) + MSCHAPv2(prov)"; break; } val = reply + 2; memcpy(val, "EAP-", 4); break; case NO_INNER: break; } for (i = 0; i < phase2Select->count(); i++) { if (phase2Select->itemText(i).compare(val) == 0) { phase2Select->setCurrentIndex(i); break; } } for (i = 0; i < 4; i++) { QLineEdit *wepEdit; switch (i) { default: case 0: wepEdit = wep0Edit; break; case 1: wepEdit = wep1Edit; break; case 2: wepEdit = wep2Edit; break; case 3: wepEdit = wep3Edit; break; } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d", network_id, i); reply_len = sizeof(reply) - 1; res = wpagui->ctrlRequest(cmd, reply, &reply_len); if (res >= 0 && reply_len >= 2 && reply[0] == '"') { reply[reply_len] = '\0'; pos = strchr(reply + 1, '"'); if (pos) *pos = '\0'; if (auth == AUTH_NONE_OPEN || auth == AUTH_IEEE8021X) { if (auth == AUTH_NONE_OPEN) auth = AUTH_NONE_WEP; encr = 1; } wepEdit->setText(reply + 1); } else if (res >= 0 && key_value_isset(reply, reply_len)) { if (auth == AUTH_NONE_OPEN || auth == AUTH_IEEE8021X) { if (auth == AUTH_NONE_OPEN) auth = AUTH_NONE_WEP; encr = 1; } wepEdit->setText(WPA_GUI_KEY_DATA); } } if (auth == AUTH_NONE_WEP) { snprintf(cmd, sizeof(cmd), "GET_NETWORK %d auth_alg", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { reply[reply_len] = '\0'; if (strcmp(reply, "SHARED") == 0) auth = AUTH_NONE_WEP_SHARED; } } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) { reply[reply_len] = '\0'; switch (atoi(reply)) { case 0: wep0Radio->setChecked(true); break; case 1: wep1Radio->setChecked(true); break; case 2: wep2Radio->setChecked(true); break; case 3: wep3Radio->setChecked(true); break; } } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d id_str", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 && reply[0] == '"') { reply[reply_len] = '\0'; pos = strchr(reply + 1, '"'); if (pos) *pos = '\0'; idstrEdit->setText(reply + 1); } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d priority", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) { reply[reply_len] = '\0'; prioritySpinBox->setValue(atoi(reply)); } authSelect->setCurrentIndex(auth); authChanged(auth); encrSelect->setCurrentIndex(encr); wepEnabled(auth == AUTH_NONE_WEP || auth == AUTH_NONE_WEP_SHARED); removeButton->setEnabled(true); addButton->setText("Save"); } void NetworkConfig::removeNetwork() { char reply[10], cmd[256]; size_t reply_len; if (QMessageBox::information( this, "wpa_gui", tr("This will permanently remove the network\n" "from the configuration. Do you really want\n" "to remove this network?"), tr("Yes"), tr("No")) != 0) return; snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id); reply_len = sizeof(reply); wpagui->ctrlRequest(cmd, reply, &reply_len); if (strncmp(reply, "OK", 2) != 0) { QMessageBox::warning(this, "wpa_gui", tr("Failed to remove network from " "wpa_supplicant\n" "configuration.")); } else { wpagui->triggerUpdate(); wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len); } close(); } void NetworkConfig::newNetwork() { new_network = true; getEapCapa(); } void NetworkConfig::getEapCapa() { char reply[256]; size_t reply_len; if (wpagui == NULL) return; reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest("GET_CAPABILITY eap", reply, &reply_len) < 0) return; reply[reply_len] = '\0'; QString res(reply); QStringList types = res.split(QChar(' ')); eapSelect->insertItems(-1, types); } void NetworkConfig::useWps() { if (wpagui == NULL) return; wpagui->setBssFromScan(bssid); wpagui->wpsDialog(); close(); } wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui0000664000175000017500000000616512343617166023201 0ustar jmjm UserDataRequest 0 0 216 103 Authentication credentials required true 0 true QLineEdit::Password 0 20 20 Expanding Horizontal &OK true true &Cancel true wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/scanresults.cpp0000664000175000017500000000535112343617166022467 0ustar jmjm/* * wpa_gui - ScanResults class * Copyright (c) 2005-2006, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include #include "scanresults.h" #include "signalbar.h" #include "wpagui.h" #include "networkconfig.h" ScanResults::ScanResults(QWidget *parent, const char *, bool, Qt::WFlags) : QDialog(parent) { setupUi(this); connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); connect(scanButton, SIGNAL(clicked()), this, SLOT(scanRequest())); connect(scanResultsWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(bssSelected(QTreeWidgetItem *))); wpagui = NULL; scanResultsWidget->setItemsExpandable(FALSE); scanResultsWidget->setRootIsDecorated(FALSE); scanResultsWidget->setItemDelegate(new SignalBar(scanResultsWidget)); } ScanResults::~ScanResults() { } void ScanResults::languageChange() { retranslateUi(this); } void ScanResults::setWpaGui(WpaGui *_wpagui) { wpagui = _wpagui; updateResults(); } void ScanResults::updateResults() { char reply[2048]; size_t reply_len; int index; char cmd[20]; scanResultsWidget->clear(); index = 0; while (wpagui) { snprintf(cmd, sizeof(cmd), "BSS %d", index++); if (index > 1000) break; reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) break; reply[reply_len] = '\0'; QString bss(reply); if (bss.isEmpty() || bss.startsWith("FAIL")) break; QString ssid, bssid, freq, signal, flags; QStringList lines = bss.split(QRegExp("\\n")); for (QStringList::Iterator it = lines.begin(); it != lines.end(); it++) { int pos = (*it).indexOf('=') + 1; if (pos < 1) continue; if ((*it).startsWith("bssid=")) bssid = (*it).mid(pos); else if ((*it).startsWith("freq=")) freq = (*it).mid(pos); else if ((*it).startsWith("level=")) signal = (*it).mid(pos); else if ((*it).startsWith("flags=")) flags = (*it).mid(pos); else if ((*it).startsWith("ssid=")) ssid = (*it).mid(pos); } QTreeWidgetItem *item = new QTreeWidgetItem(scanResultsWidget); if (item) { item->setText(0, ssid); item->setText(1, bssid); item->setText(2, freq); item->setText(3, signal); item->setText(4, flags); } if (bssid.isEmpty()) break; } } void ScanResults::scanRequest() { char reply[10]; size_t reply_len = sizeof(reply); if (wpagui == NULL) return; wpagui->ctrlRequest("SCAN", reply, &reply_len); } void ScanResults::getResults() { updateResults(); } void ScanResults::bssSelected(QTreeWidgetItem *sel) { NetworkConfig *nc = new NetworkConfig(); if (nc == NULL) return; nc->setWpaGui(wpagui); nc->paramsFromScanResults(sel); nc->show(); nc->exec(); } wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/wpamsg.h0000664000175000017500000000132512343617166021061 0ustar jmjm/* * wpa_gui - WpaMsg class for storing event messages * Copyright (c) 2005-2006, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef WPAMSG_H #define WPAMSG_H #include #include class WpaMsg { public: WpaMsg(const QString &_msg, int _priority = 2) : msg(_msg), priority(_priority) { timestamp = QDateTime::currentDateTime(); } QString getMsg() const { return msg; } int getPriority() const { return priority; } QDateTime getTimestamp() const { return timestamp; } private: QString msg; int priority; QDateTime timestamp; }; typedef QLinkedList WpaMsgList; #endif /* WPAMSG_H */ wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/.gitignore0000664000175000017500000000003412343617166021376 0ustar jmjm.moc .obj .ui qrc_icons.cpp wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/eventhistory.ui0000664000175000017500000000303012343617166022507 0ustar jmjm EventHistory 0 0 533 285 Event history 0 0 Qt::ScrollBarAlwaysOn QAbstractItemView::NoSelection Qt::Horizontal 40 20 Close wpamsg.h wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro0000664000175000017500000000264312343617166021573 0ustar jmjmTEMPLATE = app LANGUAGE = C++ TRANSLATIONS = lang/wpa_gui_de.ts CONFIG += qt warn_on release DEFINES += CONFIG_CTRL_IFACE win32 { LIBS += -lws2_32 -static DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE SOURCES += ../../src/utils/os_win32.c } else:win32-g++ { # cross compilation to win32 LIBS += -lws2_32 -static -mwindows DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE SOURCES += ../../src/utils/os_win32.c RESOURCES += icons_png.qrc } else:win32-x-g++ { # cross compilation to win32 LIBS += -lws2_32 -static -mwindows DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE DEFINES += _X86_ SOURCES += ../../src/utils/os_win32.c RESOURCES += icons_png.qrc } else { DEFINES += CONFIG_CTRL_IFACE_UNIX SOURCES += ../../src/utils/os_unix.c } INCLUDEPATH += . .. ../../src ../../src/utils HEADERS += wpamsg.h \ wpagui.h \ eventhistory.h \ scanresults.h \ signalbar.h \ userdatarequest.h \ networkconfig.h \ addinterface.h \ peers.h \ stringquery.h SOURCES += main.cpp \ wpagui.cpp \ eventhistory.cpp \ scanresults.cpp \ signalbar.cpp \ userdatarequest.cpp \ networkconfig.cpp \ addinterface.cpp \ peers.cpp \ stringquery.cpp \ ../../src/common/wpa_ctrl.c RESOURCES += icons.qrc FORMS = wpagui.ui \ eventhistory.ui \ scanresults.ui \ userdatarequest.ui \ networkconfig.ui \ peers.ui unix { UI_DIR = .ui MOC_DIR = .moc OBJECTS_DIR = .obj } wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/networkconfig.ui0000664000175000017500000003041112343617166022626 0ustar jmjm NetworkConfig 0 0 410 534 NetworkConfig Cancel QFrame::NoFrame QFrame::Plain SSID Network name (Service Set IDentifier) Authentication Plaintext (open / no authentication) Static WEP (no authentication) Static WEP (Shared Key authentication) IEEE 802.1X WPA-Personal (PSK) WPA-Enterprise (EAP) WPA2-Personal (PSK) WPA2-Enterprise (EAP) Encryption None WEP TKIP CCMP PSK false WPA/WPA2 pre-shared key or passphrase QLineEdit::Password EAP method false Identity false Username/Identity for EAP methods Password false Password for EAP methods QLineEdit::Password CA certificate false true WEP keys false key 0 false key 1 false key 3 false key 2 false false false false true Optional Settings Network Identification String Network Priority 10000 10 IDString Priority Inner auth false Add false Remove Qt::Vertical 20 40 false WPS ssidEdit authSelect encrSelect pskEdit eapSelect identityEdit passwordEdit cacertEdit wep0Radio wep0Edit wep1Radio wep1Edit wep2Radio wep2Edit wep3Radio wep3Edit idstrEdit prioritySpinBox phase2Select addButton removeButton cancelButton qtreewidget.h wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/wpagui.ui0000664000175000017500000003663412343617166021260 0ustar jmjm WpaGui 0 0 345 330 wpa_gui :/icons/wpa_gui.svg:/icons/wpa_gui.svg Adapter: Network: 0 Current Status QFrame::NoFrame QFrame::Plain Status: Last message: Authentication: Encryption: SSID: BSSID: IP address: Qt::Vertical 20 40 Connect Disconnect Scan Qt::Vertical 20 40 Manage Networks true Qt::Vertical 20 61 Enabled Edit Remove Qt::Vertical 20 61 Disabled Add Scan WPS Status: PBC - push button Generate PIN PIN: false true false Use AP PIN AP PIN: false true 0 0 345 24 &File &Network &Help Event &History &Save Configuration Ctrl+S E&xit Ctrl+Q &Add &Edit &Remove E&nable All &Disable All Re&move All false &Contents... false &Index... &About false &Wi-Fi Protected Setup &Peers qtimer.h qsocketnotifier.h wpamsg.h eventhistory.h scanresults.h peers.h wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp0000664000175000017500000000376112343617166023345 0ustar jmjm/* * wpa_gui - UserDataRequest class * Copyright (c) 2005-2006, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "userdatarequest.h" #include "wpagui.h" #include "common/wpa_ctrl.h" UserDataRequest::UserDataRequest(QWidget *parent, const char *, bool, Qt::WFlags) : QDialog(parent) { setupUi(this); connect(buttonOk, SIGNAL(clicked()), this, SLOT(sendReply())); connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject())); connect(queryEdit, SIGNAL(returnPressed()), this, SLOT(sendReply())); } UserDataRequest::~UserDataRequest() { } void UserDataRequest::languageChange() { retranslateUi(this); } int UserDataRequest::setParams(WpaGui *_wpagui, const char *reqMsg) { char *tmp, *pos, *pos2; wpagui = _wpagui; tmp = strdup(reqMsg); if (tmp == NULL) return -1; pos = strchr(tmp, '-'); if (pos == NULL) { free(tmp); return -1; } *pos++ = '\0'; field = tmp; pos2 = strchr(pos, ':'); if (pos2 == NULL) { free(tmp); return -1; } *pos2++ = '\0'; networkid = atoi(pos); queryInfo->setText(pos2); if (strcmp(tmp, "PASSWORD") == 0) { queryField->setText(tr("Password: ")); queryEdit->setEchoMode(QLineEdit::Password); } else if (strcmp(tmp, "NEW_PASSWORD") == 0) { queryField->setText(tr("New password: ")); queryEdit->setEchoMode(QLineEdit::Password); } else if (strcmp(tmp, "IDENTITY") == 0) queryField->setText(tr("Identity: ")); else if (strcmp(tmp, "PASSPHRASE") == 0) { queryField->setText(tr("Private key passphrase: ")); queryEdit->setEchoMode(QLineEdit::Password); } else queryField->setText(field + ":"); free(tmp); return 0; } void UserDataRequest::sendReply() { char reply[10]; size_t reply_len = sizeof(reply); if (wpagui == NULL) { reject(); return; } QString cmd = QString(WPA_CTRL_RSP) + field + '-' + QString::number(networkid) + ':' + queryEdit->text(); wpagui->ctrlRequest(cmd.toAscii().constData(), reply, &reply_len); accept(); } wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/wpagui.h0000664000175000017500000000717312343617166021066 0ustar jmjm/* * wpa_gui - WpaGui class * Copyright (c) 2005-2006, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef WPAGUI_H #define WPAGUI_H #include #include #include "ui_wpagui.h" #include "addinterface.h" class UserDataRequest; class WpaGui : public QMainWindow, public Ui::WpaGui { Q_OBJECT public: WpaGui(QApplication *app, QWidget *parent = 0, const char *name = 0, Qt::WFlags fl = 0); ~WpaGui(); virtual int ctrlRequest(const char *cmd, char *buf, size_t *buflen); virtual void triggerUpdate(); virtual void editNetwork(const QString &sel); virtual void removeNetwork(const QString &sel); virtual void enableNetwork(const QString &sel); virtual void disableNetwork(const QString &sel); virtual int getNetworkDisabled(const QString &sel); void setBssFromScan(const QString &bssid); #ifndef QT_NO_SESSIONMANAGER void saveState(); #endif public slots: virtual void parse_argv(); virtual void updateStatus(); virtual void updateNetworks(); virtual void helpIndex(); virtual void helpContents(); virtual void helpAbout(); virtual void disconnect(); virtual void scan(); virtual void eventHistory(); virtual void ping(); virtual void processMsg(char *msg); virtual void processCtrlReq(const char *req); virtual void receiveMsgs(); virtual void connectB(); virtual void selectNetwork(const QString &sel); virtual void editSelectedNetwork(); virtual void editListedNetwork(); virtual void removeSelectedNetwork(); virtual void removeListedNetwork(); virtual void addNetwork(); virtual void enableAllNetworks(); virtual void disableAllNetworks(); virtual void removeAllNetworks(); virtual void saveConfig(); virtual void selectAdapter(const QString &sel); virtual void updateNetworkDisabledStatus(); virtual void enableListedNetwork(bool); virtual void disableListedNetwork(bool); virtual void showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec, const QString &msg); virtual void showTrayStatus(); virtual void wpsDialog(); virtual void peersDialog(); virtual void tabChanged(int index); virtual void wpsPbc(); virtual void wpsGeneratePin(); virtual void wpsApPinChanged(const QString &text); virtual void wpsApPin(); #ifdef CONFIG_NATIVE_WINDOWS virtual void startService(); virtual void stopService(); #endif /* CONFIG_NATIVE_WINDOWS */ virtual void addInterface(); protected slots: virtual void languageChange(); virtual void trayActivated(QSystemTrayIcon::ActivationReason how); virtual void closeEvent(QCloseEvent *event); private: ScanResults *scanres; Peers *peers; bool networkMayHaveChanged; char *ctrl_iface; EventHistory *eh; struct wpa_ctrl *ctrl_conn; QSocketNotifier *msgNotifier; QTimer *timer; int pingsToStatusUpdate; WpaMsgList msgs; char *ctrl_iface_dir; struct wpa_ctrl *monitor_conn; UserDataRequest *udr; QAction *disconnectAction; QAction *reconnectAction; QAction *eventAction; QAction *scanAction; QAction *statAction; QAction *showAction; QAction *hideAction; QAction *quitAction; QMenu *tray_menu; QSystemTrayIcon *tray_icon; QString wpaStateTranslate(char *state); void createTrayIcon(bool); bool ackTrayIcon; bool startInTray; int openCtrlConnection(const char *ifname); bool wpsRunning; QString bssFromScan; void stopWpsRun(bool success); #ifdef CONFIG_NATIVE_WINDOWS QAction *fileStartServiceAction; QAction *fileStopServiceAction; bool serviceRunning(); #endif /* CONFIG_NATIVE_WINDOWS */ QAction *addInterfaceAction; AddInterface *add_iface; bool connectedToService; QApplication *app; bool inTray; }; #endif /* WPAGUI_H */ wpa_supplicant-2.2/wpa_supplicant/wpa_gui-qt4/userdatarequest.h0000664000175000017500000000140612343617166023004 0ustar jmjm/* * wpa_gui - UserDataRequest class * Copyright (c) 2005-2006, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef USERDATAREQUEST_H #define USERDATAREQUEST_H #include #include "ui_userdatarequest.h" class WpaGui; class UserDataRequest : public QDialog, public Ui::UserDataRequest { Q_OBJECT public: UserDataRequest(QWidget *parent = 0, const char *name = 0, bool modal = false, Qt::WFlags fl = 0); ~UserDataRequest(); int setParams(WpaGui *_wpagui, const char *reqMsg); public slots: virtual void sendReply(); protected slots: virtual void languageChange(); private: WpaGui *wpagui; int networkid; QString field; }; #endif /* USERDATAREQUEST_H */ wpa_supplicant-2.2/wpa_supplicant/systemd/0000775000175000017500000000000012343617166016740 5ustar jmjmwpa_supplicant-2.2/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in0000664000175000017500000000066612343617166025650 0ustar jmjm[Unit] Description=WPA supplicant daemon (interface- and wired driver-specific version) Requires=sys-subsystem-net-devices-%i.device After=sys-subsystem-net-devices-%i.device # NetworkManager users will probably want the dbus version instead. [Service] Type=simple ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-wired-%I.conf -Dwired -i%I [Install] Alias=multi-user.target.wants/wpa_supplicant-wired@%i.service wpa_supplicant-2.2/wpa_supplicant/systemd/wpa_supplicant.service.arg.in0000664000175000017500000000062012343617166024526 0ustar jmjm[Unit] Description=WPA supplicant daemon (interface-specific version) Requires=sys-subsystem-net-devices-%i.device After=sys-subsystem-net-devices-%i.device # NetworkManager users will probably want the dbus version instead. [Service] Type=simple ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I [Install] Alias=multi-user.target.wants/wpa_supplicant@%i.service wpa_supplicant-2.2/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in0000664000175000017500000000067612343617166025544 0ustar jmjm[Unit] Description=WPA supplicant daemon (interface- and nl80211 driver-specific version) Requires=sys-subsystem-net-devices-%i.device After=sys-subsystem-net-devices-%i.device # NetworkManager users will probably want the dbus version instead. [Service] Type=simple ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-%I.conf -Dnl80211 -i%I [Install] Alias=multi-user.target.wants/wpa_supplicant-nl80211@%i.service wpa_supplicant-2.2/wpa_supplicant/systemd/wpa_supplicant.service.in0000664000175000017500000000033512343617166023761 0ustar jmjm[Unit] Description=WPA supplicant [Service] Type=dbus BusName=fi.epitest.hostap.WPASupplicant ExecStart=@BINDIR@/wpa_supplicant -u [Install] WantedBy=multi-user.target Alias=dbus-fi.epitest.hostap.WPASupplicant.service wpa_supplicant-2.2/wpa_supplicant/utils/0000775000175000017500000000000012343617166016410 5ustar jmjmwpa_supplicant-2.2/wpa_supplicant/utils/log2pcap.py0000775000175000017500000000273312343617166020501 0ustar jmjm#!/usr/bin/env python # # Copyright (c) 2012, Intel Corporation # # Author: Johannes Berg # # This software may be distributed under the terms of the BSD license. # See README for more details. import sys, struct, re def write_pcap_header(pcap_file): pcap_file.write( struct.pack(' " % sys.argv[0] sys.exit(2) input_file = open(input, 'r') pcap_file = open(pcap, 'w') frame_re = re.compile(r'(([0-9]+.[0-9]{6}):\s*)?nl80211: MLME event frame - hexdump\(len=[0-9]*\):((\s*[0-9a-fA-F]{2})*)') write_pcap_header(pcap_file) for line in input_file: m = frame_re.match(line) if m is None: continue if m.group(2): ts = float(m.group(2)) else: ts = 0 hexdata = m.group(3) hexdata = hexdata.split() data = ''.join([chr(int(x, 16)) for x in hexdata]) pcap_addpacket(pcap_file, ts, data) input_file.close() pcap_file.close() wpa_supplicant-2.2/wpa_supplicant/eap_proxy_dummy.mak0000664000175000017500000000000012343617166021151 0ustar jmjmwpa_supplicant-2.2/wpa_supplicant/README-P2P0000664000175000017500000005317712343617166016544 0ustar jmjmwpa_supplicant and Wi-Fi P2P ============================ This document describes how the Wi-Fi P2P implementation in wpa_supplicant can be configured and how an external component on the client (e.g., management GUI) is used to enable WPS enrollment and registrar registration. Introduction to Wi-Fi P2P ------------------------- TODO More information about Wi-Fi P2P is available from Wi-Fi Alliance: http://www.wi-fi.org/Wi-Fi_Direct.php wpa_supplicant implementation ----------------------------- TODO wpa_supplicant configuration ---------------------------- Wi-Fi P2P is an optional component that needs to be enabled in the wpa_supplicant build configuration (.config). Here is an example configuration that includes Wi-Fi P2P support and Linux nl80211 -based driver interface: CONFIG_DRIVER_NL80211=y CONFIG_CTRL_IFACE=y CONFIG_P2P=y CONFIG_AP=y CONFIG_WPS=y In run-time configuration file (wpa_supplicant.conf), some parameters for P2P may be set. In order to make the devices easier to recognize, device_name and device_type should be specified. For example, something like this should be included: ctrl_interface=/var/run/wpa_supplicant device_name=My P2P Device device_type=1-0050F204-1 wpa_cli ------- Actual Wi-Fi P2P operations are requested during runtime. These can be done for example using wpa_cli (which is described below) or a GUI like wpa_gui-qt4. wpa_cli starts in interactive mode if no command string is included on the command line. By default, it will select the first network interface that it can find (and that wpa_supplicant controls). If more than one interface is in use, it may be necessary to select one of the explicitly by adding -i argument on the command line (e.g., 'wpa_cli -i wlan1'). Most of the P2P operations are done on the main interface (e.g., the interface that is automatically added when the driver is loaded, e.g., wlan0). When using a separate virtual interface for group operations (e.g., wlan1), the control interface for that group interface may need to be used for some operations (mainly WPS activation in GO). This may change in the future so that all the needed operations could be done over the main control interface. Device Discovery p2p_find [timeout in seconds] [type=] \ [dev_id=] [dev_type=] \ [delay=] The default behavior is to run a single full scan in the beginning and then scan only social channels. type=social will scan only social channels, i.e., it skips the initial full scan. type=progressive is like the default behavior, but it will scan through all the channels progressively one channel at the time in the Search state rounds. This will help in finding new groups or groups missed during the initial full scan. The optional dev_id option can be used to specify a single P2P peer to search for. The optional delay parameter can be used to request an extra delay to be used between search iterations (e.g., to free up radio resources for concurrent operations). The optional dev_type option can be used to specify a single device type (primary or secondary) to search for, e.g., "p2p_find dev_type=1-0050F204-1". p2p_listen [timeout in seconds] Start Listen-only state (become discoverable without searching for other devices). Optional parameter can be used to specify the duration for the Listen operation in seconds. This command may not be of that much use during normal operations and is mainly designed for testing. It can also be used to keep the device discoverable without having to maintain a group. p2p_stop_find Stop ongoing P2P device discovery or other operation (connect, listen mode). p2p_flush Flush P2P peer table and state. Group Formation p2p_prov_disc [join|auto] Send P2P provision discovery request to the specified peer. The parameters for this command are the P2P device address of the peer and the desired configuration method. For example, "p2p_prov_disc 02:01:02:03:04:05 display" would request the peer to display a PIN for us and "p2p_prov_disc 02:01:02:03:04:05 keypad" would request the peer to enter a PIN that we display. The optional "join" parameter can be used to indicate that this command is requesting an already running GO to prepare for a new client. This is mainly used with "display" to request it to display a PIN. The "auto" parameter can be used to request wpa_supplicant to automatically figure out whether the peer device is operating as a GO and if so, use join-a-group style PD instead of GO Negotiation style PD. p2p_connect [display|keypad] [persistent|persistent=] [join|auth] [go_intent=<0..15>] [freq=] [ht40] [vht] [provdisc] Start P2P group formation with a discovered P2P peer. This includes optional group owner negotiation, group interface setup, provisioning, and establishing data connection. The parameter specifies the WPS provisioning method. "pbc" string starts pushbutton method, "pin" string start PIN method using an automatically generated PIN (which will be returned as the command return code), PIN# means that a pre-selected PIN can be used (e.g., 12345670). [display|keypad] is used with PIN method to specify which PIN is used (display=dynamically generated random PIN from local display, keypad=PIN entered from peer display). "persistent" parameter can be used to request a persistent group to be formed. The "persistent=" alternative can be used to pre-populate SSID/passphrase configuration based on a previously used persistent group where this device was the GO. The previously used parameters will then be used if the local end becomes the GO in GO Negotiation (which can be forced with go_intent=15). "join" indicates that this is a command to join an existing group as a client. It skips the GO Negotiation part. This will send a Provision Discovery Request message to the target GO before associating for WPS provisioning. "auth" indicates that the WPS parameters are authorized for the peer device without actually starting GO Negotiation (i.e., the peer is expected to initiate GO Negotiation). This is mainly for testing purposes. "go_intent" can be used to override the default GO Intent for this GO Negotiation. "freq" can be used to set a forced operating channel (e.g., freq=2412 to select 2.4 GHz channel 1). "provdisc" can be used to request a Provision Discovery exchange to be used prior to starting GO Negotiation as a workaround with some deployed P2P implementations that require this to allow the user to accept the connection. p2p_group_add [persistent|persistent=] [freq=] [ht40] [vht] Set up a P2P group owner manually (i.e., without group owner negotiation with a specific peer). This is also known as autonomous GO. Optional persistent= can be used to specify restart of a persistent group. Optional freq= can be used to force the GO to be started on a specific frequency. Special freq=2 or freq=5 options can be used to request the best 2.4 GHz or 5 GHz band channel to be selected automatically. p2p_reject Reject connection attempt from a peer (specified with a device address). This is a mechanism to reject a pending GO Negotiation with a peer and request to automatically block any further connection or discovery of the peer. p2p_group_remove Terminate a P2P group. If a new virtual network interface was used for the group, it will also be removed. The network interface name of the group interface is used as a parameter for this command. p2p_cancel Cancel an ongoing P2P group formation and joining-a-group related operation. This operations unauthorizes the specific peer device (if any had been authorized to start group formation), stops P2P find (if in progress), stops pending operations for join-a-group, and removes the P2P group interface (if one was used) that is in the WPS provisioning step. If the WPS provisioning step has been completed, the group is not terminated. p2p_remove_client > This command can be used to remove the specified client from all groups (operating and persistent) from the local GO. Note that the peer device can rejoin the group if it is in possession of a valid key. See p2p_set per_sta_psk command below for more details on how the peer can be removed securely. Service Discovery p2p_serv_disc_req Schedule a P2P service discovery request. The parameters for this command are the device address of the peer device (or 00:00:00:00:00:00 for wildcard query that is sent to every discovered P2P peer that supports service discovery) and P2P Service Query TLV(s) as hexdump. For example, p2p_serv_disc_req 00:00:00:00:00:00 02000001 schedules a request for listing all available services of all service discovery protocols and requests this to be sent to all discovered peers (note: this can result in long response frames). The pending requests are sent during device discovery (see p2p_find). There can be multiple pending peer device specific queries (each will be sent in sequence whenever the peer is found). This command returns an identifier for the pending query (e.g., "1f77628") that can be used to cancel the request. Directed requests will be automatically removed when the specified peer has replied to it. Service Query TLV has following format: Length (2 octets, little endian) - length of following data Service Protocol Type (1 octet) - see the table below Service Transaction ID (1 octet) - nonzero identifier for the TLV Query Data (Length - 2 octets of data) - service protocol specific data Service Protocol Types: 0 = All service protocols 1 = Bonjour 2 = UPnP 3 = WS-Discovery 4 = Wi-Fi Display For UPnP, an alternative command format can be used to specify a single query TLV (i.e., a service discovery for a specific UPnP service): p2p_serv_disc_req 00:00:00:00:00:00 upnp For example: p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1 Additional examples for queries: # list of all Bonjour services p2p_serv_disc_req 00:00:00:00:00:00 02000101 # list of all UPnP services p2p_serv_disc_req 00:00:00:00:00:00 02000201 # list of all WS-Discovery services p2p_serv_disc_req 00:00:00:00:00:00 02000301 # list of all Bonjour and UPnP services p2p_serv_disc_req 00:00:00:00:00:00 0200010102000202 # Apple File Sharing over TCP p2p_serv_disc_req 00:00:00:00:00:00 130001010b5f6166706f766572746370c00c000c01 # Bonjour SSTH (supported service type hash) p2p_serv_disc_req 00:00:00:00:00:00 05000101000000 # UPnP examples p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 ssdp:all p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 upnp:rootdevice p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:service:ContentDirectory:2 p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 uuid:6859dede-8574-59ab-9332-123456789012 p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1 # Wi-Fi Display examples # format: wifi-display p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source] 2,3,4,5 p2p_serv_disc_req 02:01:02:03:04:05 wifi-display [pri-sink] 3 p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [sec-source] 2 p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source+sink] 2,3,4,5 p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source][pri-sink] 2,3,4,5 p2p_serv_disc_cancel_req Cancel a pending P2P service discovery request. This command takes a single parameter: identifier for the pending query (the value returned by p2p_serv_disc_req, e.g., "p2p_serv_disc_cancel_req 1f77628". p2p_serv_disc_resp Reply to a service discovery query. This command takes following parameters: frequency in MHz, destination address, dialog token, response TLV(s). The first three parameters are copied from the request event. For example, "p2p_serv_disc_resp 2437 02:40:61:c2:f3:b7 1 0300000101". This command is used only if external program is used to process the request (see p2p_serv_disc_external). p2p_service_update Indicate that local services have changed. This is used to increment the P2P service indicator value so that peers know when previously cached information may have changed. This is only needed when external service discovery processing is enabled since the commands to pre-configure services for internal processing will increment the indicator automatically. p2p_serv_disc_external <0|1> Configure external processing of P2P service requests: 0 (default) = no external processing of requests (i.e., internal code will process each request based on pre-configured services), 1 = external processing of requests (external program is responsible for replying to service discovery requests with p2p_serv_disc_resp). Please note that there is quite strict limit on how quickly the response needs to be transmitted, so use of the internal processing is strongly recommended. p2p_service_add bonjour Add a local Bonjour service for internal SD query processing. Examples: # AFP Over TCP (PTR) p2p_service_add bonjour 0b5f6166706f766572746370c00c000c01 074578616d706c65c027 # AFP Over TCP (TXT) (RDATA=null) p2p_service_add bonjour 076578616d706c650b5f6166706f766572746370c00c001001 00 # IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.) p2p_service_add bonjour 045f697070c00c000c01 094d795072696e746572c027 # IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript) p2p_service_add bonjour 096d797072696e746572045f697070c00c001001 09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074 # Supported Service Type Hash (SSTH) p2p_service_add bonjour 000000 <32-byte bitfield as hexdump> (note: see P2P spec Annex E.4 for information on how to construct the bitfield) p2p_service_del bonjour Remove a local Bonjour service from internal SD query processing. p2p_service_add upnp Add a local UPnP service for internal SD query processing. Examples: p2p_service_add upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice p2p_service_add upnp 10 uuid:5566d33e-9774-09ab-4822-333456785632::upnp:rootdevice p2p_service_add upnp 10 uuid:1122de4e-8574-59ab-9322-333456789044::urn:schemas-upnp-org:service:ContentDirectory:2 p2p_service_add upnp 10 uuid:5566d33e-9774-09ab-4822-333456785632::urn:schemas-upnp-org:service:ContentDirectory:2 p2p_service_add upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp-org:device:InternetGatewayDevice:1 p2p_service_del upnp Remove a local UPnP service from internal SD query processing. p2p_service_flush Remove all local services from internal SD query processing. Invitation p2p_invite [persistent=|group=] [peer=address] [go_dev_addr=address] [freq=] [ht40] [vht] [pref=] Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a persistent group (e.g., persistent=4). If the peer device is the GO of the persistent group, the peer parameter is not needed. Otherwise it is used to specify which device to invite. go_dev_addr parameter can be used to override the GO device address for Invitation Request should it be not known for some reason (this should not be needed in most cases). When reinvoking a persistent group, the GO device can specify the frequency for the group with the freq parameter. When reinvoking a persistent group, the P2P client device can use freq parameter to force a specific operating channel (or invitation failure if GO rejects that) or pref parameter to request a specific channel (while allowing GO to select to use another channel, if needed). Group Operations (These are used on the group interface.) wps_pin Start WPS PIN method. This allows a single WPS Enrollee to connect to the AP/GO. This is used on the GO when a P2P client joins an existing group. The second parameter is the address of the Enrollee or a string "any" to allow any station to use the entered PIN (which will restrict the PIN for one-time-use). PIN is the Enrollee PIN read either from a label or display on the P2P Client/WPS Enrollee. wps_pbc Start WPS PBC method (i.e., push the button). This allows a single WPS Enrollee to connect to the AP/GO. This is used on the GO when a P2P client joins an existing group. p2p_get_passphrase Get the passphrase for a group (only available when acting as a GO). p2p_presence_req [ ] [ ] Send a P2P Presence Request to the GO (this is only available when acting as a P2P client). If no duration/interval pairs are given, the request indicates that this client has no special needs for GO presence. The first parameter pair gives the preferred duration and interval values in microseconds. If the second pair is included, that indicates which value would be acceptable. This command returns OK immediately and the response from the GO is indicated in a P2P-PRESENCE-RESPONSE event message. Parameters p2p_ext_listen [ ] Configure Extended Listen Timing. If the parameters are omitted, this feature is disabled. If the parameters are included, Listen State will be entered every interval msec for at least period msec. Both values have acceptable range of 1-65535 (with interval obviously having to be larger than or equal to duration). If the P2P module is not idle at the time the Extended Listen Timing timeout occurs, the Listen State operation will be skipped. The configured values will also be advertised to other P2P Devices. The received values are available in the p2p_peer command output: ext_listen_period=100 ext_listen_interval=5000 p2p_set Change dynamic P2P parameters p2p_set discoverability <0/1> Disable/enable advertisement of client discoverability. This is enabled by default and this parameter is mainly used to allow testing of device discoverability. p2p_set managed <0/1> Disable/enable managed P2P Device operations. This is disabled by default. p2p_set listen_channel <1/6/11> Set P2P Listen channel. This is mainly meant for testing purposes and changing the Listen channel during normal operations can result in protocol failures. p2p_set ssid_postfix Set postfix string to be added to the automatically generated P2P SSID (DIRECT-). For example, postfix of "-testing" could result in the SSID becoming DIRECT-ab-testing. p2p_set per_sta_psk <0/1> Disabled(default)/enables use of per-client PSK in the P2P groups. This can be used to request GO to assign a unique PSK for each client during WPS provisioning. When enabled, this allow clients to be removed from the group securily with p2p_remove_client command since that client's PSK is removed at the same time to prevent it from connecting back using the old PSK. When per-client PSK is not used, the client can still be disconnected, but it will be able to re-join the group since the PSK it learned previously is still valid. It should be noted that the default passphrase on the GO that is normally used to allow legacy stations to connect through manual configuration does not change here, so if that is shared, devices with knowledge of that passphrase can still connect. set Set global configuration parameters which may also affect P2P operations. The format on these parameters is same as is used in wpa_supplicant.conf. Only the parameters listen here should be changed. Modifying other parameters may result in incorrect behavior since not all existing users of the parameters are updated. set uuid Set WPS UUID (by default, this is generated based on the MAC address). set device_name Set WPS Device Name (also included in some P2P messages). set manufacturer Set WPS Manufacturer. set model_name Set WPS Model Name. set model_number Set WPS Model Number. set serial_number Set WPS Serial Number. set device_type Set WPS Device Type. set os_version Set WPS OS Version. set config_methods Set WPS Configuration Methods. set sec_device_type Add a new Secondary Device Type. set p2p_go_intent Set the default P2P GO Intent. Note: This value can be overridden in p2p_connect command and as such, there should be no need to change the default value here during normal operations. set p2p_ssid_postfix Set P2P SSID postfix. set persistent_reconnect <0/1> Disable/enabled persistent reconnect for reinvocation of persistent groups. If enabled, invitations to reinvoke a persistent group will be accepted without separate authorization (e.g., user interaction). set country Set country code (this is included in some P2P messages). Status p2p_peers [discovered] List P2P Device Addresses of all the P2P peers we know. The optional "discovered" parameter filters out the peers that we have not fully discovered, i.e., which we have only seen in a received Probe Request frame. p2p_peer Fetch information about a known P2P peer. Group Status (These are used on the group interface.) status Show status information (connection state, role, use encryption parameters, IP address, etc.). sta Show information about an associated station (when acting in AP/GO role). all_sta Lists the currently associated stations. Configuration data list_networks Lists the configured networks, including stored information for persistent groups. The identifier in this list is used with p2p_group_add and p2p_invite to indicate which persistent group is to be reinvoked. remove_network Remove a network entry from configuration. wpa_cli action script --------------------- See examples/p2p-action.sh TODO: describe DHCP/DNS setup TODO: cross-connection wpa_supplicant-2.2/wpa_supplicant/autoscan_exponential.c0000664000175000017500000000401112343617166021633 0ustar jmjm/* * WPA Supplicant - auto scan exponential module * Copyright (c) 2012, Intel Corporation. All rights reserved. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include "common.h" #include "wpa_supplicant_i.h" #include "autoscan.h" struct autoscan_exponential_data { struct wpa_supplicant *wpa_s; int base; int limit; int interval; }; static int autoscan_exponential_get_params(struct autoscan_exponential_data *data, const char *params) { const char *pos; if (params == NULL) return -1; data->base = atoi(params); pos = os_strchr(params, ':'); if (pos == NULL) return -1; pos++; data->limit = atoi(pos); return 0; } static void * autoscan_exponential_init(struct wpa_supplicant *wpa_s, const char *params) { struct autoscan_exponential_data *data; data = os_zalloc(sizeof(struct autoscan_exponential_data)); if (data == NULL) return NULL; if (autoscan_exponential_get_params(data, params) < 0) { os_free(data); return NULL; } wpa_printf(MSG_DEBUG, "autoscan exponential: base exponential is %d " "and limit is %d", data->base, data->limit); data->wpa_s = wpa_s; return data; } static void autoscan_exponential_deinit(void *priv) { struct autoscan_exponential_data *data = priv; os_free(data); } static int autoscan_exponential_notify_scan(void *priv, struct wpa_scan_results *scan_res) { struct autoscan_exponential_data *data = priv; wpa_printf(MSG_DEBUG, "autoscan exponential: scan result " "notification"); if (data->interval >= data->limit) return data->limit; if (data->interval <= 0) data->interval = data->base; else { data->interval = data->interval * data->base; if (data->interval > data->limit) return data->limit; } return data->interval; } const struct autoscan_ops autoscan_exponential_ops = { .name = "exponential", .init = autoscan_exponential_init, .deinit = autoscan_exponential_deinit, .notify_scan = autoscan_exponential_notify_scan, }; wpa_supplicant-2.2/wpa_supplicant/config.h0000664000175000017500000010565712343617166016704 0ustar jmjm/* * WPA Supplicant / Configuration file structures * Copyright (c) 2003-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef CONFIG_H #define CONFIG_H #define DEFAULT_EAPOL_VERSION 1 #ifdef CONFIG_NO_SCAN_PROCESSING #define DEFAULT_AP_SCAN 2 #else /* CONFIG_NO_SCAN_PROCESSING */ #define DEFAULT_AP_SCAN 1 #endif /* CONFIG_NO_SCAN_PROCESSING */ #define DEFAULT_FAST_REAUTH 1 #define DEFAULT_P2P_GO_INTENT 7 #define DEFAULT_P2P_INTRA_BSS 1 #define DEFAULT_P2P_GO_MAX_INACTIVITY (5 * 60) #define DEFAULT_BSS_MAX_COUNT 200 #define DEFAULT_BSS_EXPIRATION_AGE 180 #define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2 #define DEFAULT_MAX_NUM_STA 128 #define DEFAULT_ACCESS_NETWORK_TYPE 15 #define DEFAULT_SCAN_CUR_FREQ 0 #include "config_ssid.h" #include "wps/wps.h" #include "common/ieee802_11_common.h" struct wpa_cred { /** * next - Next credential in the list * * This pointer can be used to iterate over all credentials. The head * of this list is stored in the cred field of struct wpa_config. */ struct wpa_cred *next; /** * id - Unique id for the credential * * This identifier is used as a unique identifier for each credential * block when using the control interface. Each credential is allocated * an id when it is being created, either when reading the * configuration file or when a new credential is added through the * control interface. */ int id; /** * temporary - Whether this credential is temporary and not to be saved */ int temporary; /** * priority - Priority group * * By default, all networks and credentials get the same priority group * (0). This field can be used to give higher priority for credentials * (and similarly in struct wpa_ssid for network blocks) to change the * Interworking automatic networking selection behavior. The matching * network (based on either an enabled network block or a credential) * with the highest priority value will be selected. */ int priority; /** * pcsc - Use PC/SC and SIM/USIM card */ int pcsc; /** * realm - Home Realm for Interworking */ char *realm; /** * username - Username for Interworking network selection */ char *username; /** * password - Password for Interworking network selection */ char *password; /** * ext_password - Whether password is a name for external storage */ int ext_password; /** * ca_cert - CA certificate for Interworking network selection */ char *ca_cert; /** * client_cert - File path to client certificate file (PEM/DER) * * This field is used with Interworking networking selection for a case * where client certificate/private key is used for authentication * (EAP-TLS). Full path to the file should be used since working * directory may change when wpa_supplicant is run in the background. * * Alternatively, a named configuration blob can be used by setting * this to blob://blob_name. */ char *client_cert; /** * private_key - File path to client private key file (PEM/DER/PFX) * * When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be * commented out. Both the private key and certificate will be read * from the PKCS#12 file in this case. Full path to the file should be * used since working directory may change when wpa_supplicant is run * in the background. * * Windows certificate store can be used by leaving client_cert out and * configuring private_key in one of the following formats: * * cert://substring_to_match * * hash://certificate_thumbprint_in_hex * * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4" * * Note that when running wpa_supplicant as an application, the user * certificate store (My user account) is used, whereas computer store * (Computer account) is used when running wpasvc as a service. * * Alternatively, a named configuration blob can be used by setting * this to blob://blob_name. */ char *private_key; /** * private_key_passwd - Password for private key file */ char *private_key_passwd; /** * imsi - IMSI in | | '-' | format */ char *imsi; /** * milenage - Milenage parameters for SIM/USIM simulator in * :: format */ char *milenage; /** * domain_suffix_match - Constraint for server domain name * * If set, this FQDN is used as a suffix match requirement for the AAA * server certificate in SubjectAltName dNSName element(s). If a * matching dNSName is found, this constraint is met. If no dNSName * values are present, this constraint is matched against SubjetName CN * using same suffix match comparison. Suffix match here means that the * host/domain name is compared one label at a time starting from the * top-level domain and all the labels in @domain_suffix_match shall be * included in the certificate. The certificate may include additional * sub-level labels in addition to the required labels. * * For example, domain_suffix_match=example.com would match * test.example.com but would not match test-example.com. */ char *domain_suffix_match; /** * domain - Home service provider FQDN(s) * * This is used to compare against the Domain Name List to figure out * whether the AP is operated by the Home SP. Multiple domain entries * can be used to configure alternative FQDNs that will be considered * home networks. */ char **domain; /** * num_domain - Number of FQDNs in the domain array */ size_t num_domain; /** * roaming_consortium - Roaming Consortium OI * * If roaming_consortium_len is non-zero, this field contains the * Roaming Consortium OI that can be used to determine which access * points support authentication with this credential. This is an * alternative to the use of the realm parameter. When using Roaming * Consortium to match the network, the EAP parameters need to be * pre-configured with the credential since the NAI Realm information * may not be available or fetched. */ u8 roaming_consortium[15]; /** * roaming_consortium_len - Length of roaming_consortium */ size_t roaming_consortium_len; u8 required_roaming_consortium[15]; size_t required_roaming_consortium_len; /** * eap_method - EAP method to use * * Pre-configured EAP method to use with this credential or %NULL to * indicate no EAP method is selected, i.e., the method will be * selected automatically based on ANQP information. */ struct eap_method_type *eap_method; /** * phase1 - Phase 1 (outer authentication) parameters * * Pre-configured EAP parameters or %NULL. */ char *phase1; /** * phase2 - Phase 2 (inner authentication) parameters * * Pre-configured EAP parameters or %NULL. */ char *phase2; struct excluded_ssid { u8 ssid[MAX_SSID_LEN]; size_t ssid_len; } *excluded_ssid; size_t num_excluded_ssid; struct roaming_partner { char fqdn[128]; int exact_match; u8 priority; char country[3]; } *roaming_partner; size_t num_roaming_partner; int update_identifier; /** * provisioning_sp - FQDN of the SP that provisioned the credential */ char *provisioning_sp; /** * sp_priority - Credential priority within a provisioning SP * * This is the priority of the credential among all credentials * provisionined by the same SP (i.e., for entries that have identical * provisioning_sp value). The range of this priority is 0-255 with 0 * being the highest and 255 the lower priority. */ int sp_priority; unsigned int min_dl_bandwidth_home; unsigned int min_ul_bandwidth_home; unsigned int min_dl_bandwidth_roaming; unsigned int min_ul_bandwidth_roaming; /** * max_bss_load - Maximum BSS Load Channel Utilization (1..255) * This value is used as the maximum channel utilization for network * selection purposes for home networks. If the AP does not advertise * BSS Load or if the limit would prevent any connection, this * constraint will be ignored. */ unsigned int max_bss_load; unsigned int num_req_conn_capab; u8 *req_conn_capab_proto; int **req_conn_capab_port; /** * ocsp - Whether to use/require OCSP to check server certificate * * 0 = do not use OCSP stapling (TLS certificate status extension) * 1 = try to use OCSP stapling, but not require response * 2 = require valid OCSP stapling response */ int ocsp; /** * sim_num - User selected SIM identifier * * This variable is used for identifying which SIM is used if the system * has more than one. */ int sim_num; }; #define CFG_CHANGED_DEVICE_NAME BIT(0) #define CFG_CHANGED_CONFIG_METHODS BIT(1) #define CFG_CHANGED_DEVICE_TYPE BIT(2) #define CFG_CHANGED_OS_VERSION BIT(3) #define CFG_CHANGED_UUID BIT(4) #define CFG_CHANGED_COUNTRY BIT(5) #define CFG_CHANGED_SEC_DEVICE_TYPE BIT(6) #define CFG_CHANGED_P2P_SSID_POSTFIX BIT(7) #define CFG_CHANGED_WPS_STRING BIT(8) #define CFG_CHANGED_P2P_INTRA_BSS BIT(9) #define CFG_CHANGED_VENDOR_EXTENSION BIT(10) #define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11) #define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12) #define CFG_CHANGED_P2P_PREF_CHAN BIT(13) #define CFG_CHANGED_EXT_PW_BACKEND BIT(14) #define CFG_CHANGED_NFC_PASSWORD_TOKEN BIT(15) /** * struct wpa_config - wpa_supplicant configuration data * * This data structure is presents the per-interface (radio) configuration * data. In many cases, there is only one struct wpa_config instance, but if * more than one network interface is being controlled, one instance is used * for each. */ struct wpa_config { /** * ssid - Head of the global network list * * This is the head for the list of all the configured networks. */ struct wpa_ssid *ssid; /** * pssid - Per-priority network lists (in priority order) */ struct wpa_ssid **pssid; /** * num_prio - Number of different priorities used in the pssid lists * * This indicates how many per-priority network lists are included in * pssid. */ int num_prio; /** * cred - Head of the credential list * * This is the head for the list of all the configured credentials. */ struct wpa_cred *cred; /** * eapol_version - IEEE 802.1X/EAPOL version number * * wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which * defines EAPOL version 2. However, there are many APs that do not * handle the new version number correctly (they seem to drop the * frames completely). In order to make wpa_supplicant interoperate * with these APs, the version number is set to 1 by default. This * configuration value can be used to set it to the new version (2). */ int eapol_version; /** * ap_scan - AP scanning/selection * * By default, wpa_supplicant requests driver to perform AP * scanning and then uses the scan results to select a * suitable AP. Another alternative is to allow the driver to * take care of AP scanning and selection and use * wpa_supplicant just to process EAPOL frames based on IEEE * 802.11 association information from the driver. * * 1: wpa_supplicant initiates scanning and AP selection (default). * * 0: Driver takes care of scanning, AP selection, and IEEE 802.11 * association parameters (e.g., WPA IE generation); this mode can * also be used with non-WPA drivers when using IEEE 802.1X mode; * do not try to associate with APs (i.e., external program needs * to control association). This mode must also be used when using * wired Ethernet drivers. * * 2: like 0, but associate with APs using security policy and SSID * (but not BSSID); this can be used, e.g., with ndiswrapper and NDIS * drivers to enable operation with hidden SSIDs and optimized roaming; * in this mode, the network blocks in the configuration are tried * one by one until the driver reports successful association; each * network block should have explicit security policy (i.e., only one * option in the lists) for key_mgmt, pairwise, group, proto variables. */ int ap_scan; /** * bgscan - Background scan and roaming parameters or %NULL if none * * This is an optional set of parameters for background scanning and * roaming within a network (ESS). For more detailed information see * ssid block documentation. * * The variable defines default bgscan behavior for all BSS station * networks except for those which have their own bgscan configuration. */ char *bgscan; /** * disable_scan_offload - Disable automatic offloading of scan requests * * By default, %wpa_supplicant tries to offload scanning if the driver * indicates support for this (sched_scan). This configuration * parameter can be used to disable this offloading mechanism. */ int disable_scan_offload; /** * ctrl_interface - Parameters for the control interface * * If this is specified, %wpa_supplicant will open a control interface * that is available for external programs to manage %wpa_supplicant. * The meaning of this string depends on which control interface * mechanism is used. For all cases, the existence of this parameter * in configuration is used to determine whether the control interface * is enabled. * * For UNIX domain sockets (default on Linux and BSD): This is a * directory that will be created for UNIX domain sockets for listening * to requests from external programs (CLI/GUI, etc.) for status * information and configuration. The socket file will be named based * on the interface name, so multiple %wpa_supplicant processes can be * run at the same time if more than one interface is used. * /var/run/wpa_supplicant is the recommended directory for sockets and * by default, wpa_cli will use it when trying to connect with * %wpa_supplicant. * * Access control for the control interface can be configured * by setting the directory to allow only members of a group * to use sockets. This way, it is possible to run * %wpa_supplicant as root (since it needs to change network * configuration and open raw sockets) and still allow GUI/CLI * components to be run as non-root users. However, since the * control interface can be used to change the network * configuration, this access needs to be protected in many * cases. By default, %wpa_supplicant is configured to use gid * 0 (root). If you want to allow non-root users to use the * control interface, add a new group and change this value to * match with that group. Add users that should have control * interface access to this group. * * When configuring both the directory and group, use following format: * DIR=/var/run/wpa_supplicant GROUP=wheel * DIR=/var/run/wpa_supplicant GROUP=0 * (group can be either group name or gid) * * For UDP connections (default on Windows): The value will be ignored. * This variable is just used to select that the control interface is * to be created. The value can be set to, e.g., udp * (ctrl_interface=udp). * * For Windows Named Pipe: This value can be used to set the security * descriptor for controlling access to the control interface. Security * descriptor can be set using Security Descriptor String Format (see * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/security_descriptor_string_format.asp). * The descriptor string needs to be prefixed with SDDL=. For example, * ctrl_interface=SDDL=D: would set an empty DACL (which will reject * all connections). */ char *ctrl_interface; /** * ctrl_interface_group - Control interface group (DEPRECATED) * * This variable is only used for backwards compatibility. Group for * UNIX domain sockets should now be specified using GROUP=group in * ctrl_interface variable. */ char *ctrl_interface_group; /** * fast_reauth - EAP fast re-authentication (session resumption) * * By default, fast re-authentication is enabled for all EAP methods * that support it. This variable can be used to disable fast * re-authentication (by setting fast_reauth=0). Normally, there is no * need to disable fast re-authentication. */ int fast_reauth; /** * opensc_engine_path - Path to the OpenSSL engine for opensc * * This is an OpenSSL specific configuration option for loading OpenSC * engine (engine_opensc.so); if %NULL, this engine is not loaded. */ char *opensc_engine_path; /** * pkcs11_engine_path - Path to the OpenSSL engine for PKCS#11 * * This is an OpenSSL specific configuration option for loading PKCS#11 * engine (engine_pkcs11.so); if %NULL, this engine is not loaded. */ char *pkcs11_engine_path; /** * pkcs11_module_path - Path to the OpenSSL OpenSC/PKCS#11 module * * This is an OpenSSL specific configuration option for configuring * path to OpenSC/PKCS#11 engine (opensc-pkcs11.so); if %NULL, this * module is not loaded. */ char *pkcs11_module_path; /** * pcsc_reader - PC/SC reader name prefix * * If not %NULL, PC/SC reader with a name that matches this prefix is * initialized for SIM/USIM access. Empty string can be used to match * the first available reader. */ char *pcsc_reader; /** * pcsc_pin - PIN for USIM, GSM SIM, and smartcards * * This field is used to configure PIN for SIM/USIM for EAP-SIM and * EAP-AKA. If left out, this will be asked through control interface. */ char *pcsc_pin; /** * external_sim - Use external processing for SIM/USIM operations */ int external_sim; /** * driver_param - Driver interface parameters * * This text string is passed to the selected driver interface with the * optional struct wpa_driver_ops::set_param() handler. This can be * used to configure driver specific options without having to add new * driver interface functionality. */ char *driver_param; /** * dot11RSNAConfigPMKLifetime - Maximum lifetime of a PMK * * dot11 MIB variable for the maximum lifetime of a PMK in the PMK * cache (unit: seconds). */ unsigned int dot11RSNAConfigPMKLifetime; /** * dot11RSNAConfigPMKReauthThreshold - PMK re-authentication threshold * * dot11 MIB variable for the percentage of the PMK lifetime * that should expire before an IEEE 802.1X reauthentication occurs. */ unsigned int dot11RSNAConfigPMKReauthThreshold; /** * dot11RSNAConfigSATimeout - Security association timeout * * dot11 MIB variable for the maximum time a security association * shall take to set up (unit: seconds). */ unsigned int dot11RSNAConfigSATimeout; /** * update_config - Is wpa_supplicant allowed to update configuration * * This variable control whether wpa_supplicant is allow to re-write * its configuration with wpa_config_write(). If this is zero, * configuration data is only changed in memory and the external data * is not overriden. If this is non-zero, wpa_supplicant will update * the configuration data (e.g., a file) whenever configuration is * changed. This update may replace the old configuration which can * remove comments from it in case of a text file configuration. */ int update_config; /** * blobs - Configuration blobs */ struct wpa_config_blob *blobs; /** * uuid - Universally Unique IDentifier (UUID; see RFC 4122) for WPS */ u8 uuid[16]; /** * device_name - Device Name (WPS) * User-friendly description of device; up to 32 octets encoded in * UTF-8 */ char *device_name; /** * manufacturer - Manufacturer (WPS) * The manufacturer of the device (up to 64 ASCII characters) */ char *manufacturer; /** * model_name - Model Name (WPS) * Model of the device (up to 32 ASCII characters) */ char *model_name; /** * model_number - Model Number (WPS) * Additional device description (up to 32 ASCII characters) */ char *model_number; /** * serial_number - Serial Number (WPS) * Serial number of the device (up to 32 characters) */ char *serial_number; /** * device_type - Primary Device Type (WPS) */ u8 device_type[WPS_DEV_TYPE_LEN]; /** * config_methods - Config Methods * * This is a space-separated list of supported WPS configuration * methods. For example, "label virtual_display virtual_push_button * keypad". * Available methods: usba ethernet label display ext_nfc_token * int_nfc_token nfc_interface push_button keypad * virtual_display physical_display * virtual_push_button physical_push_button. */ char *config_methods; /** * os_version - OS Version (WPS) * 4-octet operating system version number */ u8 os_version[4]; /** * country - Country code * * This is the ISO/IEC alpha2 country code for which we are operating * in */ char country[2]; /** * wps_cred_processing - Credential processing * * 0 = process received credentials internally * 1 = do not process received credentials; just pass them over * ctrl_iface to external program(s) * 2 = process received credentials internally and pass them over * ctrl_iface to external program(s) */ int wps_cred_processing; #define MAX_SEC_DEVICE_TYPES 5 /** * sec_device_types - Secondary Device Types (P2P) */ u8 sec_device_type[MAX_SEC_DEVICE_TYPES][WPS_DEV_TYPE_LEN]; int num_sec_device_types; int p2p_listen_reg_class; int p2p_listen_channel; int p2p_oper_reg_class; int p2p_oper_channel; int p2p_go_intent; char *p2p_ssid_postfix; int persistent_reconnect; int p2p_intra_bss; unsigned int num_p2p_pref_chan; struct p2p_channel *p2p_pref_chan; struct wpa_freq_range_list p2p_no_go_freq; int p2p_add_cli_chan; int p2p_ignore_shared_freq; struct wpabuf *wps_vendor_ext_m1; #define MAX_WPS_VENDOR_EXT 10 /** * wps_vendor_ext - Vendor extension attributes in WPS */ struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXT]; /** * p2p_group_idle - Maximum idle time in seconds for P2P group * * This value controls how long a P2P group is maintained after there * is no other members in the group. As a GO, this means no associated * stations in the group. As a P2P client, this means no GO seen in * scan results. The maximum idle time is specified in seconds with 0 * indicating no time limit, i.e., the P2P group remains in active * state indefinitely until explicitly removed. As a P2P client, the * maximum idle time of P2P_MAX_CLIENT_IDLE seconds is enforced, i.e., * this parameter is mainly meant for GO use and for P2P client, it can * only be used to reduce the default timeout to smaller value. A * special value -1 can be used to configure immediate removal of the * group for P2P client role on any disconnection after the data * connection has been established. */ int p2p_group_idle; /** * bss_max_count - Maximum number of BSS entries to keep in memory */ unsigned int bss_max_count; /** * bss_expiration_age - BSS entry age after which it can be expired * * This value controls the time in seconds after which a BSS entry * gets removed if it has not been updated or is not in use. */ unsigned int bss_expiration_age; /** * bss_expiration_scan_count - Expire BSS after number of scans * * If the BSS entry has not been seen in this many scans, it will be * removed. A value of 1 means that entry is removed after the first * scan in which the BSSID is not seen. Larger values can be used * to avoid BSS entries disappearing if they are not visible in * every scan (e.g., low signal quality or interference). */ unsigned int bss_expiration_scan_count; /** * filter_ssids - SSID-based scan result filtering * * 0 = do not filter scan results * 1 = only include configured SSIDs in scan results/BSS table */ int filter_ssids; /** * filter_rssi - RSSI-based scan result filtering * * 0 = do not filter scan results * -n = filter scan results below -n dBm */ int filter_rssi; /** * max_num_sta - Maximum number of STAs in an AP/P2P GO */ unsigned int max_num_sta; /** * freq_list - Array of allowed scan frequencies or %NULL for all * * This is an optional zero-terminated array of frequencies in * megahertz (MHz) to allow for narrowing scanning range. */ int *freq_list; /** * scan_cur_freq - Whether to scan only the current channel * * If true, attempt to scan only the current channel if any other * VIFs on this radio are already associated on a particular channel. */ int scan_cur_freq; /** * changed_parameters - Bitmap of changed parameters since last update */ unsigned int changed_parameters; /** * disassoc_low_ack - Disassocicate stations with massive packet loss */ int disassoc_low_ack; /** * interworking - Whether Interworking (IEEE 802.11u) is enabled */ int interworking; /** * access_network_type - Access Network Type * * When Interworking is enabled, scans will be limited to APs that * advertise the specified Access Network Type (0..15; with 15 * indicating wildcard match). */ int access_network_type; /** * hessid - Homogenous ESS identifier * * If this is set (any octet is non-zero), scans will be used to * request response only from BSSes belonging to the specified * Homogeneous ESS. This is used only if interworking is enabled. */ u8 hessid[ETH_ALEN]; /** * hs20 - Hotspot 2.0 */ int hs20; /** * pbc_in_m1 - AP mode WPS probing workaround for PBC with Windows 7 * * Windows 7 uses incorrect way of figuring out AP's WPS capabilities * by acting as a Registrar and using M1 from the AP. The config * methods attribute in that message is supposed to indicate only the * configuration method supported by the AP in Enrollee role, i.e., to * add an external Registrar. For that case, PBC shall not be used and * as such, the PushButton config method is removed from M1 by default. * If pbc_in_m1=1 is included in the configuration file, the PushButton * config method is left in M1 (if included in config_methods * parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from * a label in the AP). */ int pbc_in_m1; /** * autoscan - Automatic scan parameters or %NULL if none * * This is an optional set of parameters for automatic scanning * within an interface in following format: * : */ char *autoscan; /** * wps_nfc_pw_from_config - NFC Device Password was read from config * * This parameter can be determined whether the NFC Device Password was * included in the configuration (1) or generated dynamically (0). Only * the former case is re-written back to the configuration file. */ int wps_nfc_pw_from_config; /** * wps_nfc_dev_pw_id - NFC Device Password ID for password token */ int wps_nfc_dev_pw_id; /** * wps_nfc_dh_pubkey - NFC DH Public Key for password token */ struct wpabuf *wps_nfc_dh_pubkey; /** * wps_nfc_dh_privkey - NFC DH Private Key for password token */ struct wpabuf *wps_nfc_dh_privkey; /** * wps_nfc_dev_pw - NFC Device Password for password token */ struct wpabuf *wps_nfc_dev_pw; /** * ext_password_backend - External password backend or %NULL if none * * format: [:] */ char *ext_password_backend; /* * p2p_go_max_inactivity - Timeout in seconds to detect STA inactivity * * This timeout value is used in P2P GO mode to clean up * inactive stations. * By default: 300 seconds. */ int p2p_go_max_inactivity; struct hostapd_wmm_ac_params wmm_ac_params[4]; /** * auto_interworking - Whether to use network selection automatically * * 0 = do not automatically go through Interworking network selection * (i.e., require explicit interworking_select command for this) * 1 = perform Interworking network selection if one or more * credentials have been configured and scan did not find a * matching network block */ int auto_interworking; /** * p2p_go_ht40 - Default mode for HT40 enable when operating as GO. * * This will take effect for p2p_group_add, p2p_connect, and p2p_invite. * Note that regulatory constraints and driver capabilities are * consulted anyway, so setting it to 1 can't do real harm. * By default: 0 (disabled) */ int p2p_go_ht40; /** * p2p_go_vht - Default mode for VHT enable when operating as GO * * This will take effect for p2p_group_add, p2p_connect, and p2p_invite. * Note that regulatory constraints and driver capabilities are * consulted anyway, so setting it to 1 can't do real harm. * By default: 0 (disabled) */ int p2p_go_vht; /** * p2p_disabled - Whether P2P operations are disabled for this interface */ int p2p_disabled; /** * p2p_no_group_iface - Whether group interfaces can be used * * By default, wpa_supplicant will create a separate interface for P2P * group operations if the driver supports this. This functionality can * be disabled by setting this parameter to 1. In that case, the same * interface that was used for the P2P management operations is used * also for the group operation. */ int p2p_no_group_iface; /** * okc - Whether to enable opportunistic key caching by default * * By default, OKC is disabled unless enabled by the per-network * proactive_key_caching=1 parameter. okc=1 can be used to change this * default behavior. */ int okc; /** * pmf - Whether to enable/require PMF by default * * By default, PMF is disabled unless enabled by the per-network * ieee80211w=1 or ieee80211w=2 parameter. pmf=1/2 can be used to change * this default behavior. */ enum mfp_options pmf; /** * sae_groups - Preference list of enabled groups for SAE * * By default (if this parameter is not set), the mandatory group 19 * (ECC group defined over a 256-bit prime order field) is preferred, * but other groups are also enabled. If this parameter is set, the * groups will be tried in the indicated order. */ int *sae_groups; /** * dtim_period - Default DTIM period in Beacon intervals * * This parameter can be used to set the default value for network * blocks that do not specify dtim_period. */ int dtim_period; /** * beacon_int - Default Beacon interval in TU * * This parameter can be used to set the default value for network * blocks that do not specify beacon_int. */ int beacon_int; /** * ap_vendor_elements: Vendor specific elements for Beacon/ProbeResp * * This parameter can be used to define additional vendor specific * elements for Beacon and Probe Response frames in AP/P2P GO mode. The * format for these element(s) is a hexdump of the raw information * elements (id+len+payload for one or more elements). */ struct wpabuf *ap_vendor_elements; /** * ignore_old_scan_res - Ignore scan results older than request * * The driver may have a cache of scan results that makes it return * information that is older than our scan trigger. This parameter can * be used to configure such old information to be ignored instead of * allowing it to update the internal BSS table. */ int ignore_old_scan_res; /** * sched_scan_interval - schedule scan interval */ unsigned int sched_scan_interval; /** * tdls_external_control - External control for TDLS setup requests * * Enable TDLS mode where external programs are given the control * to specify the TDLS link to get established to the driver. The * driver requests the TDLS setup to the supplicant only for the * specified TDLS peers. */ int tdls_external_control; u8 ip_addr_go[4]; u8 ip_addr_mask[4]; u8 ip_addr_start[4]; u8 ip_addr_end[4]; /** * osu_dir - OSU provider information directory * * If set, allow FETCH_OSU control interface command to be used to fetch * OSU provider information into all APs and store the results in this * directory. */ char *osu_dir; /** * wowlan_triggers - Wake-on-WLAN triggers * * If set, these wowlan triggers will be configured. */ char *wowlan_triggers; }; /* Prototypes for common functions from config.c */ void wpa_config_free(struct wpa_config *ssid); void wpa_config_free_ssid(struct wpa_ssid *ssid); void wpa_config_foreach_network(struct wpa_config *config, void (*func)(void *, struct wpa_ssid *), void *arg); struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id); struct wpa_ssid * wpa_config_add_network(struct wpa_config *config); int wpa_config_remove_network(struct wpa_config *config, int id); void wpa_config_set_network_defaults(struct wpa_ssid *ssid); int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, int line); int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var, const char *value); char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys); char * wpa_config_get(struct wpa_ssid *ssid, const char *var); char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var); void wpa_config_update_psk(struct wpa_ssid *ssid); int wpa_config_add_prio_network(struct wpa_config *config, struct wpa_ssid *ssid); int wpa_config_update_prio_list(struct wpa_config *config); const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config, const char *name); void wpa_config_set_blob(struct wpa_config *config, struct wpa_config_blob *blob); void wpa_config_free_blob(struct wpa_config_blob *blob); int wpa_config_remove_blob(struct wpa_config *config, const char *name); void wpa_config_flush_blobs(struct wpa_config *config); struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id); struct wpa_cred * wpa_config_add_cred(struct wpa_config *config); int wpa_config_remove_cred(struct wpa_config *config, int id); void wpa_config_free_cred(struct wpa_cred *cred); int wpa_config_set_cred(struct wpa_cred *cred, const char *var, const char *value, int line); char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var); struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, const char *driver_param); #ifndef CONFIG_NO_STDOUT_DEBUG void wpa_config_debug_dump_networks(struct wpa_config *config); #else /* CONFIG_NO_STDOUT_DEBUG */ #define wpa_config_debug_dump_networks(c) do { } while (0) #endif /* CONFIG_NO_STDOUT_DEBUG */ /* Prototypes for common functions from config.c */ int wpa_config_process_global(struct wpa_config *config, char *pos, int line); /* Prototypes for backend specific functions from the selected config_*.c */ /** * wpa_config_read - Read and parse configuration database * @name: Name of the configuration (e.g., path and file name for the * configuration file) * @cfgp: Pointer to previously allocated configuration data or %NULL if none * Returns: Pointer to allocated configuration data or %NULL on failure * * This function reads configuration data, parses its contents, and allocates * data structures needed for storing configuration information. The allocated * data can be freed with wpa_config_free(). * * Each configuration backend needs to implement this function. */ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp); /** * wpa_config_write - Write or update configuration data * @name: Name of the configuration (e.g., path and file name for the * configuration file) * @config: Configuration data from wpa_config_read() * Returns: 0 on success, -1 on failure * * This function write all configuration data into an external database (e.g., * a text file) in a format that can be read with wpa_config_read(). This can * be used to allow wpa_supplicant to update its configuration, e.g., when a * new network is added or a password is changed. * * Each configuration backend needs to implement this function. */ int wpa_config_write(const char *name, struct wpa_config *config); #endif /* CONFIG_H */ wpa_supplicant-2.2/wpa_supplicant/p2p_supplicant.h0000664000175000017500000002027312343617166020370 0ustar jmjm/* * wpa_supplicant - P2P * Copyright (c) 2009-2010, Atheros Communications * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef P2P_SUPPLICANT_H #define P2P_SUPPLICANT_H enum p2p_wps_method; struct p2p_go_neg_results; enum p2p_send_action_result; struct p2p_peer_info; struct p2p_channels; struct wps_event_fail; int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s); void wpas_p2p_deinit(struct wpa_supplicant *wpa_s); void wpas_p2p_deinit_global(struct wpa_global *global); int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s); int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, const char *pin, enum p2p_wps_method wps_method, int persistent_group, int auto_join, int join, int auth, int go_intent, int freq, int persistent_id, int pd, int ht40, int vht); void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq, unsigned int duration); void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq); int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq, struct wpa_ssid *ssid); int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname); int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, int freq, int ht40, int vht); int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int addr_allocated, int force_freq, int neg_freq, int ht40, int vht, const struct p2p_channels *channels, int connection_timeout); struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int registrar); enum wpas_p2p_prov_disc_use { WPAS_P2P_PD_FOR_GO_NEG, WPAS_P2P_PD_FOR_JOIN, WPAS_P2P_PD_AUTO }; int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, const char *config_method, enum wpas_p2p_prov_disc_use use); void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data, size_t data_len, enum p2p_send_action_result result); int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end); enum p2p_discovery_type; int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, enum p2p_discovery_type type, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id, unsigned int search_delay); void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s); int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout); int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, u8 *buf, size_t len, int p2p_group); int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *dst, const u8 *bssid, const u8 *ie, size_t ie_len, int ssi_signal); void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da, const u8 *sa, const u8 *bssid, u8 category, const u8 *data, size_t len, int freq); void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies); void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s); void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s); u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *tlvs); u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst, u8 version, const char *query); u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s, const u8 *dst, const char *role); int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req); void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq, const u8 *dst, u8 dialog_token, const struct wpabuf *resp_tlvs); void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s); void wpas_p2p_service_flush(struct wpa_supplicant *wpa_s); int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s, struct wpabuf *query, struct wpabuf *resp); int wpas_p2p_service_del_bonjour(struct wpa_supplicant *wpa_s, const struct wpabuf *query); int wpas_p2p_service_add_upnp(struct wpa_supplicant *wpa_s, u8 version, const char *service); int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version, const char *service); int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr); int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq, int ht40, int vht, int pref_freq); int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, const u8 *peer_addr, const u8 *go_dev_addr); void wpas_p2p_completed(struct wpa_supplicant *wpa_s); int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1, u32 interval1, u32 duration2, u32 interval2); int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period, unsigned int interval); int wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, u16 reason_code, const u8 *ie, size_t ie_len, int locally_generated); void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, u16 reason_code, const u8 *ie, size_t ie_len, int locally_generated); void wpas_p2p_update_config(struct wpa_supplicant *wpa_s); int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start, int duration); int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled); void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s); void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s); int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s); void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s); int wpas_p2p_cancel(struct wpa_supplicant *wpa_s); void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s); void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s, int freq_24, int freq_5, int freq_overall); int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr); int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s); void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail); int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s); int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s); void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *ssid, size_t ssid_len); void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *addr); int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s); int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel); int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel); unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s); void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr, const u8 *p2p_dev_addr, const u8 *psk, size_t psk_len); void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer, int iface_addr); struct wpabuf * wpas_p2p_nfc_handover_req(struct wpa_supplicant *wpa_s, int ndef); struct wpabuf * wpas_p2p_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef, int tag); int wpas_p2p_nfc_tag_process(struct wpa_supplicant *wpa_s, const struct wpabuf *data, int forced_freq); int wpas_p2p_nfc_report_handover(struct wpa_supplicant *wpa_s, int init, const struct wpabuf *req, const struct wpabuf *sel, int forced_freq); int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled); void wpas_p2p_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx); #ifdef CONFIG_P2P int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s); void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s); #else /* CONFIG_P2P */ static inline int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s) { return 0; } static inline void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s) { } #endif /* CONFIG_P2P */ #endif /* P2P_SUPPLICANT_H */ wpa_supplicant-2.2/wpa_supplicant/wpa_cli.c0000664000175000017500000027415712343617166017052 0ustar jmjm/* * WPA Supplicant - command line interface for wpa_supplicant daemon * Copyright (c) 2004-2013, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #ifdef CONFIG_CTRL_IFACE #ifdef CONFIG_CTRL_IFACE_UNIX #include #endif /* CONFIG_CTRL_IFACE_UNIX */ #include "common/wpa_ctrl.h" #include "utils/common.h" #include "utils/eloop.h" #include "utils/edit.h" #include "utils/list.h" #include "common/version.h" #include "common/ieee802_11_defs.h" #ifdef ANDROID #include #endif /* ANDROID */ static const char *wpa_cli_version = "wpa_cli v" VERSION_STR "\n" "Copyright (c) 2004-2014, Jouni Malinen and contributors"; static const char *wpa_cli_license = "This software may be distributed under the terms of the BSD license.\n" "See README for more details.\n"; static const char *wpa_cli_full_license = "This software may be distributed under the terms of the BSD license.\n" "\n" "Redistribution and use in source and binary forms, with or without\n" "modification, are permitted provided that the following conditions are\n" "met:\n" "\n" "1. Redistributions of source code must retain the above copyright\n" " notice, this list of conditions and the following disclaimer.\n" "\n" "2. Redistributions in binary form must reproduce the above copyright\n" " notice, this list of conditions and the following disclaimer in the\n" " documentation and/or other materials provided with the distribution.\n" "\n" "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n" " names of its contributors may be used to endorse or promote products\n" " derived from this software without specific prior written permission.\n" "\n" "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" "\n"; static struct wpa_ctrl *ctrl_conn; static struct wpa_ctrl *mon_conn; static int wpa_cli_quit = 0; static int wpa_cli_attached = 0; static int wpa_cli_connected = -1; static int wpa_cli_last_id = 0; #ifndef CONFIG_CTRL_IFACE_DIR #define CONFIG_CTRL_IFACE_DIR "/var/run/wpa_supplicant" #endif /* CONFIG_CTRL_IFACE_DIR */ static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR; static char *ctrl_ifname = NULL; static const char *pid_file = NULL; static const char *action_file = NULL; static int ping_interval = 5; static int interactive = 0; static char *ifname_prefix = NULL; struct cli_txt_entry { struct dl_list list; char *txt; }; static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */ static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */ static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */ static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */ static void print_help(const char *cmd); static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx); static void wpa_cli_close_connection(void); static char * wpa_cli_get_default_ifname(void); static char ** wpa_list_cmd_list(void); static void usage(void) { printf("wpa_cli [-p] [-i] [-hvB] " "[-a] \\\n" " [-P] [-g] [-G] " "[command..]\n" " -h = help (show this usage text)\n" " -v = shown version information\n" " -a = run in daemon mode executing the action file based on " "events from\n" " wpa_supplicant\n" " -B = run a daemon in the background\n" " default path: " CONFIG_CTRL_IFACE_DIR "\n" " default interface: first interface found in socket path\n"); print_help(NULL); } static void cli_txt_list_free(struct cli_txt_entry *e) { dl_list_del(&e->list); os_free(e->txt); os_free(e); } static void cli_txt_list_flush(struct dl_list *list) { struct cli_txt_entry *e; while ((e = dl_list_first(list, struct cli_txt_entry, list))) cli_txt_list_free(e); } static struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list, const char *txt) { struct cli_txt_entry *e; dl_list_for_each(e, txt_list, struct cli_txt_entry, list) { if (os_strcmp(e->txt, txt) == 0) return e; } return NULL; } static void cli_txt_list_del(struct dl_list *txt_list, const char *txt) { struct cli_txt_entry *e; e = cli_txt_list_get(txt_list, txt); if (e) cli_txt_list_free(e); } static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt) { u8 addr[ETH_ALEN]; char buf[18]; if (hwaddr_aton(txt, addr) < 0) return; os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); cli_txt_list_del(txt_list, buf); } #ifdef CONFIG_P2P static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt) { const char *end; char *buf; end = os_strchr(txt, ' '); if (end == NULL) end = txt + os_strlen(txt); buf = dup_binstr(txt, end - txt); if (buf == NULL) return; cli_txt_list_del(txt_list, buf); os_free(buf); } #endif /* CONFIG_P2P */ static int cli_txt_list_add(struct dl_list *txt_list, const char *txt) { struct cli_txt_entry *e; e = cli_txt_list_get(txt_list, txt); if (e) return 0; e = os_zalloc(sizeof(*e)); if (e == NULL) return -1; e->txt = os_strdup(txt); if (e->txt == NULL) { os_free(e); return -1; } dl_list_add(txt_list, &e->list); return 0; } #ifdef CONFIG_P2P static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt) { u8 addr[ETH_ALEN]; char buf[18]; if (hwaddr_aton(txt, addr) < 0) return -1; os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); return cli_txt_list_add(txt_list, buf); } static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt) { const char *end; char *buf; int ret; end = os_strchr(txt, ' '); if (end == NULL) end = txt + os_strlen(txt); buf = dup_binstr(txt, end - txt); if (buf == NULL) return -1; ret = cli_txt_list_add(txt_list, buf); os_free(buf); return ret; } #endif /* CONFIG_P2P */ static char ** cli_txt_list_array(struct dl_list *txt_list) { unsigned int i, count = dl_list_len(txt_list); char **res; struct cli_txt_entry *e; res = os_calloc(count + 1, sizeof(char *)); if (res == NULL) return NULL; i = 0; dl_list_for_each(e, txt_list, struct cli_txt_entry, list) { res[i] = os_strdup(e->txt); if (res[i] == NULL) break; i++; } return res; } static int get_cmd_arg_num(const char *str, int pos) { int arg = 0, i; for (i = 0; i <= pos; i++) { if (str[i] != ' ') { arg++; while (i <= pos && str[i] != ' ') i++; } } if (arg > 0) arg--; return arg; } static int str_starts(const char *src, const char *match) { return os_strncmp(src, match, os_strlen(match)) == 0; } static int wpa_cli_show_event(const char *event) { const char *start; start = os_strchr(event, '>'); if (start == NULL) return 1; start++; /* * Skip BSS added/removed events since they can be relatively frequent * and are likely of not much use for an interactive user. */ if (str_starts(start, WPA_EVENT_BSS_ADDED) || str_starts(start, WPA_EVENT_BSS_REMOVED)) return 0; return 1; } static int wpa_cli_open_connection(const char *ifname, int attach) { #if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE) ctrl_conn = wpa_ctrl_open(ifname); if (ctrl_conn == NULL) return -1; if (attach && interactive) mon_conn = wpa_ctrl_open(ifname); else mon_conn = NULL; #else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */ char *cfile = NULL; int flen, res; if (ifname == NULL) return -1; #ifdef ANDROID if (access(ctrl_iface_dir, F_OK) < 0) { cfile = os_strdup(ifname); if (cfile == NULL) return -1; } #endif /* ANDROID */ if (cfile == NULL) { flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2; cfile = os_malloc(flen); if (cfile == NULL) return -1; res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname); if (res < 0 || res >= flen) { os_free(cfile); return -1; } } ctrl_conn = wpa_ctrl_open(cfile); if (ctrl_conn == NULL) { os_free(cfile); return -1; } if (attach && interactive) mon_conn = wpa_ctrl_open(cfile); else mon_conn = NULL; os_free(cfile); #endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */ if (mon_conn) { if (wpa_ctrl_attach(mon_conn) == 0) { wpa_cli_attached = 1; if (interactive) eloop_register_read_sock( wpa_ctrl_get_fd(mon_conn), wpa_cli_mon_receive, NULL, NULL); } else { printf("Warning: Failed to attach to " "wpa_supplicant.\n"); wpa_cli_close_connection(); return -1; } } return 0; } static void wpa_cli_close_connection(void) { if (ctrl_conn == NULL) return; if (wpa_cli_attached) { wpa_ctrl_detach(interactive ? mon_conn : ctrl_conn); wpa_cli_attached = 0; } wpa_ctrl_close(ctrl_conn); ctrl_conn = NULL; if (mon_conn) { eloop_unregister_read_sock(wpa_ctrl_get_fd(mon_conn)); wpa_ctrl_close(mon_conn); mon_conn = NULL; } } static void wpa_cli_msg_cb(char *msg, size_t len) { printf("%s\n", msg); } static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print) { char buf[4096]; size_t len; int ret; if (ctrl_conn == NULL) { printf("Not connected to wpa_supplicant - command dropped.\n"); return -1; } if (ifname_prefix) { os_snprintf(buf, sizeof(buf), "IFNAME=%s %s", ifname_prefix, cmd); buf[sizeof(buf) - 1] = '\0'; cmd = buf; } len = sizeof(buf) - 1; ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, wpa_cli_msg_cb); if (ret == -2) { printf("'%s' command timed out.\n", cmd); return -2; } else if (ret < 0) { printf("'%s' command failed.\n", cmd); return -1; } if (print) { buf[len] = '\0'; printf("%s", buf); if (interactive && len > 0 && buf[len - 1] != '\n') printf("\n"); } return 0; } static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd) { return _wpa_ctrl_command(ctrl, cmd, 1); } static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc, char *argv[]) { int i, res; char *pos, *end; pos = buf; end = buf + buflen; res = os_snprintf(pos, end - pos, "%s", cmd); if (res < 0 || res >= end - pos) goto fail; pos += res; for (i = 0; i < argc; i++) { res = os_snprintf(pos, end - pos, " %s", argv[i]); if (res < 0 || res >= end - pos) goto fail; pos += res; } buf[buflen - 1] = '\0'; return 0; fail: printf("Too long command\n"); return -1; } static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args, int argc, char *argv[]) { char buf[4096]; if (argc < min_args) { printf("Invalid %s command - at least %d argument%s " "required.\n", cmd, min_args, min_args > 1 ? "s are" : " is"); return -1; } if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0) return -1; return wpa_ctrl_command(ctrl, buf); } static int wpa_cli_cmd_ifname(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "IFNAME"); } static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc > 0 && os_strcmp(argv[0], "verbose") == 0) return wpa_ctrl_command(ctrl, "STATUS-VERBOSE"); if (argc > 0 && os_strcmp(argv[0], "wps") == 0) return wpa_ctrl_command(ctrl, "STATUS-WPS"); if (argc > 0 && os_strcmp(argv[0], "driver") == 0) return wpa_ctrl_command(ctrl, "STATUS-DRIVER"); return wpa_ctrl_command(ctrl, "STATUS"); } static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "PING"); } static int wpa_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "RELOG"); } static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "NOTE", 1, argc, argv); } static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "MIB"); } static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "PMKSA"); } static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) { print_help(argc > 0 ? argv[0] : NULL); return 0; } static char ** wpa_cli_complete_help(const char *str, int pos) { int arg = get_cmd_arg_num(str, pos); char **res = NULL; switch (arg) { case 1: res = wpa_list_cmd_list(); break; } return res; } static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[]) { printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license); return 0; } static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[]) { wpa_cli_quit = 1; if (interactive) eloop_terminate(); return 0; } static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256]; int res; if (argc == 1) { res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]); if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { printf("Too long SET command.\n"); return -1; } return wpa_ctrl_command(ctrl, cmd); } return wpa_cli_cmd(ctrl, "SET", 2, argc, argv); } static char ** wpa_cli_complete_set(const char *str, int pos) { int arg = get_cmd_arg_num(str, pos); const char *fields[] = { /* runtime values */ "EAPOL::heldPeriod", "EAPOL::authPeriod", "EAPOL::startPeriod", "EAPOL::maxStart", "dot11RSNAConfigPMKLifetime", "dot11RSNAConfigPMKReauthThreshold", "dot11RSNAConfigSATimeout", "wps_fragment_size", "wps_version_number", "ampdu", "tdls_testing", "tdls_disabled", "pno", "radio_disabled", "uapsd", "ps", "wifi_display", "bssid_filter", "disallow_aps", "no_keep_alive", /* global configuration parameters */ "eapol_version", "ap_scan", "disable_scan_offload", "fast_reauth", "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path", "pcsc_reader", "pcsc_pin", "driver_param", "dot11RSNAConfigPMKLifetime", "dot11RSNAConfigPMKReauthThreshold", "dot11RSNAConfigSATimeout", "update_config", "load_dynamic_eap", "uuid", "device_name", "manufacturer", "model_name", "model_number", "serial_number", "device_type", "os_version", "config_methods", "wps_cred_processing", "wps_vendor_ext_m1", "sec_device_type", "p2p_listen_reg_class", "p2p_listen_channel", "p2p_oper_reg_class", "p2p_oper_channel", "p2p_go_intent", "p2p_ssid_postfix", "persistent_reconnect", "p2p_intra_bss", "p2p_group_idle", "p2p_pref_chan", "p2p_no_go_freq", "p2p_go_ht40", "p2p_disabled", "p2p_no_group_iface", "p2p_go_vht", "p2p_ignore_shared_freq", "country", "bss_max_count", "bss_expiration_age", "bss_expiration_scan_count", "filter_ssids", "filter_rssi", "max_num_sta", "disassoc_low_ack", "hs20", "interworking", "hessid", "access_network_type", "pbc_in_m1", "autoscan", "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey", "wps_nfc_dh_privkey", "wps_nfc_dev_pw", "ext_password_backend", "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf", "sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements", "ignore_old_scan_res", "freq_list", "external_sim", "tdls_external_control" }; int i, num_fields = ARRAY_SIZE(fields); if (arg == 1) { char **res = os_calloc(num_fields + 1, sizeof(char *)); if (res == NULL) return NULL; for (i = 0; i < num_fields; i++) { res[i] = os_strdup(fields[i]); if (res[i] == NULL) return res; } return res; } if (arg > 1 && os_strncasecmp(str, "set bssid_filter ", 17) == 0) return cli_txt_list_array(&bsses); return NULL; } static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "GET", 1, argc, argv); } static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "LOGOFF"); } static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "LOGON"); } static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "REASSOCIATE"); } static int wpa_cli_cmd_reattach(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "REATTACH"); } static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "PREAUTH", 1, argc, argv); } static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "AP_SCAN", 1, argc, argv); } static int wpa_cli_cmd_scan_interval(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "SCAN_INTERVAL", 1, argc, argv); } static int wpa_cli_cmd_bss_expire_age(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "BSS_EXPIRE_AGE", 1, argc, argv); } static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "BSS_EXPIRE_COUNT", 1, argc, argv); } static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256]; int res; if (argc < 1) res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH 0"); else res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH %s", argv[0]); if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { printf("Too long BSS_FLUSH command.\n"); return -1; } return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv); } static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv); } static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "WPS_PBC", 0, argc, argv); } static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc == 0) { printf("Invalid WPS_PIN command: need one or two arguments:\n" "- BSSID: use 'any' to select any\n" "- PIN: optional, used only with devices that have no " "display\n"); return -1; } return wpa_cli_cmd(ctrl, "WPS_PIN", 1, argc, argv); } static int wpa_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "WPS_CHECK_PIN", 1, argc, argv); } static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "WPS_CANCEL"); } #ifdef CONFIG_WPS_NFC static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "WPS_NFC", 0, argc, argv); } static int wpa_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "WPS_NFC_CONFIG_TOKEN", 1, argc, argv); } static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "WPS_NFC_TOKEN", 1, argc, argv); } static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc, char *argv[]) { int ret; char *buf; size_t buflen; if (argc != 1) { printf("Invalid 'wps_nfc_tag_read' command - one argument " "is required.\n"); return -1; } buflen = 18 + os_strlen(argv[0]); buf = os_malloc(buflen); if (buf == NULL) return -1; os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]); ret = wpa_ctrl_command(ctrl, buf); os_free(buf); return ret; } static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv); } static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv); } static int wpa_cli_cmd_nfc_report_handover(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "NFC_REPORT_HANDOVER", 4, argc, argv); } #endif /* CONFIG_WPS_NFC */ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256]; int res; if (argc == 2) res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s", argv[0], argv[1]); else if (argc == 5 || argc == 6) { char ssid_hex[2 * 32 + 1]; char key_hex[2 * 64 + 1]; int i; ssid_hex[0] = '\0'; for (i = 0; i < 32; i++) { if (argv[2][i] == '\0') break; os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]); } key_hex[0] = '\0'; if (argc == 6) { for (i = 0; i < 64; i++) { if (argv[5][i] == '\0') break; os_snprintf(&key_hex[i * 2], 3, "%02x", argv[5][i]); } } res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s %s %s %s %s", argv[0], argv[1], ssid_hex, argv[3], argv[4], key_hex); } else { printf("Invalid WPS_REG command: need two arguments:\n" "- BSSID of the target AP\n" "- AP PIN\n"); printf("Alternatively, six arguments can be used to " "reconfigure the AP:\n" "- BSSID of the target AP\n" "- AP PIN\n" "- new SSID\n" "- new auth (OPEN, WPAPSK, WPA2PSK)\n" "- new encr (NONE, WEP, TKIP, CCMP)\n" "- new key\n"); return -1; } if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { printf("Too long WPS_REG command.\n"); return -1; } return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "WPS_AP_PIN", 1, argc, argv); } static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "WPS_ER_START", 0, argc, argv); } static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "WPS_ER_STOP"); } static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc < 2) { printf("Invalid WPS_ER_PIN command: need at least two " "arguments:\n" "- UUID: use 'any' to select any\n" "- PIN: Enrollee PIN\n" "optional: - Enrollee MAC address\n"); return -1; } return wpa_cli_cmd(ctrl, "WPS_ER_PIN", 2, argc, argv); } static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "WPS_ER_PBC", 1, argc, argv); } static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc != 2) { printf("Invalid WPS_ER_LEARN command: need two arguments:\n" "- UUID: specify which AP to use\n" "- PIN: AP PIN\n"); return -1; } return wpa_cli_cmd(ctrl, "WPS_ER_LEARN", 2, argc, argv); } static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc != 2) { printf("Invalid WPS_ER_SET_CONFIG command: need two " "arguments:\n" "- UUID: specify which AP to use\n" "- Network configuration id\n"); return -1; } return wpa_cli_cmd(ctrl, "WPS_ER_SET_CONFIG", 2, argc, argv); } static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256]; int res; if (argc == 5 || argc == 6) { char ssid_hex[2 * 32 + 1]; char key_hex[2 * 64 + 1]; int i; ssid_hex[0] = '\0'; for (i = 0; i < 32; i++) { if (argv[2][i] == '\0') break; os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]); } key_hex[0] = '\0'; if (argc == 6) { for (i = 0; i < 64; i++) { if (argv[5][i] == '\0') break; os_snprintf(&key_hex[i * 2], 3, "%02x", argv[5][i]); } } res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_CONFIG %s %s %s %s %s %s", argv[0], argv[1], ssid_hex, argv[3], argv[4], key_hex); } else { printf("Invalid WPS_ER_CONFIG command: need six arguments:\n" "- AP UUID\n" "- AP PIN\n" "- new SSID\n" "- new auth (OPEN, WPAPSK, WPA2PSK)\n" "- new encr (NONE, WEP, TKIP, CCMP)\n" "- new key\n"); return -1; } if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { printf("Too long WPS_ER_CONFIG command.\n"); return -1; } return wpa_ctrl_command(ctrl, cmd); } #ifdef CONFIG_WPS_NFC static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc != 2) { printf("Invalid WPS_ER_NFC_CONFIG_TOKEN command: need two " "arguments:\n" "- WPS/NDEF: token format\n" "- UUID: specify which AP to use\n"); return -1; } return wpa_cli_cmd(ctrl, "WPS_ER_NFC_CONFIG_TOKEN", 2, argc, argv); } #endif /* CONFIG_WPS_NFC */ static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "IBSS_RSN", 1, argc, argv); } static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "LEVEL", 1, argc, argv); } static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256], *pos, *end; int i, ret; if (argc < 2) { printf("Invalid IDENTITY command: needs two arguments " "(network id and identity)\n"); return -1; } end = cmd + sizeof(cmd); pos = cmd; ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s", argv[0], argv[1]); if (ret < 0 || ret >= end - pos) { printf("Too long IDENTITY command.\n"); return -1; } pos += ret; for (i = 2; i < argc; i++) { ret = os_snprintf(pos, end - pos, " %s", argv[i]); if (ret < 0 || ret >= end - pos) { printf("Too long IDENTITY command.\n"); return -1; } pos += ret; } return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256], *pos, *end; int i, ret; if (argc < 2) { printf("Invalid PASSWORD command: needs two arguments " "(network id and password)\n"); return -1; } end = cmd + sizeof(cmd); pos = cmd; ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s", argv[0], argv[1]); if (ret < 0 || ret >= end - pos) { printf("Too long PASSWORD command.\n"); return -1; } pos += ret; for (i = 2; i < argc; i++) { ret = os_snprintf(pos, end - pos, " %s", argv[i]); if (ret < 0 || ret >= end - pos) { printf("Too long PASSWORD command.\n"); return -1; } pos += ret; } return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256], *pos, *end; int i, ret; if (argc < 2) { printf("Invalid NEW_PASSWORD command: needs two arguments " "(network id and password)\n"); return -1; } end = cmd + sizeof(cmd); pos = cmd; ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s", argv[0], argv[1]); if (ret < 0 || ret >= end - pos) { printf("Too long NEW_PASSWORD command.\n"); return -1; } pos += ret; for (i = 2; i < argc; i++) { ret = os_snprintf(pos, end - pos, " %s", argv[i]); if (ret < 0 || ret >= end - pos) { printf("Too long NEW_PASSWORD command.\n"); return -1; } pos += ret; } return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256], *pos, *end; int i, ret; if (argc < 2) { printf("Invalid PIN command: needs two arguments " "(network id and pin)\n"); return -1; } end = cmd + sizeof(cmd); pos = cmd; ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s", argv[0], argv[1]); if (ret < 0 || ret >= end - pos) { printf("Too long PIN command.\n"); return -1; } pos += ret; for (i = 2; i < argc; i++) { ret = os_snprintf(pos, end - pos, " %s", argv[i]); if (ret < 0 || ret >= end - pos) { printf("Too long PIN command.\n"); return -1; } pos += ret; } return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256], *pos, *end; int i, ret; if (argc < 2) { printf("Invalid OTP command: needs two arguments (network " "id and password)\n"); return -1; } end = cmd + sizeof(cmd); pos = cmd; ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s", argv[0], argv[1]); if (ret < 0 || ret >= end - pos) { printf("Too long OTP command.\n"); return -1; } pos += ret; for (i = 2; i < argc; i++) { ret = os_snprintf(pos, end - pos, " %s", argv[i]); if (ret < 0 || ret >= end - pos) { printf("Too long OTP command.\n"); return -1; } pos += ret; } return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256], *pos, *end; int i, ret; if (argc < 2) { printf("Invalid SIM command: needs two arguments " "(network id and SIM operation response)\n"); return -1; } end = cmd + sizeof(cmd); pos = cmd; ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s", argv[0], argv[1]); if (ret < 0 || ret >= end - pos) { printf("Too long SIM command.\n"); return -1; } pos += ret; for (i = 2; i < argc; i++) { ret = os_snprintf(pos, end - pos, " %s", argv[i]); if (ret < 0 || ret >= end - pos) { printf("Too long SIM command.\n"); return -1; } pos += ret; } return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256], *pos, *end; int i, ret; if (argc < 2) { printf("Invalid PASSPHRASE command: needs two arguments " "(network id and passphrase)\n"); return -1; } end = cmd + sizeof(cmd); pos = cmd; ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s", argv[0], argv[1]); if (ret < 0 || ret >= end - pos) { printf("Too long PASSPHRASE command.\n"); return -1; } pos += ret; for (i = 2; i < argc; i++) { ret = os_snprintf(pos, end - pos, " %s", argv[i]); if (ret < 0 || ret >= end - pos) { printf("Too long PASSPHRASE command.\n"); return -1; } pos += ret; } return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc < 2) { printf("Invalid BSSID command: needs two arguments (network " "id and BSSID)\n"); return -1; } return wpa_cli_cmd(ctrl, "BSSID", 2, argc, argv); } static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "BLACKLIST", 0, argc, argv); } static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "LOG_LEVEL", 0, argc, argv); } static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "LIST_NETWORKS"); } static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "SELECT_NETWORK", 1, argc, argv); } static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "ENABLE_NETWORK", 1, argc, argv); } static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "DISABLE_NETWORK", 1, argc, argv); } static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "ADD_NETWORK"); } static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv); } static void wpa_cli_show_network_variables(void) { printf("set_network variables:\n" " ssid (network name, SSID)\n" " psk (WPA passphrase or pre-shared key)\n" " key_mgmt (key management protocol)\n" " identity (EAP identity)\n" " password (EAP password)\n" " ...\n" "\n" "Note: Values are entered in the same format as the " "configuration file is using,\n" "i.e., strings values need to be inside double quotation " "marks.\n" "For example: set_network 1 ssid \"network name\"\n" "\n" "Please see wpa_supplicant.conf documentation for full list " "of\navailable variables.\n"); } static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc == 0) { wpa_cli_show_network_variables(); return 0; } if (argc < 3) { printf("Invalid SET_NETWORK command: needs three arguments\n" "(network id, variable name, and value)\n"); return -1; } return wpa_cli_cmd(ctrl, "SET_NETWORK", 3, argc, argv); } static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc == 0) { wpa_cli_show_network_variables(); return 0; } if (argc != 2) { printf("Invalid GET_NETWORK command: needs two arguments\n" "(network id and variable name)\n"); return -1; } return wpa_cli_cmd(ctrl, "GET_NETWORK", 2, argc, argv); } static int wpa_cli_cmd_dup_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc == 0) { wpa_cli_show_network_variables(); return 0; } if (argc < 3) { printf("Invalid DUP_NETWORK command: needs three arguments\n" "(src netid, dest netid, and variable name)\n"); return -1; } return wpa_cli_cmd(ctrl, "DUP_NETWORK", 3, argc, argv); } static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "LIST_CREDS"); } static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "ADD_CRED"); } static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv); } static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc != 3) { printf("Invalid SET_CRED command: needs three arguments\n" "(cred id, variable name, and value)\n"); return -1; } return wpa_cli_cmd(ctrl, "SET_CRED", 3, argc, argv); } static int wpa_cli_cmd_get_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc != 2) { printf("Invalid GET_CRED command: needs two arguments\n" "(cred id, variable name)\n"); return -1; } return wpa_cli_cmd(ctrl, "GET_CRED", 2, argc, argv); } static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "DISCONNECT"); } static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "RECONNECT"); } static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "SAVE_CONFIG"); } static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "SCAN", 0, argc, argv); } static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "SCAN_RESULTS"); } static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv); } static char ** wpa_cli_complete_bss(const char *str, int pos) { int arg = get_cmd_arg_num(str, pos); char **res = NULL; switch (arg) { case 1: res = cli_txt_list_array(&bsses); break; } return res; } static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc < 1 || argc > 2) { printf("Invalid GET_CAPABILITY command: need either one or " "two arguments\n"); return -1; } if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) { printf("Invalid GET_CAPABILITY command: second argument, " "if any, must be 'strict'\n"); return -1; } return wpa_cli_cmd(ctrl, "GET_CAPABILITY", 1, argc, argv); } static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl) { printf("Available interfaces:\n"); return wpa_ctrl_command(ctrl, "INTERFACES"); } static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc < 1) { wpa_cli_list_interfaces(ctrl); return 0; } wpa_cli_close_connection(); os_free(ctrl_ifname); ctrl_ifname = os_strdup(argv[0]); if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) { printf("Connected to interface '%s.\n", ctrl_ifname); } else { printf("Could not connect to interface '%s' - re-trying\n", ctrl_ifname); } return 0; } static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "RECONFIGURE"); } static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "TERMINATE"); } static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256]; int res; if (argc < 1) { printf("Invalid INTERFACE_ADD command: needs at least one " "argument (interface name)\n" "All arguments: ifname confname driver ctrl_interface " "driver_param bridge_name\n"); return -1; } /* * INTERFACE_ADD TABTABTABTAB * TAB */ res = os_snprintf(cmd, sizeof(cmd), "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s", argv[0], argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "", argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "", argc > 5 ? argv[5] : ""); if (res < 0 || (size_t) res >= sizeof(cmd)) return -1; cmd[sizeof(cmd) - 1] = '\0'; return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "INTERFACE_REMOVE", 1, argc, argv); } static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "INTERFACE_LIST"); } #ifdef CONFIG_AP static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "STA", 1, argc, argv); } static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd, char *addr, size_t addr_len) { char buf[4096], *pos; size_t len; int ret; if (ctrl_conn == NULL) { printf("Not connected to hostapd - command dropped.\n"); return -1; } len = sizeof(buf) - 1; ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, wpa_cli_msg_cb); if (ret == -2) { printf("'%s' command timed out.\n", cmd); return -2; } else if (ret < 0) { printf("'%s' command failed.\n", cmd); return -1; } buf[len] = '\0'; if (os_memcmp(buf, "FAIL", 4) == 0) return -1; printf("%s", buf); pos = buf; while (*pos != '\0' && *pos != '\n') pos++; *pos = '\0'; os_strlcpy(addr, buf, addr_len); return 0; } static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char addr[32], cmd[64]; if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr))) return 0; do { os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0); return -1; } static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "DEAUTHENTICATE", 1, argc, argv); } static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv); } static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "CHAN_SWITCH", 2, argc, argv); } #endif /* CONFIG_AP */ static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "SUSPEND"); } static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "RESUME"); } #ifdef CONFIG_TESTING_OPTIONS static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "DROP_SA"); } #endif /* CONFIG_TESTING_OPTIONS */ static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "ROAM", 1, argc, argv); } #ifdef CONFIG_P2P static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "P2P_FIND", 0, argc, argv); } static char ** wpa_cli_complete_p2p_find(const char *str, int pos) { char **res = NULL; int arg = get_cmd_arg_num(str, pos); res = os_calloc(6, sizeof(char *)); if (res == NULL) return NULL; res[0] = os_strdup("type=social"); if (res[0] == NULL) { os_free(res); return NULL; } res[1] = os_strdup("type=progressive"); if (res[1] == NULL) return res; res[2] = os_strdup("delay="); if (res[2] == NULL) return res; res[3] = os_strdup("dev_id="); if (res[3] == NULL) return res; if (arg == 1) res[4] = os_strdup("[timeout]"); return res; } static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "P2P_STOP_FIND"); } static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "P2P_CONNECT", 2, argc, argv); } static char ** wpa_cli_complete_p2p_connect(const char *str, int pos) { int arg = get_cmd_arg_num(str, pos); char **res = NULL; switch (arg) { case 1: res = cli_txt_list_array(&p2p_peers); break; } return res; } static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "P2P_LISTEN", 0, argc, argv); } static int wpa_cli_cmd_p2p_group_remove(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "P2P_GROUP_REMOVE", 1, argc, argv); } static char ** wpa_cli_complete_p2p_group_remove(const char *str, int pos) { int arg = get_cmd_arg_num(str, pos); char **res = NULL; switch (arg) { case 1: res = cli_txt_list_array(&p2p_groups); break; } return res; } static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "P2P_GROUP_ADD", 0, argc, argv); } static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc != 2 && argc != 3) { printf("Invalid P2P_PROV_DISC command: needs at least " "two arguments, address and config method\n" "(display, keypad, or pbc) and an optional join\n"); return -1; } return wpa_cli_cmd(ctrl, "P2P_PROV_DISC", 2, argc, argv); } static int wpa_cli_cmd_p2p_get_passphrase(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "P2P_GET_PASSPHRASE"); } static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[4096]; if (argc != 2 && argc != 4) { printf("Invalid P2P_SERV_DISC_REQ command: needs two " "arguments (address and TLVs) or four arguments " "(address, \"upnp\", version, search target " "(SSDP ST:)\n"); return -1; } if (write_cmd(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ", argc, argv) < 0) return -1; return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_p2p_serv_disc_cancel_req(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_CANCEL_REQ", 1, argc, argv); } static int wpa_cli_cmd_p2p_serv_disc_resp(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[4096]; int res; if (argc != 4) { printf("Invalid P2P_SERV_DISC_RESP command: needs four " "arguments (freq, address, dialog token, and TLVs)\n"); return -1; } res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_RESP %s %s %s %s", argv[0], argv[1], argv[2], argv[3]); if (res < 0 || (size_t) res >= sizeof(cmd)) return -1; cmd[sizeof(cmd) - 1] = '\0'; return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_p2p_service_update(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "P2P_SERVICE_UPDATE"); } static int wpa_cli_cmd_p2p_serv_disc_external(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_EXTERNAL", 1, argc, argv); } static int wpa_cli_cmd_p2p_service_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "P2P_SERVICE_FLUSH"); } static int wpa_cli_cmd_p2p_service_add(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[4096]; int res; if (argc != 3 && argc != 4) { printf("Invalid P2P_SERVICE_ADD command: needs three or four " "arguments\n"); return -1; } if (argc == 4) res = os_snprintf(cmd, sizeof(cmd), "P2P_SERVICE_ADD %s %s %s %s", argv[0], argv[1], argv[2], argv[3]); else res = os_snprintf(cmd, sizeof(cmd), "P2P_SERVICE_ADD %s %s %s", argv[0], argv[1], argv[2]); if (res < 0 || (size_t) res >= sizeof(cmd)) return -1; cmd[sizeof(cmd) - 1] = '\0'; return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[4096]; int res; if (argc != 2 && argc != 3) { printf("Invalid P2P_SERVICE_DEL command: needs two or three " "arguments\n"); return -1; } if (argc == 3) res = os_snprintf(cmd, sizeof(cmd), "P2P_SERVICE_DEL %s %s %s", argv[0], argv[1], argv[2]); else res = os_snprintf(cmd, sizeof(cmd), "P2P_SERVICE_DEL %s %s", argv[0], argv[1]); if (res < 0 || (size_t) res >= sizeof(cmd)) return -1; cmd[sizeof(cmd) - 1] = '\0'; return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_p2p_reject(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "P2P_REJECT", 1, argc, argv); } static int wpa_cli_cmd_p2p_invite(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "P2P_INVITE", 1, argc, argv); } static int wpa_cli_cmd_p2p_peer(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "P2P_PEER", 1, argc, argv); } static char ** wpa_cli_complete_p2p_peer(const char *str, int pos) { int arg = get_cmd_arg_num(str, pos); char **res = NULL; switch (arg) { case 1: res = cli_txt_list_array(&p2p_peers); break; } return res; } static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd, char *addr, size_t addr_len, int discovered) { char buf[4096], *pos; size_t len; int ret; if (ctrl_conn == NULL) return -1; len = sizeof(buf) - 1; ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, wpa_cli_msg_cb); if (ret == -2) { printf("'%s' command timed out.\n", cmd); return -2; } else if (ret < 0) { printf("'%s' command failed.\n", cmd); return -1; } buf[len] = '\0'; if (os_memcmp(buf, "FAIL", 4) == 0) return -1; pos = buf; while (*pos != '\0' && *pos != '\n') pos++; *pos++ = '\0'; os_strlcpy(addr, buf, addr_len); if (!discovered || os_strstr(pos, "[PROBE_REQ_ONLY]") == NULL) printf("%s\n", addr); return 0; } static int wpa_cli_cmd_p2p_peers(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char addr[32], cmd[64]; int discovered; discovered = argc > 0 && os_strcmp(argv[0], "discovered") == 0; if (wpa_ctrl_command_p2p_peer(ctrl, "P2P_PEER FIRST", addr, sizeof(addr), discovered)) return -1; do { os_snprintf(cmd, sizeof(cmd), "P2P_PEER NEXT-%s", addr); } while (wpa_ctrl_command_p2p_peer(ctrl, cmd, addr, sizeof(addr), discovered) == 0); return 0; } static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "P2P_SET", 2, argc, argv); } static char ** wpa_cli_complete_p2p_set(const char *str, int pos) { int arg = get_cmd_arg_num(str, pos); const char *fields[] = { "discoverability", "managed", "listen_channel", "ssid_postfix", "noa", "ps", "oppps", "ctwindow", "disabled", "conc_pref", "force_long_sd", "peer_filter", "cross_connect", "go_apsd", "client_apsd", "disallow_freq", "disc_int", "per_sta_psk", }; int i, num_fields = ARRAY_SIZE(fields); if (arg == 1) { char **res = os_calloc(num_fields + 1, sizeof(char *)); if (res == NULL) return NULL; for (i = 0; i < num_fields; i++) { res[i] = os_strdup(fields[i]); if (res[i] == NULL) return res; } return res; } if (arg == 2 && os_strncasecmp(str, "p2p_set peer_filter ", 20) == 0) return cli_txt_list_array(&p2p_peers); return NULL; } static int wpa_cli_cmd_p2p_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "P2P_FLUSH"); } static int wpa_cli_cmd_p2p_cancel(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "P2P_CANCEL"); } static int wpa_cli_cmd_p2p_unauthorize(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "P2P_UNAUTHORIZE", 1, argc, argv); } static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc != 0 && argc != 2 && argc != 4) { printf("Invalid P2P_PRESENCE_REQ command: needs two arguments " "(preferred duration, interval; in microsecods).\n" "Optional second pair can be used to provide " "acceptable values.\n"); return -1; } return wpa_cli_cmd(ctrl, "P2P_PRESENCE_REQ", 0, argc, argv); } static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc != 0 && argc != 2) { printf("Invalid P2P_EXT_LISTEN command: needs two arguments " "(availability period, availability interval; in " "millisecods).\n" "Extended Listen Timing can be cancelled with this " "command when used without parameters.\n"); return -1; } return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv); } static int wpa_cli_cmd_p2p_remove_client(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "P2P_REMOVE_CLIENT", 1, argc, argv); } #endif /* CONFIG_P2P */ #ifdef CONFIG_WIFI_DISPLAY static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[100]; int res; if (argc != 1 && argc != 2) { printf("Invalid WFD_SUBELEM_SET command: needs one or two " "arguments (subelem, hexdump)\n"); return -1; } res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s", argv[0], argc > 1 ? argv[1] : ""); if (res < 0 || (size_t) res >= sizeof(cmd)) return -1; cmd[sizeof(cmd) - 1] = '\0'; return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[100]; int res; if (argc != 1) { printf("Invalid WFD_SUBELEM_GET command: needs one " "argument (subelem)\n"); return -1; } res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s", argv[0]); if (res < 0 || (size_t) res >= sizeof(cmd)) return -1; cmd[sizeof(cmd) - 1] = '\0'; return wpa_ctrl_command(ctrl, cmd); } #endif /* CONFIG_WIFI_DISPLAY */ #ifdef CONFIG_INTERWORKING static int wpa_cli_cmd_fetch_anqp(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "FETCH_ANQP"); } static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "STOP_FETCH_ANQP"); } static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "INTERWORKING_SELECT", 0, argc, argv); } static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "INTERWORKING_CONNECT", 1, argc, argv); } static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv); } static int wpa_cli_cmd_gas_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "GAS_REQUEST", 2, argc, argv); } static int wpa_cli_cmd_gas_response_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "GAS_RESPONSE_GET", 2, argc, argv); } #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 static int wpa_cli_cmd_hs20_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "HS20_ANQP_GET", 2, argc, argv); } static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[512]; if (argc == 0) { printf("Command needs one or two arguments (dst mac addr and " "optional home realm)\n"); return -1; } if (write_cmd(cmd, sizeof(cmd), "HS20_GET_NAI_HOME_REALM_LIST", argc, argv) < 0) return -1; return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_hs20_icon_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[512]; if (argc < 2) { printf("Command needs two arguments (dst mac addr and " "icon name)\n"); return -1; } if (write_cmd(cmd, sizeof(cmd), "HS20_ICON_REQUEST", argc, argv) < 0) return -1; return wpa_ctrl_command(ctrl, cmd); } static int wpa_cli_cmd_fetch_osu(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "FETCH_OSU"); } static int wpa_cli_cmd_cancel_fetch_osu(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "CANCEL_FETCH_OSU"); } #endif /* CONFIG_HS20 */ static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "STA_AUTOCONNECT", 1, argc, argv); } static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "TDLS_DISCOVER", 1, argc, argv); } static int wpa_cli_cmd_tdls_setup(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "TDLS_SETUP", 1, argc, argv); } static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "TDLS_TEARDOWN", 1, argc, argv); } static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "SIGNAL_POLL"); } static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "PKTCNT_POLL"); } static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "REAUTHENTICATE"); } #ifdef CONFIG_AUTOSCAN static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc == 0) return wpa_ctrl_command(ctrl, "AUTOSCAN "); return wpa_cli_cmd(ctrl, "AUTOSCAN", 0, argc, argv); } #endif /* CONFIG_AUTOSCAN */ #ifdef CONFIG_WNM static int wpa_cli_cmd_wnm_sleep(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv); } static int wpa_cli_cmd_wnm_bss_query(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "WNM_BSS_QUERY", 1, argc, argv); } #endif /* CONFIG_WNM */ static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc == 0) return -1; return wpa_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]); } #ifdef ANDROID static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "DRIVER", 1, argc, argv); } #endif /* ANDROID */ static int wpa_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "VENDOR", 1, argc, argv); } static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "FLUSH"); } static int wpa_cli_cmd_radio_work(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "RADIO_WORK", 1, argc, argv); } enum wpa_cli_cmd_flags { cli_cmd_flag_none = 0x00, cli_cmd_flag_sensitive = 0x01 }; struct wpa_cli_cmd { const char *cmd; int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); char ** (*completion)(const char *str, int pos); enum wpa_cli_cmd_flags flags; const char *usage; }; static struct wpa_cli_cmd wpa_cli_commands[] = { { "status", wpa_cli_cmd_status, NULL, cli_cmd_flag_none, "[verbose] = get current WPA/EAPOL/EAP status" }, { "ifname", wpa_cli_cmd_ifname, NULL, cli_cmd_flag_none, "= get current interface name" }, { "ping", wpa_cli_cmd_ping, NULL, cli_cmd_flag_none, "= pings wpa_supplicant" }, { "relog", wpa_cli_cmd_relog, NULL, cli_cmd_flag_none, "= re-open log-file (allow rolling logs)" }, { "note", wpa_cli_cmd_note, NULL, cli_cmd_flag_none, " = add a note to wpa_supplicant debug log" }, { "mib", wpa_cli_cmd_mib, NULL, cli_cmd_flag_none, "= get MIB variables (dot1x, dot11)" }, { "help", wpa_cli_cmd_help, wpa_cli_complete_help, cli_cmd_flag_none, "[command] = show usage help" }, { "interface", wpa_cli_cmd_interface, NULL, cli_cmd_flag_none, "[ifname] = show interfaces/select interface" }, { "level", wpa_cli_cmd_level, NULL, cli_cmd_flag_none, " = change debug level" }, { "license", wpa_cli_cmd_license, NULL, cli_cmd_flag_none, "= show full wpa_cli license" }, { "quit", wpa_cli_cmd_quit, NULL, cli_cmd_flag_none, "= exit wpa_cli" }, { "set", wpa_cli_cmd_set, wpa_cli_complete_set, cli_cmd_flag_none, "= set variables (shows list of variables when run without " "arguments)" }, { "get", wpa_cli_cmd_get, NULL, cli_cmd_flag_none, " = get information" }, { "logon", wpa_cli_cmd_logon, NULL, cli_cmd_flag_none, "= IEEE 802.1X EAPOL state machine logon" }, { "logoff", wpa_cli_cmd_logoff, NULL, cli_cmd_flag_none, "= IEEE 802.1X EAPOL state machine logoff" }, { "pmksa", wpa_cli_cmd_pmksa, NULL, cli_cmd_flag_none, "= show PMKSA cache" }, { "reassociate", wpa_cli_cmd_reassociate, NULL, cli_cmd_flag_none, "= force reassociation" }, { "reattach", wpa_cli_cmd_reattach, NULL, cli_cmd_flag_none, "= force reassociation back to the same BSS" }, { "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss, cli_cmd_flag_none, " = force preauthentication" }, { "identity", wpa_cli_cmd_identity, NULL, cli_cmd_flag_none, " = configure identity for an SSID" }, { "password", wpa_cli_cmd_password, NULL, cli_cmd_flag_sensitive, " = configure password for an SSID" }, { "new_password", wpa_cli_cmd_new_password, NULL, cli_cmd_flag_sensitive, " = change password for an SSID" }, { "pin", wpa_cli_cmd_pin, NULL, cli_cmd_flag_sensitive, " = configure pin for an SSID" }, { "otp", wpa_cli_cmd_otp, NULL, cli_cmd_flag_sensitive, " = configure one-time-password for an SSID" }, { "passphrase", wpa_cli_cmd_passphrase, NULL, cli_cmd_flag_sensitive, " = configure private key passphrase\n" " for an SSID" }, { "sim", wpa_cli_cmd_sim, NULL, cli_cmd_flag_sensitive, " = report SIM operation result" }, { "bssid", wpa_cli_cmd_bssid, NULL, cli_cmd_flag_none, " = set preferred BSSID for an SSID" }, { "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss, cli_cmd_flag_none, " = add a BSSID to the blacklist\n" "blacklist clear = clear the blacklist\n" "blacklist = display the blacklist" }, { "log_level", wpa_cli_cmd_log_level, NULL, cli_cmd_flag_none, " [] = update the log level/timestamp\n" "log_level = display the current log level and log options" }, { "list_networks", wpa_cli_cmd_list_networks, NULL, cli_cmd_flag_none, "= list configured networks" }, { "select_network", wpa_cli_cmd_select_network, NULL, cli_cmd_flag_none, " = select a network (disable others)" }, { "enable_network", wpa_cli_cmd_enable_network, NULL, cli_cmd_flag_none, " = enable a network" }, { "disable_network", wpa_cli_cmd_disable_network, NULL, cli_cmd_flag_none, " = disable a network" }, { "add_network", wpa_cli_cmd_add_network, NULL, cli_cmd_flag_none, "= add a network" }, { "remove_network", wpa_cli_cmd_remove_network, NULL, cli_cmd_flag_none, " = remove a network" }, { "set_network", wpa_cli_cmd_set_network, NULL, cli_cmd_flag_sensitive, " = set network variables (shows\n" " list of variables when run without arguments)" }, { "get_network", wpa_cli_cmd_get_network, NULL, cli_cmd_flag_none, " = get network variables" }, { "dup_network", wpa_cli_cmd_dup_network, NULL, cli_cmd_flag_none, " = duplicate network variables" }, { "list_creds", wpa_cli_cmd_list_creds, NULL, cli_cmd_flag_none, "= list configured credentials" }, { "add_cred", wpa_cli_cmd_add_cred, NULL, cli_cmd_flag_none, "= add a credential" }, { "remove_cred", wpa_cli_cmd_remove_cred, NULL, cli_cmd_flag_none, " = remove a credential" }, { "set_cred", wpa_cli_cmd_set_cred, NULL, cli_cmd_flag_sensitive, " = set credential variables" }, { "get_cred", wpa_cli_cmd_get_cred, NULL, cli_cmd_flag_none, " = get credential variables" }, { "save_config", wpa_cli_cmd_save_config, NULL, cli_cmd_flag_none, "= save the current configuration" }, { "disconnect", wpa_cli_cmd_disconnect, NULL, cli_cmd_flag_none, "= disconnect and wait for reassociate/reconnect command before\n" " connecting" }, { "reconnect", wpa_cli_cmd_reconnect, NULL, cli_cmd_flag_none, "= like reassociate, but only takes effect if already disconnected" }, { "scan", wpa_cli_cmd_scan, NULL, cli_cmd_flag_none, "= request new BSS scan" }, { "scan_results", wpa_cli_cmd_scan_results, NULL, cli_cmd_flag_none, "= get latest scan results" }, { "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss, cli_cmd_flag_none, "< | > = get detailed scan result info" }, { "get_capability", wpa_cli_cmd_get_capability, NULL, cli_cmd_flag_none, " " "= get capabilies" }, { "reconfigure", wpa_cli_cmd_reconfigure, NULL, cli_cmd_flag_none, "= force wpa_supplicant to re-read its configuration file" }, { "terminate", wpa_cli_cmd_terminate, NULL, cli_cmd_flag_none, "= terminate wpa_supplicant" }, { "interface_add", wpa_cli_cmd_interface_add, NULL, cli_cmd_flag_none, " \n" " = adds new interface, all parameters but \n" " are optional" }, { "interface_remove", wpa_cli_cmd_interface_remove, NULL, cli_cmd_flag_none, " = removes the interface" }, { "interface_list", wpa_cli_cmd_interface_list, NULL, cli_cmd_flag_none, "= list available interfaces" }, { "ap_scan", wpa_cli_cmd_ap_scan, NULL, cli_cmd_flag_none, " = set ap_scan parameter" }, { "scan_interval", wpa_cli_cmd_scan_interval, NULL, cli_cmd_flag_none, " = set scan_interval parameter (in seconds)" }, { "bss_expire_age", wpa_cli_cmd_bss_expire_age, NULL, cli_cmd_flag_none, " = set BSS expiration age parameter" }, { "bss_expire_count", wpa_cli_cmd_bss_expire_count, NULL, cli_cmd_flag_none, " = set BSS expiration scan count parameter" }, { "bss_flush", wpa_cli_cmd_bss_flush, NULL, cli_cmd_flag_none, " = set BSS flush age (0 by default)" }, { "stkstart", wpa_cli_cmd_stkstart, NULL, cli_cmd_flag_none, " = request STK negotiation with " }, { "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss, cli_cmd_flag_none, " = request over-the-DS FT with " }, { "wps_pbc", wpa_cli_cmd_wps_pbc, wpa_cli_complete_bss, cli_cmd_flag_none, "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" }, { "wps_pin", wpa_cli_cmd_wps_pin, wpa_cli_complete_bss, cli_cmd_flag_sensitive, " [PIN] = start WPS PIN method (returns PIN, if not " "hardcoded)" }, { "wps_check_pin", wpa_cli_cmd_wps_check_pin, NULL, cli_cmd_flag_sensitive, " = verify PIN checksum" }, { "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none, "Cancels the pending WPS operation" }, #ifdef CONFIG_WPS_NFC { "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss, cli_cmd_flag_none, "[BSSID] = start Wi-Fi Protected Setup: NFC" }, { "wps_nfc_config_token", wpa_cli_cmd_wps_nfc_config_token, NULL, cli_cmd_flag_none, " = build configuration token" }, { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL, cli_cmd_flag_none, " = create password token" }, { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL, cli_cmd_flag_sensitive, " = report read NFC tag with WPS data" }, { "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL, cli_cmd_flag_none, " = create NFC handover request" }, { "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL, cli_cmd_flag_none, " = create NFC handover select" }, { "nfc_report_handover", wpa_cli_cmd_nfc_report_handover, NULL, cli_cmd_flag_none, " = report completed " "NFC handover" }, #endif /* CONFIG_WPS_NFC */ { "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss, cli_cmd_flag_sensitive, " = start WPS Registrar to configure an AP" }, { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin, NULL, cli_cmd_flag_sensitive, "[params..] = enable/disable AP PIN" }, { "wps_er_start", wpa_cli_cmd_wps_er_start, NULL, cli_cmd_flag_none, "[IP address] = start Wi-Fi Protected Setup External Registrar" }, { "wps_er_stop", wpa_cli_cmd_wps_er_stop, NULL, cli_cmd_flag_none, "= stop Wi-Fi Protected Setup External Registrar" }, { "wps_er_pin", wpa_cli_cmd_wps_er_pin, NULL, cli_cmd_flag_sensitive, " = add an Enrollee PIN to External Registrar" }, { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc, NULL, cli_cmd_flag_none, " = accept an Enrollee PBC using External Registrar" }, { "wps_er_learn", wpa_cli_cmd_wps_er_learn, NULL, cli_cmd_flag_sensitive, " = learn AP configuration" }, { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config, NULL, cli_cmd_flag_none, " = set AP configuration for enrolling" }, { "wps_er_config", wpa_cli_cmd_wps_er_config, NULL, cli_cmd_flag_sensitive, " = configure AP" }, #ifdef CONFIG_WPS_NFC { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token, NULL, cli_cmd_flag_none, " = build NFC configuration token" }, #endif /* CONFIG_WPS_NFC */ { "ibss_rsn", wpa_cli_cmd_ibss_rsn, NULL, cli_cmd_flag_none, " = request RSN authentication with in IBSS" }, #ifdef CONFIG_AP { "sta", wpa_cli_cmd_sta, NULL, cli_cmd_flag_none, " = get information about an associated station (AP)" }, { "all_sta", wpa_cli_cmd_all_sta, NULL, cli_cmd_flag_none, "= get information about all associated stations (AP)" }, { "deauthenticate", wpa_cli_cmd_deauthenticate, NULL, cli_cmd_flag_none, " = deauthenticate a station" }, { "disassociate", wpa_cli_cmd_disassociate, NULL, cli_cmd_flag_none, " = disassociate a station" }, { "chan_switch", wpa_cli_cmd_chanswitch, NULL, cli_cmd_flag_none, " [sec_channel_offset=] [center_freq1=]" " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]" " = CSA parameters" }, #endif /* CONFIG_AP */ { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none, "= notification of suspend/hibernate" }, { "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none, "= notification of resume/thaw" }, #ifdef CONFIG_TESTING_OPTIONS { "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none, "= drop SA without deauth/disassoc (test command)" }, #endif /* CONFIG_TESTING_OPTIONS */ { "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss, cli_cmd_flag_none, " = roam to the specified BSS" }, #ifdef CONFIG_P2P { "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find, cli_cmd_flag_none, "[timeout] [type=*] = find P2P Devices for up-to timeout seconds" }, { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none, "= stop P2P Devices search" }, { "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect, cli_cmd_flag_none, " <\"pbc\"|PIN> [ht40] = connect to a P2P Device" }, { "p2p_listen", wpa_cli_cmd_p2p_listen, NULL, cli_cmd_flag_none, "[timeout] = listen for P2P Devices for up-to timeout seconds" }, { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove, wpa_cli_complete_p2p_group_remove, cli_cmd_flag_none, " = remove P2P group interface (terminate group if GO)" }, { "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none, "[ht40] = add a new P2P group (local end as GO)" }, { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc, wpa_cli_complete_p2p_peer, cli_cmd_flag_none, " = request provisioning discovery" }, { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase, NULL, cli_cmd_flag_none, "= get the passphrase for a group (GO only)" }, { "p2p_serv_disc_req", wpa_cli_cmd_p2p_serv_disc_req, wpa_cli_complete_p2p_peer, cli_cmd_flag_none, " = schedule service discovery request" }, { "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req, NULL, cli_cmd_flag_none, " = cancel pending service discovery request" }, { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp, NULL, cli_cmd_flag_none, " = service discovery response" }, { "p2p_service_update", wpa_cli_cmd_p2p_service_update, NULL, cli_cmd_flag_none, "= indicate change in local services" }, { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external, NULL, cli_cmd_flag_none, " = set external processing of service discovery" }, { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush, NULL, cli_cmd_flag_none, "= remove all stored service entries" }, { "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL, cli_cmd_flag_none, " = add a local " "service" }, { "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL, cli_cmd_flag_none, " [|service] = remove a local " "service" }, { "p2p_reject", wpa_cli_cmd_p2p_reject, wpa_cli_complete_p2p_peer, cli_cmd_flag_none, " = reject connection attempts from a specific peer" }, { "p2p_invite", wpa_cli_cmd_p2p_invite, NULL, cli_cmd_flag_none, " [peer=addr] = invite peer" }, { "p2p_peers", wpa_cli_cmd_p2p_peers, NULL, cli_cmd_flag_none, "[discovered] = list known (optionally, only fully discovered) P2P " "peers" }, { "p2p_peer", wpa_cli_cmd_p2p_peer, wpa_cli_complete_p2p_peer, cli_cmd_flag_none, "
= show information about known P2P peer" }, { "p2p_set", wpa_cli_cmd_p2p_set, wpa_cli_complete_p2p_set, cli_cmd_flag_none, " = set a P2P parameter" }, { "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none, "= flush P2P state" }, { "p2p_cancel", wpa_cli_cmd_p2p_cancel, NULL, cli_cmd_flag_none, "= cancel P2P group formation" }, { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize, wpa_cli_complete_p2p_peer, cli_cmd_flag_none, "
= unauthorize a peer" }, { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, NULL, cli_cmd_flag_none, "[ ] [ ] = request GO " "presence" }, { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL, cli_cmd_flag_none, "[ ] = set extended listen timing" }, { "p2p_remove_client", wpa_cli_cmd_p2p_remove_client, wpa_cli_complete_p2p_peer, cli_cmd_flag_none, " = remove a peer from all groups" }, #endif /* CONFIG_P2P */ #ifdef CONFIG_WIFI_DISPLAY { "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL, cli_cmd_flag_none, " [contents] = set Wi-Fi Display subelement" }, { "wfd_subelem_get", wpa_cli_cmd_wfd_subelem_get, NULL, cli_cmd_flag_none, " = get Wi-Fi Display subelement" }, #endif /* CONFIG_WIFI_DISPLAY */ #ifdef CONFIG_INTERWORKING { "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none, "= fetch ANQP information for all APs" }, { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, NULL, cli_cmd_flag_none, "= stop fetch_anqp operation" }, { "interworking_select", wpa_cli_cmd_interworking_select, NULL, cli_cmd_flag_none, "[auto] = perform Interworking network selection" }, { "interworking_connect", wpa_cli_cmd_interworking_connect, wpa_cli_complete_bss, cli_cmd_flag_none, " = connect using Interworking credentials" }, { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss, cli_cmd_flag_none, " [,]... = request ANQP information" }, { "gas_request", wpa_cli_cmd_gas_request, wpa_cli_complete_bss, cli_cmd_flag_none, " [QueryReq] = GAS request" }, { "gas_response_get", wpa_cli_cmd_gas_response_get, wpa_cli_complete_bss, cli_cmd_flag_none, " [start,len] = Fetch last GAS response" }, #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, wpa_cli_complete_bss, cli_cmd_flag_none, " [,]... = request HS 2.0 ANQP information" }, { "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list, wpa_cli_complete_bss, cli_cmd_flag_none, " = get HS20 nai home realm list" }, { "hs20_icon_request", wpa_cli_cmd_hs20_icon_request, wpa_cli_complete_bss, cli_cmd_flag_none, " = get Hotspot 2.0 OSU icon" }, { "fetch_osu", wpa_cli_cmd_fetch_osu, NULL, cli_cmd_flag_none, "= fetch OSU provider information from all APs" }, { "cancel_fetch_osu", wpa_cli_cmd_cancel_fetch_osu, NULL, cli_cmd_flag_none, "= cancel fetch_osu command" }, #endif /* CONFIG_HS20 */ { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL, cli_cmd_flag_none, "<0/1> = disable/enable automatic reconnection" }, { "tdls_discover", wpa_cli_cmd_tdls_discover, NULL, cli_cmd_flag_none, " = request TDLS discovery with " }, { "tdls_setup", wpa_cli_cmd_tdls_setup, NULL, cli_cmd_flag_none, " = request TDLS setup with " }, { "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL, cli_cmd_flag_none, " = tear down TDLS with " }, { "signal_poll", wpa_cli_cmd_signal_poll, NULL, cli_cmd_flag_none, "= get signal parameters" }, { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL, cli_cmd_flag_none, "= get TX/RX packet counters" }, { "reauthenticate", wpa_cli_cmd_reauthenticate, NULL, cli_cmd_flag_none, "= trigger IEEE 802.1X/EAPOL reauthentication" }, #ifdef CONFIG_AUTOSCAN { "autoscan", wpa_cli_cmd_autoscan, NULL, cli_cmd_flag_none, "[params] = Set or unset (if none) autoscan parameters" }, #endif /* CONFIG_AUTOSCAN */ #ifdef CONFIG_WNM { "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none, " [interval=#] = enter/exit WNM-Sleep mode" }, { "wnm_bss_query", wpa_cli_cmd_wnm_bss_query, NULL, cli_cmd_flag_none, " = Send BSS Transition Management Query" }, #endif /* CONFIG_WNM */ { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive, " = Sent unprocessed command" }, { "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none, "= flush wpa_supplicant state" }, #ifdef ANDROID { "driver", wpa_cli_cmd_driver, NULL, cli_cmd_flag_none, " = driver private commands" }, #endif /* ANDROID */ { "radio_work", wpa_cli_cmd_radio_work, NULL, cli_cmd_flag_none, "= radio_work " }, { "vendor", wpa_cli_cmd_vendor, NULL, cli_cmd_flag_none, " [] = Send vendor command" }, { NULL, NULL, NULL, cli_cmd_flag_none, NULL } }; /* * Prints command usage, lines are padded with the specified string. */ static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad) { char c; size_t n; printf("%s%s ", pad, cmd->cmd); for (n = 0; (c = cmd->usage[n]); n++) { printf("%c", c); if (c == '\n') printf("%s", pad); } printf("\n"); } static void print_help(const char *cmd) { int n; printf("commands:\n"); for (n = 0; wpa_cli_commands[n].cmd; n++) { if (cmd == NULL || str_starts(wpa_cli_commands[n].cmd, cmd)) print_cmd_help(&wpa_cli_commands[n], " "); } } static int wpa_cli_edit_filter_history_cb(void *ctx, const char *cmd) { const char *c, *delim; int n; size_t len; delim = os_strchr(cmd, ' '); if (delim) len = delim - cmd; else len = os_strlen(cmd); for (n = 0; (c = wpa_cli_commands[n].cmd); n++) { if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c)) return (wpa_cli_commands[n].flags & cli_cmd_flag_sensitive); } return 0; } static char ** wpa_list_cmd_list(void) { char **res; int i, count; struct cli_txt_entry *e; count = ARRAY_SIZE(wpa_cli_commands); count += dl_list_len(&p2p_groups); count += dl_list_len(&ifnames); res = os_calloc(count + 1, sizeof(char *)); if (res == NULL) return NULL; for (i = 0; wpa_cli_commands[i].cmd; i++) { res[i] = os_strdup(wpa_cli_commands[i].cmd); if (res[i] == NULL) break; } dl_list_for_each(e, &p2p_groups, struct cli_txt_entry, list) { size_t len = 8 + os_strlen(e->txt); res[i] = os_malloc(len); if (res[i] == NULL) break; os_snprintf(res[i], len, "ifname=%s", e->txt); i++; } dl_list_for_each(e, &ifnames, struct cli_txt_entry, list) { res[i] = os_strdup(e->txt); if (res[i] == NULL) break; i++; } return res; } static char ** wpa_cli_cmd_completion(const char *cmd, const char *str, int pos) { int i; for (i = 0; wpa_cli_commands[i].cmd; i++) { if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) { if (wpa_cli_commands[i].completion) return wpa_cli_commands[i].completion(str, pos); edit_clear_line(); printf("\r%s\n", wpa_cli_commands[i].usage); edit_redraw(); break; } } return NULL; } static char ** wpa_cli_edit_completion_cb(void *ctx, const char *str, int pos) { char **res; const char *end; char *cmd; if (pos > 7 && os_strncasecmp(str, "IFNAME=", 7) == 0) { end = os_strchr(str, ' '); if (end && pos > end - str) { pos -= end - str + 1; str = end + 1; } } end = os_strchr(str, ' '); if (end == NULL || str + pos < end) return wpa_list_cmd_list(); cmd = os_malloc(pos + 1); if (cmd == NULL) return NULL; os_memcpy(cmd, str, pos); cmd[end - str] = '\0'; res = wpa_cli_cmd_completion(cmd, str, pos); os_free(cmd); return res; } static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) { struct wpa_cli_cmd *cmd, *match = NULL; int count; int ret = 0; if (argc > 1 && os_strncasecmp(argv[0], "IFNAME=", 7) == 0) { ifname_prefix = argv[0] + 7; argv = &argv[1]; argc--; } else ifname_prefix = NULL; if (argc == 0) return -1; count = 0; cmd = wpa_cli_commands; while (cmd->cmd) { if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0) { match = cmd; if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { /* we have an exact match */ count = 1; break; } count++; } cmd++; } if (count > 1) { printf("Ambiguous command '%s'; possible commands:", argv[0]); cmd = wpa_cli_commands; while (cmd->cmd) { if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0) { printf(" %s", cmd->cmd); } cmd++; } printf("\n"); ret = 1; } else if (count == 0) { printf("Unknown command '%s'\n", argv[0]); ret = 1; } else { ret = match->handler(ctrl, argc - 1, &argv[1]); } return ret; } static int str_match(const char *a, const char *b) { return os_strncmp(a, b, os_strlen(b)) == 0; } static int wpa_cli_exec(const char *program, const char *arg1, const char *arg2) { char *cmd; size_t len; int res; int ret = 0; len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3; cmd = os_malloc(len); if (cmd == NULL) return -1; res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2); if (res < 0 || (size_t) res >= len) { os_free(cmd); return -1; } cmd[len - 1] = '\0'; #ifndef _WIN32_WCE if (system(cmd) < 0) ret = -1; #endif /* _WIN32_WCE */ os_free(cmd); return ret; } static void wpa_cli_action_process(const char *msg) { const char *pos; char *copy = NULL, *id, *pos2; pos = msg; if (*pos == '<') { /* skip priority */ pos = os_strchr(pos, '>'); if (pos) pos++; else pos = msg; } if (str_match(pos, WPA_EVENT_CONNECTED)) { int new_id = -1; os_unsetenv("WPA_ID"); os_unsetenv("WPA_ID_STR"); os_unsetenv("WPA_CTRL_DIR"); pos = os_strstr(pos, "[id="); if (pos) copy = os_strdup(pos + 4); if (copy) { pos2 = id = copy; while (*pos2 && *pos2 != ' ') pos2++; *pos2++ = '\0'; new_id = atoi(id); os_setenv("WPA_ID", id, 1); while (*pos2 && *pos2 != '=') pos2++; if (*pos2 == '=') pos2++; id = pos2; while (*pos2 && *pos2 != ']') pos2++; *pos2 = '\0'; os_setenv("WPA_ID_STR", id, 1); os_free(copy); } os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1); if (wpa_cli_connected <= 0 || new_id != wpa_cli_last_id) { wpa_cli_connected = 1; wpa_cli_last_id = new_id; wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED"); } } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) { if (wpa_cli_connected) { wpa_cli_connected = 0; wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED"); } } else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) { wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) { wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) { wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) { wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) { wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, WPS_EVENT_SUCCESS)) { wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, WPS_EVENT_FAIL)) { wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, AP_STA_CONNECTED)) { wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, AP_STA_DISCONNECTED)) { wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, ESS_DISASSOC_IMMINENT)) { wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, HS20_SUBSCRIPTION_REMEDIATION)) { wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, HS20_DEAUTH_IMMINENT_NOTICE)) { wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_match(pos, WPA_EVENT_TERMINATING)) { printf("wpa_supplicant is terminating - stop monitoring\n"); wpa_cli_quit = 1; } } #ifndef CONFIG_ANSI_C_EXTRA static void wpa_cli_action_cb(char *msg, size_t len) { wpa_cli_action_process(msg); } #endif /* CONFIG_ANSI_C_EXTRA */ static void wpa_cli_reconnect(void) { wpa_cli_close_connection(); if (wpa_cli_open_connection(ctrl_ifname, 1) < 0) return; if (interactive) { edit_clear_line(); printf("\rConnection to wpa_supplicant re-established\n"); edit_redraw(); } } static void cli_event(const char *str) { const char *start, *s; start = os_strchr(str, '>'); if (start == NULL) return; start++; if (str_starts(start, WPA_EVENT_BSS_ADDED)) { s = os_strchr(start, ' '); if (s == NULL) return; s = os_strchr(s + 1, ' '); if (s == NULL) return; cli_txt_list_add(&bsses, s + 1); return; } if (str_starts(start, WPA_EVENT_BSS_REMOVED)) { s = os_strchr(start, ' '); if (s == NULL) return; s = os_strchr(s + 1, ' '); if (s == NULL) return; cli_txt_list_del_addr(&bsses, s + 1); return; } #ifdef CONFIG_P2P if (str_starts(start, P2P_EVENT_DEVICE_FOUND)) { s = os_strstr(start, " p2p_dev_addr="); if (s == NULL) return; cli_txt_list_add_addr(&p2p_peers, s + 14); return; } if (str_starts(start, P2P_EVENT_DEVICE_LOST)) { s = os_strstr(start, " p2p_dev_addr="); if (s == NULL) return; cli_txt_list_del_addr(&p2p_peers, s + 14); return; } if (str_starts(start, P2P_EVENT_GROUP_STARTED)) { s = os_strchr(start, ' '); if (s == NULL) return; cli_txt_list_add_word(&p2p_groups, s + 1); return; } if (str_starts(start, P2P_EVENT_GROUP_REMOVED)) { s = os_strchr(start, ' '); if (s == NULL) return; cli_txt_list_del_word(&p2p_groups, s + 1); return; } #endif /* CONFIG_P2P */ } static int check_terminating(const char *msg) { const char *pos = msg; if (*pos == '<') { /* skip priority */ pos = os_strchr(pos, '>'); if (pos) pos++; else pos = msg; } if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) { edit_clear_line(); printf("\rConnection to wpa_supplicant lost - trying to " "reconnect\n"); edit_redraw(); wpa_cli_attached = 0; wpa_cli_close_connection(); return 1; } return 0; } static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor) { if (ctrl_conn == NULL) { wpa_cli_reconnect(); return; } while (wpa_ctrl_pending(ctrl) > 0) { char buf[256]; size_t len = sizeof(buf) - 1; if (wpa_ctrl_recv(ctrl, buf, &len) == 0) { buf[len] = '\0'; if (action_monitor) wpa_cli_action_process(buf); else { cli_event(buf); if (wpa_cli_show_event(buf)) { edit_clear_line(); printf("\r%s\n", buf); edit_redraw(); } if (interactive && check_terminating(buf) > 0) return; } } else { printf("Could not read pending message.\n"); break; } } if (wpa_ctrl_pending(ctrl) < 0) { printf("Connection to wpa_supplicant lost - trying to " "reconnect\n"); wpa_cli_reconnect(); } } #define max_args 10 static int tokenize_cmd(char *cmd, char *argv[]) { char *pos; int argc = 0; pos = cmd; for (;;) { while (*pos == ' ') pos++; if (*pos == '\0') break; argv[argc] = pos; argc++; if (argc == max_args) break; if (*pos == '"') { char *pos2 = os_strrchr(pos, '"'); if (pos2) pos = pos2 + 1; } while (*pos != '\0' && *pos != ' ') pos++; if (*pos == ' ') *pos++ = '\0'; } return argc; } static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx) { if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) { printf("Connection to wpa_supplicant lost - trying to " "reconnect\n"); wpa_cli_close_connection(); } if (!ctrl_conn) wpa_cli_reconnect(); eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL); } static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx) { wpa_cli_recv_pending(mon_conn, 0); } static void wpa_cli_edit_cmd_cb(void *ctx, char *cmd) { char *argv[max_args]; int argc; argc = tokenize_cmd(cmd, argv); if (argc) wpa_request(ctrl_conn, argc, argv); } static void wpa_cli_edit_eof_cb(void *ctx) { eloop_terminate(); } static int warning_displayed = 0; static char *hfile = NULL; static int edit_started = 0; static void start_edit(void) { char *home; char *ps = NULL; #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE ps = wpa_ctrl_get_remote_ifname(ctrl_conn); #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ home = getenv("HOME"); if (home) { const char *fname = ".wpa_cli_history"; int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1; hfile = os_malloc(hfile_len); if (hfile) os_snprintf(hfile, hfile_len, "%s/%s", home, fname); } if (edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb, wpa_cli_edit_completion_cb, NULL, hfile, ps) < 0) { eloop_terminate(); return; } edit_started = 1; eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL); } static void update_bssid_list(struct wpa_ctrl *ctrl) { char buf[4096]; size_t len = sizeof(buf); int ret; char *cmd = "BSS RANGE=ALL MASK=0x2"; char *pos, *end; if (ctrl == NULL) return; ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL); if (ret < 0) return; buf[len] = '\0'; pos = buf; while (pos) { pos = os_strstr(pos, "bssid="); if (pos == NULL) break; pos += 6; end = os_strchr(pos, '\n'); if (end == NULL) break; *end = '\0'; cli_txt_list_add(&bsses, pos); pos = end + 1; } } static void update_ifnames(struct wpa_ctrl *ctrl) { char buf[4096]; size_t len = sizeof(buf); int ret; char *cmd = "INTERFACES"; char *pos, *end; char txt[200]; cli_txt_list_flush(&ifnames); if (ctrl == NULL) return; ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL); if (ret < 0) return; buf[len] = '\0'; pos = buf; while (pos) { end = os_strchr(pos, '\n'); if (end == NULL) break; *end = '\0'; ret = os_snprintf(txt, sizeof(txt), "ifname=%s", pos); if (ret > 0 && ret < (int) sizeof(txt)) cli_txt_list_add(&ifnames, txt); pos = end + 1; } } static void try_connection(void *eloop_ctx, void *timeout_ctx) { if (ctrl_conn) goto done; if (ctrl_ifname == NULL) ctrl_ifname = wpa_cli_get_default_ifname(); if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) { if (!warning_displayed) { printf("Could not connect to wpa_supplicant: " "%s - re-trying\n", ctrl_ifname); warning_displayed = 1; } eloop_register_timeout(1, 0, try_connection, NULL, NULL); return; } update_bssid_list(ctrl_conn); if (warning_displayed) printf("Connection established.\n"); done: start_edit(); } static void wpa_cli_interactive(void) { printf("\nInteractive mode\n\n"); eloop_register_timeout(0, 0, try_connection, NULL, NULL); eloop_run(); eloop_cancel_timeout(try_connection, NULL, NULL); cli_txt_list_flush(&p2p_peers); cli_txt_list_flush(&p2p_groups); cli_txt_list_flush(&bsses); cli_txt_list_flush(&ifnames); if (edit_started) edit_deinit(hfile, wpa_cli_edit_filter_history_cb); os_free(hfile); eloop_cancel_timeout(wpa_cli_ping, NULL, NULL); wpa_cli_close_connection(); } static void wpa_cli_action(struct wpa_ctrl *ctrl) { #ifdef CONFIG_ANSI_C_EXTRA /* TODO: ANSI C version(?) */ printf("Action processing not supported in ANSI C build.\n"); #else /* CONFIG_ANSI_C_EXTRA */ fd_set rfds; int fd, res; struct timeval tv; char buf[256]; /* note: large enough to fit in unsolicited messages */ size_t len; fd = wpa_ctrl_get_fd(ctrl); while (!wpa_cli_quit) { FD_ZERO(&rfds); FD_SET(fd, &rfds); tv.tv_sec = ping_interval; tv.tv_usec = 0; res = select(fd + 1, &rfds, NULL, NULL, &tv); if (res < 0 && errno != EINTR) { perror("select"); break; } if (FD_ISSET(fd, &rfds)) wpa_cli_recv_pending(ctrl, 1); else { /* verify that connection is still working */ len = sizeof(buf) - 1; if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, wpa_cli_action_cb) < 0 || len < 4 || os_memcmp(buf, "PONG", 4) != 0) { printf("wpa_supplicant did not reply to PING " "command - exiting\n"); break; } } } #endif /* CONFIG_ANSI_C_EXTRA */ } static void wpa_cli_cleanup(void) { wpa_cli_close_connection(); if (pid_file) os_daemonize_terminate(pid_file); os_program_deinit(); } static void wpa_cli_terminate(int sig, void *ctx) { eloop_terminate(); } static char * wpa_cli_get_default_ifname(void) { char *ifname = NULL; #ifdef CONFIG_CTRL_IFACE_UNIX struct dirent *dent; DIR *dir = opendir(ctrl_iface_dir); if (!dir) { #ifdef ANDROID char ifprop[PROPERTY_VALUE_MAX]; if (property_get("wifi.interface", ifprop, NULL) != 0) { ifname = os_strdup(ifprop); printf("Using interface '%s'\n", ifname); return ifname; } #endif /* ANDROID */ return NULL; } while ((dent = readdir(dir))) { #ifdef _DIRENT_HAVE_D_TYPE /* * Skip the file if it is not a socket. Also accept * DT_UNKNOWN (0) in case the C library or underlying * file system does not support d_type. */ if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN) continue; #endif /* _DIRENT_HAVE_D_TYPE */ if (os_strcmp(dent->d_name, ".") == 0 || os_strcmp(dent->d_name, "..") == 0) continue; printf("Selected interface '%s'\n", dent->d_name); ifname = os_strdup(dent->d_name); break; } closedir(dir); #endif /* CONFIG_CTRL_IFACE_UNIX */ #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE char buf[4096], *pos; size_t len; struct wpa_ctrl *ctrl; int ret; ctrl = wpa_ctrl_open(NULL); if (ctrl == NULL) return NULL; len = sizeof(buf) - 1; ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL); if (ret >= 0) { buf[len] = '\0'; pos = os_strchr(buf, '\n'); if (pos) *pos = '\0'; ifname = os_strdup(buf); } wpa_ctrl_close(ctrl); #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ return ifname; } int main(int argc, char *argv[]) { int c; int daemonize = 0; int ret = 0; const char *global = NULL; if (os_program_init()) return -1; for (;;) { c = getopt(argc, argv, "a:Bg:G:hi:p:P:v"); if (c < 0) break; switch (c) { case 'a': action_file = optarg; break; case 'B': daemonize = 1; break; case 'g': global = optarg; break; case 'G': ping_interval = atoi(optarg); break; case 'h': usage(); return 0; case 'v': printf("%s\n", wpa_cli_version); return 0; case 'i': os_free(ctrl_ifname); ctrl_ifname = os_strdup(optarg); break; case 'p': ctrl_iface_dir = optarg; break; case 'P': pid_file = optarg; break; default: usage(); return -1; } } interactive = (argc == optind) && (action_file == NULL); if (interactive) printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license); if (eloop_init()) return -1; if (global) { #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE ctrl_conn = wpa_ctrl_open(NULL); #else /* CONFIG_CTRL_IFACE_NAMED_PIPE */ ctrl_conn = wpa_ctrl_open(global); #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ if (ctrl_conn == NULL) { fprintf(stderr, "Failed to connect to wpa_supplicant " "global interface: %s error: %s\n", global, strerror(errno)); return -1; } if (interactive) { update_ifnames(ctrl_conn); mon_conn = wpa_ctrl_open(global); if (mon_conn) { if (wpa_ctrl_attach(mon_conn) == 0) { wpa_cli_attached = 1; eloop_register_read_sock( wpa_ctrl_get_fd(mon_conn), wpa_cli_mon_receive, NULL, NULL); } else { printf("Failed to open monitor " "connection through global " "control interface\n"); } } } } eloop_register_signal_terminate(wpa_cli_terminate, NULL); if (ctrl_ifname == NULL) ctrl_ifname = wpa_cli_get_default_ifname(); if (interactive) { wpa_cli_interactive(); } else { if (!global && wpa_cli_open_connection(ctrl_ifname, 0) < 0) { fprintf(stderr, "Failed to connect to non-global " "ctrl_ifname: %s error: %s\n", ctrl_ifname, strerror(errno)); return -1; } if (action_file) { if (wpa_ctrl_attach(ctrl_conn) == 0) { wpa_cli_attached = 1; } else { printf("Warning: Failed to attach to " "wpa_supplicant.\n"); return -1; } } if (daemonize && os_daemonize(pid_file)) return -1; if (action_file) wpa_cli_action(ctrl_conn); else ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]); } os_free(ctrl_ifname); eloop_destroy(); wpa_cli_cleanup(); return ret; } #else /* CONFIG_CTRL_IFACE */ int main(int argc, char *argv[]) { printf("CONFIG_CTRL_IFACE not defined - wpa_cli disabled\n"); return -1; } #endif /* CONFIG_CTRL_IFACE */ wpa_supplicant-2.2/wpa_supplicant/wps_supplicant.c0000664000175000017500000022201312343617166020467 0ustar jmjm/* * wpa_supplicant / WPS integration * Copyright (c) 2008-2014, 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 "eloop.h" #include "uuid.h" #include "crypto/random.h" #include "crypto/dh_group5.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_common.h" #include "common/wpa_ctrl.h" #include "eap_common/eap_wsc_common.h" #include "eap_peer/eap.h" #include "eapol_supp/eapol_supp_sm.h" #include "rsn_supp/wpa.h" #include "wps/wps_attr_parse.h" #include "config.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "notify.h" #include "blacklist.h" #include "bss.h" #include "scan.h" #include "ap.h" #include "p2p/p2p.h" #include "p2p_supplicant.h" #include "wps_supplicant.h" #ifndef WPS_PIN_SCAN_IGNORE_SEL_REG #define WPS_PIN_SCAN_IGNORE_SEL_REG 3 #endif /* WPS_PIN_SCAN_IGNORE_SEL_REG */ static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx); static void wpas_clear_wps(struct wpa_supplicant *wpa_s); static void wpas_wps_clear_ap_info(struct wpa_supplicant *wpa_s) { os_free(wpa_s->wps_ap); wpa_s->wps_ap = NULL; wpa_s->num_wps_ap = 0; wpa_s->wps_ap_iter = 0; } static void wpas_wps_assoc_with_cred(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; int use_fast_assoc = timeout_ctx != NULL; wpa_printf(MSG_DEBUG, "WPS: Continuing association after eapol_cb"); if (!use_fast_assoc || wpa_supplicant_fast_associate(wpa_s) != 1) wpa_supplicant_req_scan(wpa_s, 0, 0); } static void wpas_wps_assoc_with_cred_cancel(struct wpa_supplicant *wpa_s) { eloop_cancel_timeout(wpas_wps_assoc_with_cred, wpa_s, (void *) 0); eloop_cancel_timeout(wpas_wps_assoc_with_cred, wpa_s, (void *) 1); } int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) { #ifdef CONFIG_P2P if (wpas_p2p_wps_eapol_cb(wpa_s) > 0) return 1; #endif /* CONFIG_P2P */ if (!wpa_s->wps_success && wpa_s->current_ssid && eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) { const u8 *bssid = wpa_s->bssid; if (is_zero_ether_addr(bssid)) bssid = wpa_s->pending_bssid; wpa_printf(MSG_DEBUG, "WPS: PIN registration with " MACSTR " did not succeed - continue trying to find " "suitable AP", MAC2STR(bssid)); wpa_blacklist_add(wpa_s, bssid); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); wpa_s->reassociate = 1; wpa_supplicant_req_scan(wpa_s, wpa_s->blacklist_cleared ? 5 : 0, 0); wpa_s->blacklist_cleared = 0; return 1; } wpas_wps_clear_ap_info(wpa_s); eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL); if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && !wpa_s->wps_success) wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL); if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid && !(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) { int disabled = wpa_s->current_ssid->disabled; unsigned int freq = wpa_s->assoc_freq; struct wpa_bss *bss; struct wpa_ssid *ssid = NULL; int use_fast_assoc = 0; wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - " "try to associate with the received credential " "(freq=%u)", freq); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); if (disabled) { wpa_printf(MSG_DEBUG, "WPS: Current network is " "disabled - wait for user to enable"); return 1; } wpa_s->after_wps = 5; wpa_s->wps_freq = freq; wpa_s->normal_scans = 0; wpa_s->reassociate = 1; wpa_printf(MSG_DEBUG, "WPS: Checking whether fast association " "without a new scan can be used"); bss = wpa_supplicant_pick_network(wpa_s, &ssid); if (bss) { struct wpabuf *wps; struct wps_parse_attr attr; wps = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); if (wps && wps_parse_msg(wps, &attr) == 0 && attr.wps_state && *attr.wps_state == WPS_STATE_CONFIGURED) use_fast_assoc = 1; wpabuf_free(wps); } /* * Complete the next step from an eloop timeout to allow pending * driver events related to the disconnection to be processed * first. This makes it less likely for disconnection event to * cause problems with the following connection. */ wpa_printf(MSG_DEBUG, "WPS: Continue association from timeout"); wpas_wps_assoc_with_cred_cancel(wpa_s); eloop_register_timeout(0, 10000, wpas_wps_assoc_with_cred, wpa_s, use_fast_assoc ? (void *) 1 : (void *) 0); return 1; } if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid) { wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting " "for external credential processing"); wpas_clear_wps(wpa_s); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); return 1; } return 0; } static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, const struct wps_credential *cred) { struct wpa_driver_capa capa; struct wpa_bss *bss; const u8 *ie; struct wpa_ie_data adv; int wpa2 = 0, ccmp = 0; /* * Many existing WPS APs do not know how to negotiate WPA2 or CCMP in * case they are configured for mixed mode operation (WPA+WPA2 and * TKIP+CCMP). Try to use scan results to figure out whether the AP * actually supports stronger security and select that if the client * has support for it, too. */ if (wpa_drv_get_capa(wpa_s, &capa)) return; /* Unknown what driver supports */ if (ssid->ssid == NULL) return; bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len); if (bss == NULL) { wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS " "table - use credential as-is"); return; } wpa_printf(MSG_DEBUG, "WPS: AP found from BSS table"); ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0) { wpa2 = 1; if (adv.pairwise_cipher & WPA_CIPHER_CCMP) ccmp = 1; } else { ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0 && adv.pairwise_cipher & WPA_CIPHER_CCMP) ccmp = 1; } if (ie == NULL && (ssid->proto & WPA_PROTO_WPA) && (ssid->pairwise_cipher & WPA_CIPHER_TKIP)) { /* * TODO: This could be the initial AP configuration and the * Beacon contents could change shortly. Should request a new * scan and delay addition of the network until the updated * scan results are available. */ wpa_printf(MSG_DEBUG, "WPS: The AP did not yet advertise WPA " "support - use credential as-is"); return; } if (ccmp && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) && (ssid->pairwise_cipher & WPA_CIPHER_TKIP) && (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { wpa_printf(MSG_DEBUG, "WPS: Add CCMP into the credential " "based on scan results"); if (wpa_s->conf->ap_scan == 1) ssid->pairwise_cipher |= WPA_CIPHER_CCMP; else ssid->pairwise_cipher = WPA_CIPHER_CCMP; } if (wpa2 && !(ssid->proto & WPA_PROTO_RSN) && (ssid->proto & WPA_PROTO_WPA) && (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP)) { wpa_printf(MSG_DEBUG, "WPS: Add WPA2 into the credential " "based on scan results"); if (wpa_s->conf->ap_scan == 1) ssid->proto |= WPA_PROTO_RSN; else ssid->proto = WPA_PROTO_RSN; } } static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *new_ssid) { struct wpa_ssid *ssid, *next; for (ssid = wpa_s->conf->ssid, next = ssid ? ssid->next : NULL; ssid; ssid = next, next = ssid ? ssid->next : NULL) { /* * new_ssid has already been added to the list in * wpas_wps_add_network(), so skip it. */ if (ssid == new_ssid) continue; if (ssid->bssid_set || new_ssid->bssid_set) { if (ssid->bssid_set != new_ssid->bssid_set) continue; if (os_memcmp(ssid->bssid, new_ssid->bssid, ETH_ALEN) != 0) continue; } /* compare SSID */ if (ssid->ssid_len == 0 || ssid->ssid_len != new_ssid->ssid_len) continue; if (ssid->ssid && new_ssid->ssid) { if (os_memcmp(ssid->ssid, new_ssid->ssid, ssid->ssid_len) != 0) continue; } else if (ssid->ssid || new_ssid->ssid) continue; /* compare security parameters */ if (ssid->auth_alg != new_ssid->auth_alg || ssid->key_mgmt != new_ssid->key_mgmt || ssid->proto != new_ssid->proto || ssid->pairwise_cipher != new_ssid->pairwise_cipher || ssid->group_cipher != new_ssid->group_cipher) continue; /* Remove the duplicated older network entry. */ wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id); wpas_notify_network_removed(wpa_s, ssid); wpa_config_remove_network(wpa_s->conf, ssid->id); } } static int wpa_supplicant_wps_cred(void *ctx, const struct wps_credential *cred) { struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *ssid = wpa_s->current_ssid; u16 auth_type; #ifdef CONFIG_WPS_REG_DISABLE_OPEN int registrar = 0; #endif /* CONFIG_WPS_REG_DISABLE_OPEN */ if ((wpa_s->conf->wps_cred_processing == 1 || wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) { size_t blen = cred->cred_attr_len * 2 + 1; char *buf = os_malloc(blen); if (buf) { wpa_snprintf_hex(buf, blen, cred->cred_attr, cred->cred_attr_len); wpa_msg(wpa_s, MSG_INFO, "%s%s", WPS_EVENT_CRED_RECEIVED, buf); os_free(buf); } wpas_notify_wps_credential(wpa_s, cred); } else wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED); wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute", cred->cred_attr, cred->cred_attr_len); if (wpa_s->conf->wps_cred_processing == 1) return 0; wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len); wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x", cred->auth_type); wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type); wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx); wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", cred->key, cred->key_len); wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, MAC2STR(cred->mac_addr)); auth_type = cred->auth_type; if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) { wpa_printf(MSG_DEBUG, "WPS: Workaround - convert mixed-mode " "auth_type into WPA2PSK"); auth_type = WPS_AUTH_WPA2PSK; } if (auth_type != WPS_AUTH_OPEN && auth_type != WPS_AUTH_WPAPSK && auth_type != WPS_AUTH_WPA2PSK) { wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for " "unsupported authentication type 0x%x", auth_type); return 0; } if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) { if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) { wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with " "invalid Network Key length %lu", (unsigned long) cred->key_len); return -1; } } if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) { wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based " "on the received credential"); #ifdef CONFIG_WPS_REG_DISABLE_OPEN if (ssid->eap.identity && ssid->eap.identity_len == WSC_ID_REGISTRAR_LEN && os_memcmp(ssid->eap.identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) registrar = 1; #endif /* CONFIG_WPS_REG_DISABLE_OPEN */ os_free(ssid->eap.identity); ssid->eap.identity = NULL; ssid->eap.identity_len = 0; os_free(ssid->eap.phase1); ssid->eap.phase1 = NULL; os_free(ssid->eap.eap_methods); ssid->eap.eap_methods = NULL; if (!ssid->p2p_group) { ssid->temporary = 0; ssid->bssid_set = 0; } ssid->disabled_until.sec = 0; ssid->disabled_until.usec = 0; ssid->auth_failures = 0; } else { wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the " "received credential"); ssid = wpa_config_add_network(wpa_s->conf); if (ssid == NULL) return -1; if (wpa_s->current_ssid) { /* * Should the GO issue multiple credentials for some * reason, each credential should be marked as a * temporary P2P group similarly to the one that gets * marked as such based on the pre-configured values * used for the WPS network block. */ ssid->p2p_group = wpa_s->current_ssid->p2p_group; ssid->temporary = wpa_s->current_ssid->temporary; } wpas_notify_network_added(wpa_s, ssid); } wpa_config_set_network_defaults(ssid); os_free(ssid->ssid); ssid->ssid = os_malloc(cred->ssid_len); if (ssid->ssid) { os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len); ssid->ssid_len = cred->ssid_len; } switch (cred->encr_type) { case WPS_ENCR_NONE: break; case WPS_ENCR_TKIP: ssid->pairwise_cipher = WPA_CIPHER_TKIP; break; case WPS_ENCR_AES: ssid->pairwise_cipher = WPA_CIPHER_CCMP; break; } switch (auth_type) { case WPS_AUTH_OPEN: ssid->auth_alg = WPA_AUTH_ALG_OPEN; ssid->key_mgmt = WPA_KEY_MGMT_NONE; ssid->proto = 0; #ifdef CONFIG_WPS_REG_DISABLE_OPEN if (registrar) { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OPEN_NETWORK "id=%d - Credentials for an open " "network disabled by default - use " "'select_network %d' to enable", ssid->id, ssid->id); ssid->disabled = 1; } #endif /* CONFIG_WPS_REG_DISABLE_OPEN */ break; case WPS_AUTH_WPAPSK: ssid->auth_alg = WPA_AUTH_ALG_OPEN; ssid->key_mgmt = WPA_KEY_MGMT_PSK; ssid->proto = WPA_PROTO_WPA; break; case WPS_AUTH_WPA2PSK: ssid->auth_alg = WPA_AUTH_ALG_OPEN; ssid->key_mgmt = WPA_KEY_MGMT_PSK; ssid->proto = WPA_PROTO_RSN; break; } if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) { if (cred->key_len == 2 * PMK_LEN) { if (hexstr2bin((const char *) cred->key, ssid->psk, PMK_LEN)) { wpa_printf(MSG_ERROR, "WPS: Invalid Network " "Key"); return -1; } ssid->psk_set = 1; ssid->export_keys = 1; } else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) { os_free(ssid->passphrase); ssid->passphrase = os_malloc(cred->key_len + 1); if (ssid->passphrase == NULL) return -1; os_memcpy(ssid->passphrase, cred->key, cred->key_len); ssid->passphrase[cred->key_len] = '\0'; wpa_config_update_psk(ssid); ssid->export_keys = 1; } else { wpa_printf(MSG_ERROR, "WPS: Invalid Network Key " "length %lu", (unsigned long) cred->key_len); return -1; } } wpas_wps_security_workaround(wpa_s, ssid, cred); wpas_wps_remove_dup_network(wpa_s, ssid); #ifndef CONFIG_NO_CONFIG_WRITE if (wpa_s->conf->update_config && wpa_config_write(wpa_s->confname, wpa_s->conf)) { wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration"); return -1; } #endif /* CONFIG_NO_CONFIG_WRITE */ /* * Optimize the post-WPS scan based on the channel used during * the provisioning in case EAP-Failure is not received. */ wpa_s->after_wps = 5; wpa_s->wps_freq = wpa_s->assoc_freq; return 0; } static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s, struct wps_event_m2d *m2d) { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_M2D "dev_password_id=%d config_error=%d", m2d->dev_password_id, m2d->config_error); wpas_notify_wps_event_m2d(wpa_s, m2d); #ifdef CONFIG_P2P if (wpa_s->parent && wpa_s->parent != wpa_s) { wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_M2D "dev_password_id=%d config_error=%d", m2d->dev_password_id, m2d->config_error); } if (m2d->config_error == WPS_CFG_MULTIPLE_PBC_DETECTED) { /* * Notify P2P from eloop timeout to avoid issues with the * interface getting removed while processing a message. */ eloop_register_timeout(0, 0, wpas_p2p_pbc_overlap_cb, wpa_s, NULL); } #endif /* CONFIG_P2P */ } static void wpas_wps_clear_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; wpa_printf(MSG_DEBUG, "WPS: Clear WPS network from timeout"); wpas_clear_wps(wpa_s); } static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail) { if (fail->error_indication > 0 && fail->error_indication < NUM_WPS_EI_VALUES) { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)", fail->msg, fail->config_error, fail->error_indication, wps_ei_str(fail->error_indication)); if (wpa_s->parent && wpa_s->parent != wpa_s) wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)", fail->msg, fail->config_error, fail->error_indication, wps_ei_str(fail->error_indication)); } else { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL "msg=%d config_error=%d", fail->msg, fail->config_error); if (wpa_s->parent && wpa_s->parent != wpa_s) wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL "msg=%d config_error=%d", fail->msg, fail->config_error); } /* * Need to allow WPS processing to complete, e.g., by sending WSC_NACK. */ wpa_printf(MSG_DEBUG, "WPS: Register timeout to clear WPS network"); eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL); eloop_register_timeout(0, 100000, wpas_wps_clear_timeout, wpa_s, NULL); wpas_notify_wps_event_fail(wpa_s, fail); #ifdef CONFIG_P2P wpas_p2p_wps_failed(wpa_s, fail); #endif /* CONFIG_P2P */ } static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx); static void wpas_wps_reenable_networks(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid; int changed = 0; eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL); for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (ssid->disabled_for_connect && ssid->disabled) { ssid->disabled_for_connect = 0; ssid->disabled = 0; wpas_notify_network_enabled_changed(wpa_s, ssid); changed++; } } if (changed) { #ifndef CONFIG_NO_CONFIG_WRITE if (wpa_s->conf->update_config && wpa_config_write(wpa_s->confname, wpa_s->conf)) { wpa_printf(MSG_DEBUG, "WPS: Failed to update " "configuration"); } #endif /* CONFIG_NO_CONFIG_WRITE */ } } static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; /* Enable the networks disabled during wpas_wps_reassoc */ wpas_wps_reenable_networks(wpa_s); } static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s) { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS); wpa_s->wps_success = 1; wpas_notify_wps_event_success(wpa_s); if (wpa_s->current_ssid) wpas_clear_temp_disabled(wpa_s, wpa_s->current_ssid, 1); wpa_s->extra_blacklist_count = 0; /* * Enable the networks disabled during wpas_wps_reassoc after 10 * seconds. The 10 seconds timer is to allow the data connection to be * formed before allowing other networks to be selected. */ eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s, NULL); #ifdef CONFIG_P2P wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0); #endif /* CONFIG_P2P */ } static void wpa_supplicant_wps_event_er_ap_add(struct wpa_supplicant *wpa_s, struct wps_event_er_ap *ap) { char uuid_str[100]; char dev_type[WPS_DEV_TYPE_BUFSIZE]; uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str)); if (ap->pri_dev_type) wps_dev_type_bin2str(ap->pri_dev_type, dev_type, sizeof(dev_type)); else dev_type[0] = '\0'; wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_ADD "%s " MACSTR " pri_dev_type=%s wps_state=%d |%s|%s|%s|%s|%s|%s|", uuid_str, MAC2STR(ap->mac_addr), dev_type, ap->wps_state, ap->friendly_name ? ap->friendly_name : "", ap->manufacturer ? ap->manufacturer : "", ap->model_description ? ap->model_description : "", ap->model_name ? ap->model_name : "", ap->manufacturer_url ? ap->manufacturer_url : "", ap->model_url ? ap->model_url : ""); } static void wpa_supplicant_wps_event_er_ap_remove(struct wpa_supplicant *wpa_s, struct wps_event_er_ap *ap) { char uuid_str[100]; uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str)); wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_REMOVE "%s", uuid_str); } static void wpa_supplicant_wps_event_er_enrollee_add( struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee) { char uuid_str[100]; char dev_type[WPS_DEV_TYPE_BUFSIZE]; uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str)); if (enrollee->pri_dev_type) wps_dev_type_bin2str(enrollee->pri_dev_type, dev_type, sizeof(dev_type)); else dev_type[0] = '\0'; wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_ADD "%s " MACSTR " M1=%d config_methods=0x%x dev_passwd_id=%d pri_dev_type=%s " "|%s|%s|%s|%s|%s|", uuid_str, MAC2STR(enrollee->mac_addr), enrollee->m1_received, enrollee->config_methods, enrollee->dev_passwd_id, dev_type, enrollee->dev_name ? enrollee->dev_name : "", enrollee->manufacturer ? enrollee->manufacturer : "", enrollee->model_name ? enrollee->model_name : "", enrollee->model_number ? enrollee->model_number : "", enrollee->serial_number ? enrollee->serial_number : ""); } static void wpa_supplicant_wps_event_er_enrollee_remove( struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee) { char uuid_str[100]; uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str)); wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_REMOVE "%s " MACSTR, uuid_str, MAC2STR(enrollee->mac_addr)); } static void wpa_supplicant_wps_event_er_ap_settings( struct wpa_supplicant *wpa_s, struct wps_event_er_ap_settings *ap_settings) { char uuid_str[100]; char key_str[65]; const struct wps_credential *cred = ap_settings->cred; key_str[0] = '\0'; if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) { if (cred->key_len >= 8 && cred->key_len <= 64) { os_memcpy(key_str, cred->key, cred->key_len); key_str[cred->key_len] = '\0'; } } uuid_bin2str(ap_settings->uuid, uuid_str, sizeof(uuid_str)); /* Use wpa_msg_ctrl to avoid showing the key in debug log */ wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_SETTINGS "uuid=%s ssid=%s auth_type=0x%04x encr_type=0x%04x " "key=%s", uuid_str, wpa_ssid_txt(cred->ssid, cred->ssid_len), cred->auth_type, cred->encr_type, key_str); } static void wpa_supplicant_wps_event_er_set_sel_reg( struct wpa_supplicant *wpa_s, struct wps_event_er_set_selected_registrar *ev) { char uuid_str[100]; uuid_bin2str(ev->uuid, uuid_str, sizeof(uuid_str)); switch (ev->state) { case WPS_ER_SET_SEL_REG_START: wpa_msg(wpa_s, MSG_DEBUG, WPS_EVENT_ER_SET_SEL_REG "uuid=%s state=START sel_reg=%d dev_passwd_id=%u " "sel_reg_config_methods=0x%x", uuid_str, ev->sel_reg, ev->dev_passwd_id, ev->sel_reg_config_methods); break; case WPS_ER_SET_SEL_REG_DONE: wpa_msg(wpa_s, MSG_DEBUG, WPS_EVENT_ER_SET_SEL_REG "uuid=%s state=DONE", uuid_str); break; case WPS_ER_SET_SEL_REG_FAILED: wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_SET_SEL_REG "uuid=%s state=FAILED", uuid_str); break; } } static void wpa_supplicant_wps_event(void *ctx, enum wps_event event, union wps_event_data *data) { struct wpa_supplicant *wpa_s = ctx; switch (event) { case WPS_EV_M2D: wpa_supplicant_wps_event_m2d(wpa_s, &data->m2d); break; case WPS_EV_FAIL: wpa_supplicant_wps_event_fail(wpa_s, &data->fail); break; case WPS_EV_SUCCESS: wpa_supplicant_wps_event_success(wpa_s); break; case WPS_EV_PWD_AUTH_FAIL: #ifdef CONFIG_AP if (wpa_s->ap_iface && data->pwd_auth_fail.enrollee) wpa_supplicant_ap_pwd_auth_fail(wpa_s); #endif /* CONFIG_AP */ break; case WPS_EV_PBC_OVERLAP: break; case WPS_EV_PBC_TIMEOUT: break; case WPS_EV_PBC_ACTIVE: wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ACTIVE); break; case WPS_EV_PBC_DISABLE: wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_DISABLE); break; case WPS_EV_ER_AP_ADD: wpa_supplicant_wps_event_er_ap_add(wpa_s, &data->ap); break; case WPS_EV_ER_AP_REMOVE: wpa_supplicant_wps_event_er_ap_remove(wpa_s, &data->ap); break; case WPS_EV_ER_ENROLLEE_ADD: wpa_supplicant_wps_event_er_enrollee_add(wpa_s, &data->enrollee); break; case WPS_EV_ER_ENROLLEE_REMOVE: wpa_supplicant_wps_event_er_enrollee_remove(wpa_s, &data->enrollee); break; case WPS_EV_ER_AP_SETTINGS: wpa_supplicant_wps_event_er_ap_settings(wpa_s, &data->ap_settings); break; case WPS_EV_ER_SET_SELECTED_REGISTRAR: wpa_supplicant_wps_event_er_set_sel_reg(wpa_s, &data->set_sel_reg); break; case WPS_EV_AP_PIN_SUCCESS: break; } } static int wpa_supplicant_wps_rf_band(void *ctx) { struct wpa_supplicant *wpa_s = ctx; if (!wpa_s->current_ssid || !wpa_s->assoc_freq) return 0; return (wpa_s->assoc_freq > 2484) ? WPS_RF_50GHZ : WPS_RF_24GHZ; } enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid) { if (eap_is_wps_pbc_enrollee(&ssid->eap) || eap_is_wps_pin_enrollee(&ssid->eap)) return WPS_REQ_ENROLLEE; else return WPS_REQ_REGISTRAR; } static void wpas_clear_wps(struct wpa_supplicant *wpa_s) { int id; struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current; wpa_s->after_wps = 0; wpa_s->known_wps_freq = 0; prev_current = wpa_s->current_ssid; /* Enable the networks disabled during wpas_wps_reassoc */ wpas_wps_reenable_networks(wpa_s); eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL); /* Remove any existing WPS network from configuration */ ssid = wpa_s->conf->ssid; while (ssid) { if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { if (ssid == wpa_s->current_ssid) { wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); } id = ssid->id; remove_ssid = ssid; } else id = -1; ssid = ssid->next; if (id >= 0) { if (prev_current == remove_ssid) { wpa_sm_set_config(wpa_s->wpa, NULL); eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); } wpas_notify_network_removed(wpa_s, remove_ssid); wpa_config_remove_network(wpa_s->conf, id); } } wpas_wps_clear_ap_info(wpa_s); } static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed " "out"); wpas_clear_wps(wpa_s); } static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s, int registrar, const u8 *dev_addr, const u8 *bssid) { struct wpa_ssid *ssid; ssid = wpa_config_add_network(wpa_s->conf); if (ssid == NULL) return NULL; wpas_notify_network_added(wpa_s, ssid); wpa_config_set_network_defaults(ssid); ssid->temporary = 1; if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 || wpa_config_set(ssid, "eap", "WSC", 0) < 0 || wpa_config_set(ssid, "identity", registrar ? "\"" WSC_ID_REGISTRAR "\"" : "\"" WSC_ID_ENROLLEE "\"", 0) < 0) { wpas_notify_network_removed(wpa_s, ssid); wpa_config_remove_network(wpa_s->conf, ssid->id); return NULL; } #ifdef CONFIG_P2P if (dev_addr) os_memcpy(ssid->go_p2p_dev_addr, dev_addr, ETH_ALEN); #endif /* CONFIG_P2P */ if (bssid) { #ifndef CONFIG_P2P struct wpa_bss *bss; int count = 0; #endif /* CONFIG_P2P */ os_memcpy(ssid->bssid, bssid, ETH_ALEN); ssid->bssid_set = 1; /* * Note: With P2P, the SSID may change at the time the WPS * provisioning is started, so better not filter the AP based * on the current SSID in the scan results. */ #ifndef CONFIG_P2P dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (os_memcmp(bssid, bss->bssid, ETH_ALEN) != 0) continue; os_free(ssid->ssid); ssid->ssid = os_malloc(bss->ssid_len); if (ssid->ssid == NULL) break; os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len); ssid->ssid_len = bss->ssid_len; wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from " "scan results", ssid->ssid, ssid->ssid_len); count++; } if (count > 1) { wpa_printf(MSG_DEBUG, "WPS: More than one SSID found " "for the AP; use wildcard"); os_free(ssid->ssid); ssid->ssid = NULL; ssid->ssid_len = 0; } #endif /* CONFIG_P2P */ } return ssid; } static void wpas_wps_temp_disable(struct wpa_supplicant *wpa_s, struct wpa_ssid *selected) { struct wpa_ssid *ssid; if (wpa_s->current_ssid) wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); /* Mark all other networks disabled and trigger reassociation */ ssid = wpa_s->conf->ssid; while (ssid) { int was_disabled = ssid->disabled; ssid->disabled_for_connect = 0; /* * In case the network object corresponds to a persistent group * then do not send out network disabled signal. In addition, * do not change disabled status of persistent network objects * from 2 to 1 should we connect to another network. */ if (was_disabled != 2) { ssid->disabled = ssid != selected; if (was_disabled != ssid->disabled) { if (ssid->disabled) ssid->disabled_for_connect = 1; wpas_notify_network_enabled_changed(wpa_s, ssid); } } ssid = ssid->next; } } static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s, struct wpa_ssid *selected, const u8 *bssid, int freq) { struct wpa_bss *bss; wpa_s->after_wps = 0; wpa_s->known_wps_freq = 0; if (freq) { wpa_s->after_wps = 5; wpa_s->wps_freq = freq; } else if (bssid) { bss = wpa_bss_get_bssid_latest(wpa_s, bssid); if (bss && bss->freq > 0) { wpa_s->known_wps_freq = 1; wpa_s->wps_freq = bss->freq; } } wpas_wps_temp_disable(wpa_s, selected); wpa_s->disconnected = 0; wpa_s->reassociate = 1; wpa_s->scan_runs = 0; wpa_s->normal_scans = 0; wpa_s->wps_success = 0; wpa_s->blacklist_cleared = 0; wpa_supplicant_cancel_sched_scan(wpa_s); wpa_supplicant_req_scan(wpa_s, 0, 0); } int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, int p2p_group) { struct wpa_ssid *ssid; wpas_clear_wps(wpa_s); ssid = wpas_wps_add_network(wpa_s, 0, NULL, bssid); if (ssid == NULL) return -1; ssid->temporary = 1; ssid->p2p_group = p2p_group; #ifdef CONFIG_P2P if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) { ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1); if (ssid->ssid) { ssid->ssid_len = wpa_s->go_params->ssid_len; os_memcpy(ssid->ssid, wpa_s->go_params->ssid, ssid->ssid_len); wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP " "SSID", ssid->ssid, ssid->ssid_len); } } #endif /* CONFIG_P2P */ if (wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0) < 0) return -1; if (wpa_s->wps_fragment_size) ssid->eap.fragment_size = wpa_s->wps_fragment_size; eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, wpa_s, NULL); wpas_wps_reassoc(wpa_s, ssid, bssid, 0); return 0; } static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s, const u8 *dev_addr, const u8 *bssid, const char *pin, int p2p_group, u16 dev_pw_id, const u8 *peer_pubkey_hash, const u8 *ssid_val, size_t ssid_len, int freq) { struct wpa_ssid *ssid; char val[128 + 2 * WPS_OOB_PUBKEY_HASH_LEN]; unsigned int rpin = 0; char hash[2 * WPS_OOB_PUBKEY_HASH_LEN + 10]; wpas_clear_wps(wpa_s); if (bssid && is_zero_ether_addr(bssid)) bssid = NULL; ssid = wpas_wps_add_network(wpa_s, 0, dev_addr, bssid); if (ssid == NULL) { wpa_printf(MSG_DEBUG, "WPS: Could not add network"); return -1; } ssid->temporary = 1; ssid->p2p_group = p2p_group; if (ssid_val) { ssid->ssid = os_malloc(ssid_len); if (ssid->ssid) { os_memcpy(ssid->ssid, ssid_val, ssid_len); ssid->ssid_len = ssid_len; } } if (peer_pubkey_hash) { os_memcpy(hash, " pkhash=", 8); wpa_snprintf_hex_uppercase(hash + 8, sizeof(hash) - 8, peer_pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN); } else { hash[0] = '\0'; } #ifdef CONFIG_P2P if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) { ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1); if (ssid->ssid) { ssid->ssid_len = wpa_s->go_params->ssid_len; os_memcpy(ssid->ssid, wpa_s->go_params->ssid, ssid->ssid_len); wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP " "SSID", ssid->ssid, ssid->ssid_len); } } #endif /* CONFIG_P2P */ if (pin) os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u%s\"", pin, dev_pw_id, hash); else if (pin == NULL && dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) { os_snprintf(val, sizeof(val), "\"dev_pw_id=%u%s\"", dev_pw_id, hash); } else { rpin = wps_generate_pin(); os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"", rpin, dev_pw_id, hash); } if (wpa_config_set(ssid, "phase1", val, 0) < 0) { wpa_printf(MSG_DEBUG, "WPS: Failed to set phase1 '%s'", val); return -1; } if (wpa_s->wps_fragment_size) ssid->eap.fragment_size = wpa_s->wps_fragment_size; eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, wpa_s, NULL); wpa_s->wps_ap_iter = 1; wpas_wps_reassoc(wpa_s, ssid, bssid, freq); return rpin; } int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, const char *pin, int p2p_group, u16 dev_pw_id) { return wpas_wps_start_dev_pw(wpa_s, NULL, bssid, pin, p2p_group, dev_pw_id, NULL, NULL, 0, 0); } /* Cancel the wps pbc/pin requests */ int wpas_wps_cancel(struct wpa_supplicant *wpa_s) { #ifdef CONFIG_AP if (wpa_s->ap_iface) { wpa_printf(MSG_DEBUG, "WPS: Cancelling in AP mode"); return wpa_supplicant_ap_wps_cancel(wpa_s); } #endif /* CONFIG_AP */ if (wpa_s->wpa_state == WPA_SCANNING || wpa_s->wpa_state == WPA_DISCONNECTED) { wpa_printf(MSG_DEBUG, "WPS: Cancel operation - cancel scan"); wpa_supplicant_cancel_scan(wpa_s); wpas_clear_wps(wpa_s); } else if (wpa_s->wpa_state >= WPA_ASSOCIATED) { wpa_printf(MSG_DEBUG, "WPS: Cancel operation - " "deauthenticate"); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); wpas_clear_wps(wpa_s); } else { wpas_wps_reenable_networks(wpa_s); wpas_wps_clear_ap_info(wpa_s); if (eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL) > 0) wpas_clear_wps(wpa_s); } wpa_s->after_wps = 0; return 0; } int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid, const char *pin, struct wps_new_ap_settings *settings) { struct wpa_ssid *ssid; char val[200]; char *pos, *end; int res; if (!pin) return -1; wpas_clear_wps(wpa_s); ssid = wpas_wps_add_network(wpa_s, 1, NULL, bssid); if (ssid == NULL) return -1; ssid->temporary = 1; pos = val; end = pos + sizeof(val); res = os_snprintf(pos, end - pos, "\"pin=%s", pin); if (res < 0 || res >= end - pos) return -1; pos += res; if (settings) { res = os_snprintf(pos, end - pos, " new_ssid=%s new_auth=%s " "new_encr=%s new_key=%s", settings->ssid_hex, settings->auth, settings->encr, settings->key_hex); if (res < 0 || res >= end - pos) return -1; pos += res; } res = os_snprintf(pos, end - pos, "\""); if (res < 0 || res >= end - pos) return -1; if (wpa_config_set(ssid, "phase1", val, 0) < 0) return -1; if (wpa_s->wps_fragment_size) ssid->eap.fragment_size = wpa_s->wps_fragment_size; eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, wpa_s, NULL); wpas_wps_reassoc(wpa_s, ssid, bssid, 0); return 0; } static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *p2p_dev_addr, const u8 *psk, size_t psk_len) { if (is_zero_ether_addr(p2p_dev_addr)) { wpa_printf(MSG_DEBUG, "Received new WPA/WPA2-PSK from WPS for STA " MACSTR, MAC2STR(mac_addr)); } else { wpa_printf(MSG_DEBUG, "Received new WPA/WPA2-PSK from WPS for STA " MACSTR " P2P Device Addr " MACSTR, MAC2STR(mac_addr), MAC2STR(p2p_dev_addr)); } wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len); /* TODO */ return 0; } static void wpas_wps_pin_needed_cb(void *ctx, const u8 *uuid_e, const struct wps_device_data *dev) { char uuid[40], txt[400]; int len; char devtype[WPS_DEV_TYPE_BUFSIZE]; if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) return; wpa_printf(MSG_DEBUG, "WPS: PIN needed for UUID-E %s", uuid); len = os_snprintf(txt, sizeof(txt), "WPS-EVENT-PIN-NEEDED %s " MACSTR " [%s|%s|%s|%s|%s|%s]", uuid, MAC2STR(dev->mac_addr), dev->device_name, dev->manufacturer, dev->model_name, dev->model_number, dev->serial_number, wps_dev_type_bin2str(dev->pri_dev_type, devtype, sizeof(devtype))); if (len > 0 && len < (int) sizeof(txt)) wpa_printf(MSG_INFO, "%s", txt); } static void wpas_wps_set_sel_reg_cb(void *ctx, int sel_reg, u16 dev_passwd_id, u16 sel_reg_config_methods) { #ifdef CONFIG_WPS_ER struct wpa_supplicant *wpa_s = ctx; if (wpa_s->wps_er == NULL) return; wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar - sel_reg=%d " "dev_password_id=%u sel_reg_config_methods=0x%x", sel_reg, dev_passwd_id, sel_reg_config_methods); wps_er_set_sel_reg(wpa_s->wps_er, sel_reg, dev_passwd_id, sel_reg_config_methods); #endif /* CONFIG_WPS_ER */ } static u16 wps_fix_config_methods(u16 config_methods) { if ((config_methods & (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY | WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) { wpa_printf(MSG_INFO, "WPS: Converting display to " "virtual_display for WPS 2.0 compliance"); config_methods |= WPS_CONFIG_VIRT_DISPLAY; } if ((config_methods & (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON | WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) { wpa_printf(MSG_INFO, "WPS: Converting push_button to " "virtual_push_button for WPS 2.0 compliance"); config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON; } return config_methods; } static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s, struct wps_context *wps) { char buf[50]; const char *src; if (is_nil_uuid(wpa_s->conf->uuid)) { struct wpa_supplicant *first; first = wpa_s->global->ifaces; while (first && first->next) first = first->next; if (first && first != wpa_s) { if (wps != wpa_s->global->ifaces->wps) os_memcpy(wps->uuid, wpa_s->global->ifaces->wps->uuid, WPS_UUID_LEN); src = "from the first interface"; } else { uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid); src = "based on MAC address"; } } else { os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN); src = "based on configuration"; } uuid_bin2str(wps->uuid, buf, sizeof(buf)); wpa_dbg(wpa_s, MSG_DEBUG, "WPS: UUID %s: %s", src, buf); } static void wpas_wps_set_vendor_ext_m1(struct wpa_supplicant *wpa_s, struct wps_context *wps) { wpabuf_free(wps->dev.vendor_ext_m1); wps->dev.vendor_ext_m1 = NULL; if (wpa_s->conf->wps_vendor_ext_m1) { wps->dev.vendor_ext_m1 = wpabuf_dup(wpa_s->conf->wps_vendor_ext_m1); if (!wps->dev.vendor_ext_m1) { wpa_printf(MSG_ERROR, "WPS: Cannot " "allocate memory for vendor_ext_m1"); } } } int wpas_wps_init(struct wpa_supplicant *wpa_s) { struct wps_context *wps; struct wps_registrar_config rcfg; struct hostapd_hw_modes *modes; u16 m; wps = os_zalloc(sizeof(*wps)); if (wps == NULL) return -1; wps->cred_cb = wpa_supplicant_wps_cred; wps->event_cb = wpa_supplicant_wps_event; wps->rf_band_cb = wpa_supplicant_wps_rf_band; wps->cb_ctx = wpa_s; wps->dev.device_name = wpa_s->conf->device_name; wps->dev.manufacturer = wpa_s->conf->manufacturer; wps->dev.model_name = wpa_s->conf->model_name; wps->dev.model_number = wpa_s->conf->model_number; wps->dev.serial_number = wpa_s->conf->serial_number; wps->config_methods = wps_config_methods_str2bin(wpa_s->conf->config_methods); if ((wps->config_methods & (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) == (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) { wpa_printf(MSG_ERROR, "WPS: Both Label and Display config " "methods are not allowed at the same time"); os_free(wps); return -1; } wps->config_methods = wps_fix_config_methods(wps->config_methods); wps->dev.config_methods = wps->config_methods; os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type, WPS_DEV_TYPE_LEN); wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types; os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type, WPS_DEV_TYPE_LEN * wps->dev.num_sec_dev_types); wpas_wps_set_vendor_ext_m1(wpa_s, wps); wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version); modes = wpa_s->hw.modes; if (modes) { for (m = 0; m < wpa_s->hw.num_modes; m++) { if (modes[m].mode == HOSTAPD_MODE_IEEE80211B || modes[m].mode == HOSTAPD_MODE_IEEE80211G) wps->dev.rf_bands |= WPS_RF_24GHZ; else if (modes[m].mode == HOSTAPD_MODE_IEEE80211A) wps->dev.rf_bands |= WPS_RF_50GHZ; } } if (wps->dev.rf_bands == 0) { /* * Default to claiming support for both bands if the driver * does not provide support for fetching supported bands. */ wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ; } os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN); wpas_wps_set_uuid(wpa_s, wps); wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK; wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP; os_memset(&rcfg, 0, sizeof(rcfg)); rcfg.new_psk_cb = wpas_wps_new_psk_cb; rcfg.pin_needed_cb = wpas_wps_pin_needed_cb; rcfg.set_sel_reg_cb = wpas_wps_set_sel_reg_cb; rcfg.cb_ctx = wpa_s; wps->registrar = wps_registrar_init(wps, &rcfg); if (wps->registrar == NULL) { wpa_printf(MSG_DEBUG, "Failed to initialize WPS Registrar"); os_free(wps); return -1; } wpa_s->wps = wps; return 0; } #ifdef CONFIG_WPS_ER static void wpas_wps_nfc_clear(struct wps_context *wps) { wps->ap_nfc_dev_pw_id = 0; wpabuf_free(wps->ap_nfc_dh_pubkey); wps->ap_nfc_dh_pubkey = NULL; wpabuf_free(wps->ap_nfc_dh_privkey); wps->ap_nfc_dh_privkey = NULL; wpabuf_free(wps->ap_nfc_dev_pw); wps->ap_nfc_dev_pw = NULL; } #endif /* CONFIG_WPS_ER */ void wpas_wps_deinit(struct wpa_supplicant *wpa_s) { wpas_wps_assoc_with_cred_cancel(wpa_s); eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL); wpas_wps_clear_ap_info(wpa_s); #ifdef CONFIG_P2P eloop_cancel_timeout(wpas_p2p_pbc_overlap_cb, wpa_s, NULL); #endif /* CONFIG_P2P */ if (wpa_s->wps == NULL) return; #ifdef CONFIG_WPS_ER wps_er_deinit(wpa_s->wps_er, NULL, NULL); wpa_s->wps_er = NULL; wpas_wps_nfc_clear(wpa_s->wps); #endif /* CONFIG_WPS_ER */ wps_registrar_deinit(wpa_s->wps->registrar); wpabuf_free(wpa_s->wps->dh_pubkey); wpabuf_free(wpa_s->wps->dh_privkey); wpabuf_free(wpa_s->wps->dev.vendor_ext_m1); os_free(wpa_s->wps->network_key); os_free(wpa_s->wps); wpa_s->wps = NULL; } int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_bss *bss) { struct wpabuf *wps_ie; if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) return -1; wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); if (eap_is_wps_pbc_enrollee(&ssid->eap)) { if (!wps_ie) { wpa_printf(MSG_DEBUG, " skip - non-WPS AP"); return 0; } if (!wps_is_selected_pbc_registrar(wps_ie)) { wpa_printf(MSG_DEBUG, " skip - WPS AP " "without active PBC Registrar"); wpabuf_free(wps_ie); return 0; } /* TODO: overlap detection */ wpa_printf(MSG_DEBUG, " selected based on WPS IE " "(Active PBC)"); wpabuf_free(wps_ie); return 1; } if (eap_is_wps_pin_enrollee(&ssid->eap)) { if (!wps_ie) { wpa_printf(MSG_DEBUG, " skip - non-WPS AP"); return 0; } /* * Start with WPS APs that advertise our address as an * authorized MAC (v2.0) or active PIN Registrar (v1.0) and * allow any WPS AP after couple of scans since some APs do not * set Selected Registrar attribute properly when using * external Registrar. */ if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) { if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) { wpa_printf(MSG_DEBUG, " skip - WPS AP " "without active PIN Registrar"); wpabuf_free(wps_ie); return 0; } wpa_printf(MSG_DEBUG, " selected based on WPS IE"); } else { wpa_printf(MSG_DEBUG, " selected based on WPS IE " "(Authorized MAC or Active PIN)"); } wpabuf_free(wps_ie); return 1; } if (wps_ie) { wpa_printf(MSG_DEBUG, " selected based on WPS IE"); wpabuf_free(wps_ie); return 1; } return -1; } int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_bss *bss) { struct wpabuf *wps_ie = NULL; int ret = 0; if (eap_is_wps_pbc_enrollee(&ssid->eap)) { wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) { /* allow wildcard SSID for WPS PBC */ ret = 1; } } else if (eap_is_wps_pin_enrollee(&ssid->eap)) { wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); if (wps_ie && (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1) || wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) { /* allow wildcard SSID for WPS PIN */ ret = 1; } } if (!ret && ssid->bssid_set && os_memcmp(ssid->bssid, bss->bssid, ETH_ALEN) == 0) { /* allow wildcard SSID due to hardcoded BSSID match */ ret = 1; } #ifdef CONFIG_WPS_STRICT if (wps_ie) { if (wps_validate_beacon_probe_resp(wps_ie, bss->beacon_ie_len > 0, bss->bssid) < 0) ret = 0; if (bss->beacon_ie_len) { struct wpabuf *bcn_wps; bcn_wps = wpa_bss_get_vendor_ie_multi_beacon( bss, WPS_IE_VENDOR_TYPE); if (bcn_wps == NULL) { wpa_printf(MSG_DEBUG, "WPS: Mandatory WPS IE " "missing from AP Beacon"); ret = 0; } else { if (wps_validate_beacon(wps_ie) < 0) ret = 0; wpabuf_free(bcn_wps); } } } #endif /* CONFIG_WPS_STRICT */ wpabuf_free(wps_ie); return ret; } int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, struct wpa_bss *selected, struct wpa_ssid *ssid) { const u8 *sel_uuid, *uuid; struct wpabuf *wps_ie; int ret = 0; struct wpa_bss *bss; if (!eap_is_wps_pbc_enrollee(&ssid->eap)) return 0; wpa_printf(MSG_DEBUG, "WPS: Check whether PBC session overlap is " "present in scan results; selected BSSID " MACSTR, MAC2STR(selected->bssid)); /* Make sure that only one AP is in active PBC mode */ wps_ie = wpa_bss_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE); if (wps_ie) { sel_uuid = wps_get_uuid_e(wps_ie); wpa_hexdump(MSG_DEBUG, "WPS: UUID of the selected BSS", sel_uuid, UUID_LEN); } else { wpa_printf(MSG_DEBUG, "WPS: Selected BSS does not include " "WPS IE?!"); sel_uuid = NULL; } dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { struct wpabuf *ie; if (bss == selected) continue; ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); if (!ie) continue; if (!wps_is_selected_pbc_registrar(ie)) { wpabuf_free(ie); continue; } wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: " MACSTR, MAC2STR(bss->bssid)); uuid = wps_get_uuid_e(ie); wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS", uuid, UUID_LEN); if (sel_uuid == NULL || uuid == NULL || os_memcmp(sel_uuid, uuid, UUID_LEN) != 0) { ret = 1; /* PBC overlap */ wpa_msg(wpa_s, MSG_INFO, "WPS: PBC overlap detected: " MACSTR " and " MACSTR, MAC2STR(selected->bssid), MAC2STR(bss->bssid)); wpabuf_free(ie); break; } /* TODO: verify that this is reasonable dual-band situation */ wpabuf_free(ie); } wpabuf_free(wps_ie); return ret; } void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss; unsigned int pbc = 0, auth = 0, pin = 0, wps = 0; if (wpa_s->disconnected || wpa_s->wpa_state >= WPA_ASSOCIATED) return; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { struct wpabuf *ie; ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); if (!ie) continue; if (wps_is_selected_pbc_registrar(ie)) pbc++; else if (wps_is_addr_authorized(ie, wpa_s->own_addr, 0)) auth++; else if (wps_is_selected_pin_registrar(ie)) pin++; else wps++; wpabuf_free(ie); } if (pbc) wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PBC); else if (auth) wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_AUTH); else if (pin) wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PIN); else if (wps) wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE); } int wpas_wps_searching(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid; for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && !ssid->disabled) return 1; } return 0; } int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end) { struct wpabuf *wps_ie; int ret; wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_DEV_OUI_WFA); if (wps_ie == NULL) return 0; ret = wps_attr_text(wps_ie, buf, end); wpabuf_free(wps_ie); return ret; } int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter) { #ifdef CONFIG_WPS_ER if (wpa_s->wps_er) { wps_er_refresh(wpa_s->wps_er); return 0; } wpa_s->wps_er = wps_er_init(wpa_s->wps, wpa_s->ifname, filter); if (wpa_s->wps_er == NULL) return -1; return 0; #else /* CONFIG_WPS_ER */ return 0; #endif /* CONFIG_WPS_ER */ } int wpas_wps_er_stop(struct wpa_supplicant *wpa_s) { #ifdef CONFIG_WPS_ER wps_er_deinit(wpa_s->wps_er, NULL, NULL); wpa_s->wps_er = NULL; #endif /* CONFIG_WPS_ER */ return 0; } #ifdef CONFIG_WPS_ER int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr, const char *uuid, const char *pin) { u8 u[UUID_LEN]; const u8 *use_uuid = NULL; u8 addr_buf[ETH_ALEN]; if (os_strcmp(uuid, "any") == 0) { } else if (uuid_str2bin(uuid, u) == 0) { use_uuid = u; } else if (hwaddr_aton(uuid, addr_buf) == 0) { use_uuid = wps_er_get_sta_uuid(wpa_s->wps_er, addr_buf); if (use_uuid == NULL) return -1; } else return -1; return wps_registrar_add_pin(wpa_s->wps->registrar, addr, use_uuid, (const u8 *) pin, os_strlen(pin), 300); } int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid) { u8 u[UUID_LEN], *use_uuid = NULL; u8 addr[ETH_ALEN], *use_addr = NULL; if (uuid_str2bin(uuid, u) == 0) use_uuid = u; else if (hwaddr_aton(uuid, addr) == 0) use_addr = addr; else return -1; return wps_er_pbc(wpa_s->wps_er, use_uuid, use_addr); } int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid, const char *pin) { u8 u[UUID_LEN], *use_uuid = NULL; u8 addr[ETH_ALEN], *use_addr = NULL; if (uuid_str2bin(uuid, u) == 0) use_uuid = u; else if (hwaddr_aton(uuid, addr) == 0) use_addr = addr; else return -1; return wps_er_learn(wpa_s->wps_er, use_uuid, use_addr, (const u8 *) pin, os_strlen(pin)); } static int wpas_wps_network_to_cred(struct wpa_ssid *ssid, struct wps_credential *cred) { os_memset(cred, 0, sizeof(*cred)); if (ssid->ssid_len > 32) return -1; os_memcpy(cred->ssid, ssid->ssid, ssid->ssid_len); cred->ssid_len = ssid->ssid_len; if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { cred->auth_type = (ssid->proto & WPA_PROTO_RSN) ? WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK; if (ssid->pairwise_cipher & WPA_CIPHER_CCMP) cred->encr_type = WPS_ENCR_AES; else cred->encr_type = WPS_ENCR_TKIP; if (ssid->passphrase) { cred->key_len = os_strlen(ssid->passphrase); if (cred->key_len >= 64) return -1; os_memcpy(cred->key, ssid->passphrase, cred->key_len); } else if (ssid->psk_set) { cred->key_len = 32; os_memcpy(cred->key, ssid->psk, 32); } else return -1; } else { cred->auth_type = WPS_AUTH_OPEN; cred->encr_type = WPS_ENCR_NONE; } return 0; } int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid, int id) { u8 u[UUID_LEN], *use_uuid = NULL; u8 addr[ETH_ALEN], *use_addr = NULL; struct wpa_ssid *ssid; struct wps_credential cred; if (uuid_str2bin(uuid, u) == 0) use_uuid = u; else if (hwaddr_aton(uuid, addr) == 0) use_addr = addr; else return -1; ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL || ssid->ssid == NULL) return -1; if (wpas_wps_network_to_cred(ssid, &cred) < 0) return -1; return wps_er_set_config(wpa_s->wps_er, use_uuid, use_addr, &cred); } int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid, const char *pin, struct wps_new_ap_settings *settings) { u8 u[UUID_LEN], *use_uuid = NULL; u8 addr[ETH_ALEN], *use_addr = NULL; struct wps_credential cred; size_t len; if (uuid_str2bin(uuid, u) == 0) use_uuid = u; else if (hwaddr_aton(uuid, addr) == 0) use_addr = addr; else return -1; if (settings->ssid_hex == NULL || settings->auth == NULL || settings->encr == NULL || settings->key_hex == NULL) return -1; os_memset(&cred, 0, sizeof(cred)); len = os_strlen(settings->ssid_hex); if ((len & 1) || len > 2 * sizeof(cred.ssid) || hexstr2bin(settings->ssid_hex, cred.ssid, len / 2)) return -1; cred.ssid_len = len / 2; len = os_strlen(settings->key_hex); if ((len & 1) || len > 2 * sizeof(cred.key) || hexstr2bin(settings->key_hex, cred.key, len / 2)) return -1; cred.key_len = len / 2; if (os_strcmp(settings->auth, "OPEN") == 0) cred.auth_type = WPS_AUTH_OPEN; else if (os_strcmp(settings->auth, "WPAPSK") == 0) cred.auth_type = WPS_AUTH_WPAPSK; else if (os_strcmp(settings->auth, "WPA2PSK") == 0) cred.auth_type = WPS_AUTH_WPA2PSK; else return -1; if (os_strcmp(settings->encr, "NONE") == 0) cred.encr_type = WPS_ENCR_NONE; #ifdef CONFIG_TESTING_OPTIONS else if (os_strcmp(settings->encr, "WEP") == 0) cred.encr_type = WPS_ENCR_WEP; #endif /* CONFIG_TESTING_OPTIONS */ else if (os_strcmp(settings->encr, "TKIP") == 0) cred.encr_type = WPS_ENCR_TKIP; else if (os_strcmp(settings->encr, "CCMP") == 0) cred.encr_type = WPS_ENCR_AES; else return -1; return wps_er_config(wpa_s->wps_er, use_uuid, use_addr, (const u8 *) pin, os_strlen(pin), &cred); } #ifdef CONFIG_WPS_NFC struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s, int ndef, const char *uuid) { struct wpabuf *ret; u8 u[UUID_LEN], *use_uuid = NULL; u8 addr[ETH_ALEN], *use_addr = NULL; if (!wpa_s->wps_er) return NULL; if (uuid_str2bin(uuid, u) == 0) use_uuid = u; else if (hwaddr_aton(uuid, addr) == 0) use_addr = addr; else return NULL; ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr); if (ndef && ret) { struct wpabuf *tmp; tmp = ndef_build_wifi(ret); wpabuf_free(ret); if (tmp == NULL) return NULL; ret = tmp; } return ret; } #endif /* CONFIG_WPS_NFC */ static int callbacks_pending = 0; static void wpas_wps_terminate_cb(void *ctx) { wpa_printf(MSG_DEBUG, "WPS ER: Terminated"); if (--callbacks_pending <= 0) eloop_terminate(); } #endif /* CONFIG_WPS_ER */ int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s) { #ifdef CONFIG_WPS_ER if (wpa_s->wps_er) { callbacks_pending++; wps_er_deinit(wpa_s->wps_er, wpas_wps_terminate_cb, wpa_s); wpa_s->wps_er = NULL; return 1; } #endif /* CONFIG_WPS_ER */ return 0; } void wpas_wps_update_config(struct wpa_supplicant *wpa_s) { struct wps_context *wps = wpa_s->wps; if (wps == NULL) return; if (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS) { wps->config_methods = wps_config_methods_str2bin( wpa_s->conf->config_methods); if ((wps->config_methods & (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) == (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) { wpa_printf(MSG_ERROR, "WPS: Both Label and Display " "config methods are not allowed at the " "same time"); wps->config_methods &= ~WPS_CONFIG_LABEL; } } wps->config_methods = wps_fix_config_methods(wps->config_methods); wps->dev.config_methods = wps->config_methods; if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE) os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type, WPS_DEV_TYPE_LEN); if (wpa_s->conf->changed_parameters & CFG_CHANGED_SEC_DEVICE_TYPE) { wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types; os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type, wps->dev.num_sec_dev_types * WPS_DEV_TYPE_LEN); } if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION) wpas_wps_set_vendor_ext_m1(wpa_s, wps); if (wpa_s->conf->changed_parameters & CFG_CHANGED_OS_VERSION) wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version); if (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID) wpas_wps_set_uuid(wpa_s, wps); if (wpa_s->conf->changed_parameters & (CFG_CHANGED_DEVICE_NAME | CFG_CHANGED_WPS_STRING)) { /* Update pointers to make sure they refer current values */ wps->dev.device_name = wpa_s->conf->device_name; wps->dev.manufacturer = wpa_s->conf->manufacturer; wps->dev.model_name = wpa_s->conf->model_name; wps->dev.model_number = wpa_s->conf->model_number; wps->dev.serial_number = wpa_s->conf->serial_number; } } #ifdef CONFIG_WPS_NFC #ifdef CONFIG_WPS_ER static struct wpabuf * wpas_wps_network_config_token(struct wpa_supplicant *wpa_s, int ndef, struct wpa_ssid *ssid) { struct wpabuf *ret; struct wps_credential cred; if (wpas_wps_network_to_cred(ssid, &cred) < 0) return NULL; ret = wps_er_config_token_from_cred(wpa_s->wps, &cred); if (ndef && ret) { struct wpabuf *tmp; tmp = ndef_build_wifi(ret); wpabuf_free(ret); if (tmp == NULL) return NULL; ret = tmp; } return ret; } #endif /* CONFIG_WPS_ER */ struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s, int ndef, const char *id_str) { #ifdef CONFIG_WPS_ER if (id_str) { int id; char *end = NULL; struct wpa_ssid *ssid; id = strtol(id_str, &end, 10); if (end && *end) return NULL; ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL) return NULL; return wpas_wps_network_config_token(wpa_s, ndef, ssid); } #endif /* CONFIG_WPS_ER */ #ifdef CONFIG_AP if (wpa_s->ap_iface) return wpas_ap_wps_nfc_config_token(wpa_s, ndef); #endif /* CONFIG_AP */ return NULL; } struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef) { if (wpa_s->conf->wps_nfc_pw_from_config) { return wps_nfc_token_build(ndef, wpa_s->conf->wps_nfc_dev_pw_id, wpa_s->conf->wps_nfc_dh_pubkey, wpa_s->conf->wps_nfc_dev_pw); } return wps_nfc_token_gen(ndef, &wpa_s->conf->wps_nfc_dev_pw_id, &wpa_s->conf->wps_nfc_dh_pubkey, &wpa_s->conf->wps_nfc_dh_privkey, &wpa_s->conf->wps_nfc_dev_pw); } int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *go_dev_addr, const u8 *bssid, const struct wpabuf *dev_pw, u16 dev_pw_id, int p2p_group, const u8 *peer_pubkey_hash, const u8 *ssid, size_t ssid_len, int freq) { struct wps_context *wps = wpa_s->wps; char pw[32 * 2 + 1]; if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && dev_pw == NULL) { dev_pw = wpa_s->conf->wps_nfc_dev_pw; dev_pw_id = wpa_s->conf->wps_nfc_dev_pw_id; } if (wpa_s->conf->wps_nfc_dh_pubkey == NULL || wpa_s->conf->wps_nfc_dh_privkey == NULL) { wpa_printf(MSG_DEBUG, "WPS: Missing DH params - " "cannot start NFC-triggered connection"); return -1; } if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && dev_pw == NULL) { wpa_printf(MSG_DEBUG, "WPS: Missing Device Password (id=%u) - " "cannot start NFC-triggered connection", dev_pw_id); return -1; } dh5_free(wps->dh_ctx); wpabuf_free(wps->dh_pubkey); wpabuf_free(wps->dh_privkey); wps->dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey); wps->dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey); if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) { wps->dh_ctx = NULL; wpabuf_free(wps->dh_pubkey); wps->dh_pubkey = NULL; wpabuf_free(wps->dh_privkey); wps->dh_privkey = NULL; wpa_printf(MSG_DEBUG, "WPS: Failed to get DH priv/pub key"); return -1; } wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey); if (wps->dh_ctx == NULL) { wpabuf_free(wps->dh_pubkey); wps->dh_pubkey = NULL; wpabuf_free(wps->dh_privkey); wps->dh_privkey = NULL; wpa_printf(MSG_DEBUG, "WPS: Failed to initialize DH context"); return -1; } if (dev_pw) { wpa_snprintf_hex_uppercase(pw, sizeof(pw), wpabuf_head(dev_pw), wpabuf_len(dev_pw)); } return wpas_wps_start_dev_pw(wpa_s, go_dev_addr, bssid, dev_pw ? pw : NULL, p2p_group, dev_pw_id, peer_pubkey_hash, ssid, ssid_len, freq); } static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s, struct wps_parse_attr *attr) { /* * Disable existing networks temporarily to allow the newly learned * credential to be preferred. Enable the temporarily disabled networks * after 10 seconds. */ wpas_wps_temp_disable(wpa_s, NULL); eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s, NULL); if (wps_oob_use_cred(wpa_s->wps, attr) < 0) return -1; if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) return 0; if (attr->ap_channel) { u16 chan = WPA_GET_BE16(attr->ap_channel); int freq = 0; if (chan >= 1 && chan <= 13) freq = 2407 + 5 * chan; else if (chan == 14) freq = 2484; else if (chan >= 30) freq = 5000 + 5 * chan; if (freq) { wpa_printf(MSG_DEBUG, "WPS: Credential container indicated AP channel %u -> %u MHz", chan, freq); wpa_s->after_wps = 5; wpa_s->wps_freq = freq; } } wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network " "based on the received credential added"); wpa_s->normal_scans = 0; wpa_supplicant_reinit_autoscan(wpa_s); wpa_s->disconnected = 0; wpa_s->reassociate = 1; wpa_supplicant_cancel_sched_scan(wpa_s); wpa_supplicant_req_scan(wpa_s, 0, 0); return 0; } #ifdef CONFIG_WPS_ER static int wpas_wps_add_nfc_password_token(struct wpa_supplicant *wpa_s, struct wps_parse_attr *attr) { return wps_registrar_add_nfc_password_token( wpa_s->wps->registrar, attr->oob_dev_password, attr->oob_dev_password_len); } #endif /* CONFIG_WPS_ER */ static int wpas_wps_nfc_tag_process(struct wpa_supplicant *wpa_s, const struct wpabuf *wps) { struct wps_parse_attr attr; wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps); if (wps_parse_msg(wps, &attr)) { wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag"); return -1; } if (attr.num_cred) return wpas_wps_use_cred(wpa_s, &attr); #ifdef CONFIG_WPS_ER if (attr.oob_dev_password) return wpas_wps_add_nfc_password_token(wpa_s, &attr); #endif /* CONFIG_WPS_ER */ wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag"); return -1; } int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s, const struct wpabuf *data, int forced_freq) { const struct wpabuf *wps = data; struct wpabuf *tmp = NULL; int ret; if (wpabuf_len(data) < 4) return -1; if (*wpabuf_head_u8(data) != 0x10) { /* Assume this contains full NDEF record */ tmp = ndef_parse_wifi(data); if (tmp == NULL) { #ifdef CONFIG_P2P tmp = ndef_parse_p2p(data); if (tmp) { ret = wpas_p2p_nfc_tag_process(wpa_s, tmp, forced_freq); wpabuf_free(tmp); return ret; } #endif /* CONFIG_P2P */ wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF"); return -1; } wps = tmp; } ret = wpas_wps_nfc_tag_process(wpa_s, wps); wpabuf_free(tmp); return ret; } struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s, int ndef) { struct wpabuf *ret; if (wpa_s->conf->wps_nfc_dh_pubkey == NULL && wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey, &wpa_s->conf->wps_nfc_dh_privkey) < 0) return NULL; ret = wps_build_nfc_handover_req(wpa_s->wps, wpa_s->conf->wps_nfc_dh_pubkey); if (ndef && ret) { struct wpabuf *tmp; tmp = ndef_build_wifi(ret); wpabuf_free(ret); if (tmp == NULL) return NULL; ret = tmp; } return ret; } #ifdef CONFIG_WPS_NFC static struct wpabuf * wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef, const char *uuid) { #ifdef CONFIG_WPS_ER struct wpabuf *ret; u8 u[UUID_LEN], *use_uuid = NULL; u8 addr[ETH_ALEN], *use_addr = NULL; struct wps_context *wps = wpa_s->wps; if (wps == NULL) return NULL; if (uuid == NULL) return NULL; if (uuid_str2bin(uuid, u) == 0) use_uuid = u; else if (hwaddr_aton(uuid, addr) == 0) use_addr = addr; else return NULL; if (wpa_s->conf->wps_nfc_dh_pubkey == NULL) { if (wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey, &wpa_s->conf->wps_nfc_dh_privkey) < 0) return NULL; } wpas_wps_nfc_clear(wps); wps->ap_nfc_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER; wps->ap_nfc_dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey); wps->ap_nfc_dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey); if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey) { wpas_wps_nfc_clear(wps); return NULL; } ret = wps_er_nfc_handover_sel(wpa_s->wps_er, wpa_s->wps, use_uuid, use_addr, wpa_s->conf->wps_nfc_dh_pubkey); if (ndef && ret) { struct wpabuf *tmp; tmp = ndef_build_wifi(ret); wpabuf_free(ret); if (tmp == NULL) return NULL; ret = tmp; } return ret; #else /* CONFIG_WPS_ER */ return NULL; #endif /* CONFIG_WPS_ER */ } #endif /* CONFIG_WPS_NFC */ struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef, int cr, const char *uuid) { struct wpabuf *ret; if (!cr) return NULL; ret = wpas_ap_wps_nfc_handover_sel(wpa_s, ndef); if (ret) return ret; return wpas_wps_er_nfc_handover_sel(wpa_s, ndef, uuid); } static int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s, const struct wpabuf *data) { struct wpabuf *wps; int ret = -1; u16 wsc_len; const u8 *pos; struct wpabuf msg; struct wps_parse_attr attr; u16 dev_pw_id; const u8 *bssid = NULL; int freq = 0; wps = ndef_parse_wifi(data); if (wps == NULL) return -1; wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc " "payload from NFC connection handover"); wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps); if (wpabuf_len(wps) < 2) { wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Select " "Message"); goto out; } pos = wpabuf_head(wps); wsc_len = WPA_GET_BE16(pos); if (wsc_len > wpabuf_len(wps) - 2) { wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) " "in Wi-Fi Handover Select Message", wsc_len); goto out; } pos += 2; wpa_hexdump(MSG_DEBUG, "WPS: WSC attributes in Wi-Fi Handover Select Message", pos, wsc_len); if (wsc_len < wpabuf_len(wps) - 2) { wpa_hexdump(MSG_DEBUG, "WPS: Ignore extra data after WSC attributes", pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len); } wpabuf_set(&msg, pos, wsc_len); ret = wps_parse_msg(&msg, &attr); if (ret < 0) { wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in " "Wi-Fi Handover Select Message"); goto out; } if (attr.oob_dev_password == NULL || attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) { wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password " "included in Wi-Fi Handover Select Message"); ret = -1; goto out; } if (attr.ssid == NULL) { wpa_printf(MSG_DEBUG, "WPS: No SSID included in Wi-Fi Handover " "Select Message"); ret = -1; goto out; } wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", attr.ssid, attr.ssid_len); if (attr.mac_addr) { bssid = attr.mac_addr; wpa_printf(MSG_DEBUG, "WPS: MAC Address (BSSID): " MACSTR, MAC2STR(bssid)); } if (attr.rf_bands) wpa_printf(MSG_DEBUG, "WPS: RF Bands: %d", *attr.rf_bands); if (attr.ap_channel) { u16 chan = WPA_GET_BE16(attr.ap_channel); wpa_printf(MSG_DEBUG, "WPS: AP Channel: %d", chan); if (chan >= 1 && chan <= 13 && (attr.rf_bands == NULL || *attr.rf_bands & WPS_RF_24GHZ)) freq = 2407 + 5 * chan; else if (chan == 14 && (attr.rf_bands == NULL || *attr.rf_bands & WPS_RF_24GHZ)) freq = 2484; else if (chan >= 30 && (attr.rf_bands == NULL || *attr.rf_bands & WPS_RF_50GHZ)) freq = 5000 + 5 * chan; if (freq) { wpa_printf(MSG_DEBUG, "WPS: AP indicated channel %u -> %u MHz", chan, freq); } } wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password", attr.oob_dev_password, attr.oob_dev_password_len); dev_pw_id = WPA_GET_BE16(attr.oob_dev_password + WPS_OOB_PUBKEY_HASH_LEN); if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) { wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID " "%u in Wi-Fi Handover Select Message", dev_pw_id); ret = -1; goto out; } wpa_hexdump(MSG_DEBUG, "WPS: AP Public Key hash", attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN); ret = wpas_wps_start_nfc(wpa_s, NULL, bssid, NULL, dev_pw_id, 0, attr.oob_dev_password, attr.ssid, attr.ssid_len, freq); out: wpabuf_free(wps); return ret; } int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s, const struct wpabuf *req, const struct wpabuf *sel) { wpa_printf(MSG_DEBUG, "NFC: WPS connection handover reported"); wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in request", req); wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in select", sel); return wpas_wps_nfc_rx_handover_sel(wpa_s, sel); } int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s, const struct wpabuf *req, const struct wpabuf *sel) { struct wpabuf *wps; int ret = -1; u16 wsc_len; const u8 *pos; struct wpabuf msg; struct wps_parse_attr attr; u16 dev_pw_id; /* * Enrollee/station is always initiator of the NFC connection handover, * so use the request message here to find Enrollee public key hash. */ wps = ndef_parse_wifi(req); if (wps == NULL) return -1; wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc " "payload from NFC connection handover"); wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps); if (wpabuf_len(wps) < 2) { wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request " "Message"); goto out; } pos = wpabuf_head(wps); wsc_len = WPA_GET_BE16(pos); if (wsc_len > wpabuf_len(wps) - 2) { wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) " "in rt Wi-Fi Handover Request Message", wsc_len); goto out; } pos += 2; wpa_hexdump(MSG_DEBUG, "WPS: WSC attributes in Wi-Fi Handover Request Message", pos, wsc_len); if (wsc_len < wpabuf_len(wps) - 2) { wpa_hexdump(MSG_DEBUG, "WPS: Ignore extra data after WSC attributes", pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len); } wpabuf_set(&msg, pos, wsc_len); ret = wps_parse_msg(&msg, &attr); if (ret < 0) { wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in " "Wi-Fi Handover Request Message"); goto out; } if (attr.oob_dev_password == NULL || attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) { wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password " "included in Wi-Fi Handover Request Message"); ret = -1; goto out; } if (attr.uuid_e == NULL) { wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi " "Handover Request Message"); ret = -1; goto out; } wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN); wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password", attr.oob_dev_password, attr.oob_dev_password_len); dev_pw_id = WPA_GET_BE16(attr.oob_dev_password + WPS_OOB_PUBKEY_HASH_LEN); if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) { wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID " "%u in Wi-Fi Handover Request Message", dev_pw_id); ret = -1; goto out; } wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash", attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN); ret = wps_registrar_add_nfc_pw_token(wpa_s->wps->registrar, attr.oob_dev_password, DEV_PW_NFC_CONNECTION_HANDOVER, NULL, 0, 1); out: wpabuf_free(wps); return ret; } #endif /* CONFIG_WPS_NFC */ static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s) { size_t i; struct os_reltime now; if (wpa_debug_level > MSG_DEBUG) return; if (wpa_s->wps_ap == NULL) return; os_get_reltime(&now); for (i = 0; i < wpa_s->num_wps_ap; i++) { struct wps_ap_info *ap = &wpa_s->wps_ap[i]; struct wpa_blacklist *e = wpa_blacklist_get(wpa_s, ap->bssid); wpa_printf(MSG_DEBUG, "WPS: AP[%d] " MACSTR " type=%d " "tries=%d last_attempt=%d sec ago blacklist=%d", (int) i, MAC2STR(ap->bssid), ap->type, ap->tries, ap->last_attempt.sec > 0 ? (int) now.sec - (int) ap->last_attempt.sec : -1, e ? e->count : 0); } } static struct wps_ap_info * wpas_wps_get_ap_info(struct wpa_supplicant *wpa_s, const u8 *bssid) { size_t i; if (wpa_s->wps_ap == NULL) return NULL; for (i = 0; i < wpa_s->num_wps_ap; i++) { struct wps_ap_info *ap = &wpa_s->wps_ap[i]; if (os_memcmp(ap->bssid, bssid, ETH_ALEN) == 0) return ap; } return NULL; } static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res) { struct wpabuf *wps; enum wps_ap_info_type type; struct wps_ap_info *ap; int r; if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL) return; wps = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE); if (wps == NULL) return; r = wps_is_addr_authorized(wps, wpa_s->own_addr, 1); if (r == 2) type = WPS_AP_SEL_REG_OUR; else if (r == 1) type = WPS_AP_SEL_REG; else type = WPS_AP_NOT_SEL_REG; wpabuf_free(wps); ap = wpas_wps_get_ap_info(wpa_s, res->bssid); if (ap) { if (ap->type != type) { wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " changed type %d -> %d", MAC2STR(res->bssid), ap->type, type); ap->type = type; if (type != WPS_AP_NOT_SEL_REG) wpa_blacklist_del(wpa_s, ap->bssid); } return; } ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1, sizeof(struct wps_ap_info)); if (ap == NULL) return; wpa_s->wps_ap = ap; ap = &wpa_s->wps_ap[wpa_s->num_wps_ap]; wpa_s->num_wps_ap++; os_memset(ap, 0, sizeof(*ap)); os_memcpy(ap->bssid, res->bssid, ETH_ALEN); ap->type = type; wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added", MAC2STR(ap->bssid), ap->type); } void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { size_t i; for (i = 0; i < scan_res->num; i++) wpas_wps_update_ap_info_bss(wpa_s, scan_res->res[i]); wpas_wps_dump_ap_info(wpa_s); } void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid) { struct wps_ap_info *ap; wpa_s->after_wps = 0; if (!wpa_s->wps_ap_iter) return; ap = wpas_wps_get_ap_info(wpa_s, bssid); if (ap == NULL) return; ap->tries++; os_get_reltime(&ap->last_attempt); } wpa_supplicant-2.2/wpa_supplicant/eap_register.c0000664000175000017500000001206512343617166020071 0ustar jmjm/* * EAP method registration * Copyright (c) 2004-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 "eap_peer/eap_methods.h" #include "eap_server/eap_methods.h" #include "wpa_supplicant_i.h" /** * eap_register_methods - Register statically linked EAP methods * Returns: 0 on success, -1 or -2 on failure * * This function is called at program initialization to register all EAP * methods that were linked in statically. */ int eap_register_methods(void) { int ret = 0; #ifdef EAP_MD5 if (ret == 0) ret = eap_peer_md5_register(); #endif /* EAP_MD5 */ #ifdef EAP_TLS if (ret == 0) ret = eap_peer_tls_register(); #endif /* EAP_TLS */ #ifdef EAP_UNAUTH_TLS if (ret == 0) ret = eap_peer_unauth_tls_register(); #endif /* EAP_UNAUTH_TLS */ #ifdef EAP_TLS #ifdef CONFIG_HS20 if (ret == 0) ret = eap_peer_wfa_unauth_tls_register(); #endif /* CONFIG_HS20 */ #endif /* EAP_TLS */ #ifdef EAP_MSCHAPv2 if (ret == 0) ret = eap_peer_mschapv2_register(); #endif /* EAP_MSCHAPv2 */ #ifdef EAP_PEAP if (ret == 0) ret = eap_peer_peap_register(); #endif /* EAP_PEAP */ #ifdef EAP_TTLS if (ret == 0) ret = eap_peer_ttls_register(); #endif /* EAP_TTLS */ #ifdef EAP_GTC if (ret == 0) ret = eap_peer_gtc_register(); #endif /* EAP_GTC */ #ifdef EAP_OTP if (ret == 0) ret = eap_peer_otp_register(); #endif /* EAP_OTP */ #ifdef EAP_SIM if (ret == 0) ret = eap_peer_sim_register(); #endif /* EAP_SIM */ #ifdef EAP_LEAP if (ret == 0) ret = eap_peer_leap_register(); #endif /* EAP_LEAP */ #ifdef EAP_PSK if (ret == 0) ret = eap_peer_psk_register(); #endif /* EAP_PSK */ #ifdef EAP_AKA if (ret == 0) ret = eap_peer_aka_register(); #endif /* EAP_AKA */ #ifdef EAP_AKA_PRIME if (ret == 0) ret = eap_peer_aka_prime_register(); #endif /* EAP_AKA_PRIME */ #ifdef EAP_FAST if (ret == 0) ret = eap_peer_fast_register(); #endif /* EAP_FAST */ #ifdef EAP_PAX if (ret == 0) ret = eap_peer_pax_register(); #endif /* EAP_PAX */ #ifdef EAP_SAKE if (ret == 0) ret = eap_peer_sake_register(); #endif /* EAP_SAKE */ #ifdef EAP_GPSK if (ret == 0) ret = eap_peer_gpsk_register(); #endif /* EAP_GPSK */ #ifdef EAP_WSC if (ret == 0) ret = eap_peer_wsc_register(); #endif /* EAP_WSC */ #ifdef EAP_IKEV2 if (ret == 0) ret = eap_peer_ikev2_register(); #endif /* EAP_IKEV2 */ #ifdef EAP_VENDOR_TEST if (ret == 0) ret = eap_peer_vendor_test_register(); #endif /* EAP_VENDOR_TEST */ #ifdef EAP_TNC if (ret == 0) ret = eap_peer_tnc_register(); #endif /* EAP_TNC */ #ifdef EAP_PWD if (ret == 0) ret = eap_peer_pwd_register(); #endif /* EAP_PWD */ #ifdef EAP_EKE if (ret == 0) ret = eap_peer_eke_register(); #endif /* EAP_EKE */ #ifdef EAP_SERVER_IDENTITY if (ret == 0) ret = eap_server_identity_register(); #endif /* EAP_SERVER_IDENTITY */ #ifdef EAP_SERVER_MD5 if (ret == 0) ret = eap_server_md5_register(); #endif /* EAP_SERVER_MD5 */ #ifdef EAP_SERVER_TLS if (ret == 0) ret = eap_server_tls_register(); #endif /* EAP_SERVER_TLS */ #ifdef EAP_SERVER_UNAUTH_TLS if (ret == 0) ret = eap_server_unauth_tls_register(); #endif /* EAP_SERVER_UNAUTH_TLS */ #ifdef EAP_SERVER_MSCHAPV2 if (ret == 0) ret = eap_server_mschapv2_register(); #endif /* EAP_SERVER_MSCHAPV2 */ #ifdef EAP_SERVER_PEAP if (ret == 0) ret = eap_server_peap_register(); #endif /* EAP_SERVER_PEAP */ #ifdef EAP_SERVER_TLV if (ret == 0) ret = eap_server_tlv_register(); #endif /* EAP_SERVER_TLV */ #ifdef EAP_SERVER_GTC if (ret == 0) ret = eap_server_gtc_register(); #endif /* EAP_SERVER_GTC */ #ifdef EAP_SERVER_TTLS if (ret == 0) ret = eap_server_ttls_register(); #endif /* EAP_SERVER_TTLS */ #ifdef EAP_SERVER_SIM if (ret == 0) ret = eap_server_sim_register(); #endif /* EAP_SERVER_SIM */ #ifdef EAP_SERVER_AKA if (ret == 0) ret = eap_server_aka_register(); #endif /* EAP_SERVER_AKA */ #ifdef EAP_SERVER_AKA_PRIME if (ret == 0) ret = eap_server_aka_prime_register(); #endif /* EAP_SERVER_AKA_PRIME */ #ifdef EAP_SERVER_PAX if (ret == 0) ret = eap_server_pax_register(); #endif /* EAP_SERVER_PAX */ #ifdef EAP_SERVER_PSK if (ret == 0) ret = eap_server_psk_register(); #endif /* EAP_SERVER_PSK */ #ifdef EAP_SERVER_SAKE if (ret == 0) ret = eap_server_sake_register(); #endif /* EAP_SERVER_SAKE */ #ifdef EAP_SERVER_GPSK if (ret == 0) ret = eap_server_gpsk_register(); #endif /* EAP_SERVER_GPSK */ #ifdef EAP_SERVER_VENDOR_TEST if (ret == 0) ret = eap_server_vendor_test_register(); #endif /* EAP_SERVER_VENDOR_TEST */ #ifdef EAP_SERVER_FAST if (ret == 0) ret = eap_server_fast_register(); #endif /* EAP_SERVER_FAST */ #ifdef EAP_SERVER_WSC if (ret == 0) ret = eap_server_wsc_register(); #endif /* EAP_SERVER_WSC */ #ifdef EAP_SERVER_IKEV2 if (ret == 0) ret = eap_server_ikev2_register(); #endif /* EAP_SERVER_IKEV2 */ #ifdef EAP_SERVER_TNC if (ret == 0) ret = eap_server_tnc_register(); #endif /* EAP_SERVER_TNC */ #ifdef EAP_SERVER_PWD if (ret == 0) ret = eap_server_pwd_register(); #endif /* EAP_SERVER_PWD */ return ret; } wpa_supplicant-2.2/wpa_supplicant/config.c0000664000175000017500000027025212343617166016671 0ustar jmjm/* * WPA Supplicant / Configuration parser and common functions * Copyright (c) 2003-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 "utils/uuid.h" #include "utils/ip_addr.h" #include "crypto/sha1.h" #include "rsn_supp/wpa.h" #include "eap_peer/eap.h" #include "p2p/p2p.h" #include "config.h" #if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE) #define NO_CONFIG_WRITE #endif /* * Structure for network configuration parsing. This data is used to implement * a generic parser for each network block variable. The table of configuration * variables is defined below in this file (ssid_fields[]). */ struct parse_data { /* Configuration variable name */ char *name; /* Parser function for this variable */ int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value); #ifndef NO_CONFIG_WRITE /* Writer function (i.e., to get the variable in text format from * internal presentation). */ char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid); #endif /* NO_CONFIG_WRITE */ /* Variable specific parameters for the parser. */ void *param1, *param2, *param3, *param4; /* 0 = this variable can be included in debug output and ctrl_iface * 1 = this variable contains key/private data and it must not be * included in debug output unless explicitly requested. In * addition, this variable will not be readable through the * ctrl_iface. */ int key_data; }; static int wpa_config_parse_str(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { size_t res_len, *dst_len; char **dst, *tmp; if (os_strcmp(value, "NULL") == 0) { wpa_printf(MSG_DEBUG, "Unset configuration string '%s'", data->name); tmp = NULL; res_len = 0; goto set; } tmp = wpa_config_parse_string(value, &res_len); if (tmp == NULL) { wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.", line, data->name, data->key_data ? "[KEY DATA REMOVED]" : value); return -1; } if (data->key_data) { wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name, (u8 *) tmp, res_len); } else { wpa_hexdump_ascii(MSG_MSGDUMP, data->name, (u8 *) tmp, res_len); } if (data->param3 && res_len < (size_t) data->param3) { wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu " "min_len=%ld)", line, data->name, (unsigned long) res_len, (long) data->param3); os_free(tmp); return -1; } if (data->param4 && res_len > (size_t) data->param4) { wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu " "max_len=%ld)", line, data->name, (unsigned long) res_len, (long) data->param4); os_free(tmp); return -1; } set: dst = (char **) (((u8 *) ssid) + (long) data->param1); dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2); os_free(*dst); *dst = tmp; if (data->param2) *dst_len = res_len; return 0; } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_string_ascii(const u8 *value, size_t len) { char *buf; buf = os_malloc(len + 3); if (buf == NULL) return NULL; buf[0] = '"'; os_memcpy(buf + 1, value, len); buf[len + 1] = '"'; buf[len + 2] = '\0'; return buf; } static char * wpa_config_write_string_hex(const u8 *value, size_t len) { char *buf; buf = os_zalloc(2 * len + 1); if (buf == NULL) return NULL; wpa_snprintf_hex(buf, 2 * len + 1, value, len); return buf; } static char * wpa_config_write_string(const u8 *value, size_t len) { if (value == NULL) return NULL; if (is_hex(value, len)) return wpa_config_write_string_hex(value, len); else return wpa_config_write_string_ascii(value, len); } static char * wpa_config_write_str(const struct parse_data *data, struct wpa_ssid *ssid) { size_t len; char **src; src = (char **) (((u8 *) ssid) + (long) data->param1); if (*src == NULL) return NULL; if (data->param2) len = *((size_t *) (((u8 *) ssid) + (long) data->param2)); else len = os_strlen(*src); return wpa_config_write_string((const u8 *) *src, len); } #endif /* NO_CONFIG_WRITE */ static int wpa_config_parse_int(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { int val, *dst; char *end; dst = (int *) (((u8 *) ssid) + (long) data->param1); val = strtol(value, &end, 0); if (*end) { wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"", line, value); return -1; } *dst = val; wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst); if (data->param3 && *dst < (long) data->param3) { wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d " "min_value=%ld)", line, data->name, *dst, (long) data->param3); *dst = (long) data->param3; return -1; } if (data->param4 && *dst > (long) data->param4) { wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d " "max_value=%ld)", line, data->name, *dst, (long) data->param4); *dst = (long) data->param4; return -1; } return 0; } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_int(const struct parse_data *data, struct wpa_ssid *ssid) { int *src, res; char *value; src = (int *) (((u8 *) ssid) + (long) data->param1); value = os_malloc(20); if (value == NULL) return NULL; res = os_snprintf(value, 20, "%d", *src); if (res < 0 || res >= 20) { os_free(value); return NULL; } value[20 - 1] = '\0'; return value; } #endif /* NO_CONFIG_WRITE */ static int wpa_config_parse_bssid(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 || os_strcmp(value, "any") == 0) { ssid->bssid_set = 0; wpa_printf(MSG_MSGDUMP, "BSSID any"); return 0; } if (hwaddr_aton(value, ssid->bssid)) { wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.", line, value); return -1; } ssid->bssid_set = 1; wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN); return 0; } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_bssid(const struct parse_data *data, struct wpa_ssid *ssid) { char *value; int res; if (!ssid->bssid_set) return NULL; value = os_malloc(20); if (value == NULL) return NULL; res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid)); if (res < 0 || res >= 20) { os_free(value); return NULL; } value[20 - 1] = '\0'; return value; } #endif /* NO_CONFIG_WRITE */ static int wpa_config_parse_psk(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { #ifdef CONFIG_EXT_PASSWORD if (os_strncmp(value, "ext:", 4) == 0) { os_free(ssid->passphrase); ssid->passphrase = NULL; ssid->psk_set = 0; os_free(ssid->ext_psk); ssid->ext_psk = os_strdup(value + 4); if (ssid->ext_psk == NULL) return -1; wpa_printf(MSG_DEBUG, "PSK: External password '%s'", ssid->ext_psk); return 0; } #endif /* CONFIG_EXT_PASSWORD */ if (*value == '"') { #ifndef CONFIG_NO_PBKDF2 const char *pos; size_t len; value++; pos = os_strrchr(value, '"'); if (pos) len = pos - value; else len = os_strlen(value); if (len < 8 || len > 63) { wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase " "length %lu (expected: 8..63) '%s'.", line, (unsigned long) len, value); return -1; } wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)", (u8 *) value, len); if (ssid->passphrase && os_strlen(ssid->passphrase) == len && os_memcmp(ssid->passphrase, value, len) == 0) return 0; ssid->psk_set = 0; os_free(ssid->passphrase); ssid->passphrase = dup_binstr(value, len); if (ssid->passphrase == NULL) return -1; return 0; #else /* CONFIG_NO_PBKDF2 */ wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not " "supported.", line); return -1; #endif /* CONFIG_NO_PBKDF2 */ } if (hexstr2bin(value, ssid->psk, PMK_LEN) || value[PMK_LEN * 2] != '\0') { wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.", line, value); return -1; } os_free(ssid->passphrase); ssid->passphrase = NULL; ssid->psk_set = 1; wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN); return 0; } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_psk(const struct parse_data *data, struct wpa_ssid *ssid) { #ifdef CONFIG_EXT_PASSWORD if (ssid->ext_psk) { size_t len = 4 + os_strlen(ssid->ext_psk) + 1; char *buf = os_malloc(len); if (buf == NULL) return NULL; os_snprintf(buf, len, "ext:%s", ssid->ext_psk); return buf; } #endif /* CONFIG_EXT_PASSWORD */ if (ssid->passphrase) return wpa_config_write_string_ascii( (const u8 *) ssid->passphrase, os_strlen(ssid->passphrase)); if (ssid->psk_set) return wpa_config_write_string_hex(ssid->psk, PMK_LEN); return NULL; } #endif /* NO_CONFIG_WRITE */ static int wpa_config_parse_proto(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { int val = 0, last, errors = 0; char *start, *end, *buf; buf = os_strdup(value); if (buf == NULL) return -1; start = buf; while (*start != '\0') { while (*start == ' ' || *start == '\t') start++; if (*start == '\0') break; end = start; while (*end != ' ' && *end != '\t' && *end != '\0') end++; last = *end == '\0'; *end = '\0'; if (os_strcmp(start, "WPA") == 0) val |= WPA_PROTO_WPA; else if (os_strcmp(start, "RSN") == 0 || os_strcmp(start, "WPA2") == 0) val |= WPA_PROTO_RSN; else if (os_strcmp(start, "OSEN") == 0) val |= WPA_PROTO_OSEN; else { wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'", line, start); errors++; } if (last) break; start = end + 1; } os_free(buf); if (val == 0) { wpa_printf(MSG_ERROR, "Line %d: no proto values configured.", line); errors++; } wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val); ssid->proto = val; return errors ? -1 : 0; } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_proto(const struct parse_data *data, struct wpa_ssid *ssid) { int first = 1, ret; char *buf, *pos, *end; pos = buf = os_zalloc(20); if (buf == NULL) return NULL; end = buf + 20; if (ssid->proto & WPA_PROTO_WPA) { ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " "); if (ret < 0 || ret >= end - pos) return buf; pos += ret; first = 0; } if (ssid->proto & WPA_PROTO_RSN) { ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " "); if (ret < 0 || ret >= end - pos) return buf; pos += ret; first = 0; } if (ssid->proto & WPA_PROTO_OSEN) { ret = os_snprintf(pos, end - pos, "%sOSEN", first ? "" : " "); if (ret < 0 || ret >= end - pos) return buf; pos += ret; first = 0; } return buf; } #endif /* NO_CONFIG_WRITE */ static int wpa_config_parse_key_mgmt(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { int val = 0, last, errors = 0; char *start, *end, *buf; buf = os_strdup(value); if (buf == NULL) return -1; start = buf; while (*start != '\0') { while (*start == ' ' || *start == '\t') start++; if (*start == '\0') break; end = start; while (*end != ' ' && *end != '\t' && *end != '\0') end++; last = *end == '\0'; *end = '\0'; if (os_strcmp(start, "WPA-PSK") == 0) val |= WPA_KEY_MGMT_PSK; else if (os_strcmp(start, "WPA-EAP") == 0) val |= WPA_KEY_MGMT_IEEE8021X; else if (os_strcmp(start, "IEEE8021X") == 0) val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA; else if (os_strcmp(start, "NONE") == 0) val |= WPA_KEY_MGMT_NONE; else if (os_strcmp(start, "WPA-NONE") == 0) val |= WPA_KEY_MGMT_WPA_NONE; #ifdef CONFIG_IEEE80211R else if (os_strcmp(start, "FT-PSK") == 0) val |= WPA_KEY_MGMT_FT_PSK; else if (os_strcmp(start, "FT-EAP") == 0) val |= WPA_KEY_MGMT_FT_IEEE8021X; #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W else if (os_strcmp(start, "WPA-PSK-SHA256") == 0) val |= WPA_KEY_MGMT_PSK_SHA256; else if (os_strcmp(start, "WPA-EAP-SHA256") == 0) val |= WPA_KEY_MGMT_IEEE8021X_SHA256; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WPS else if (os_strcmp(start, "WPS") == 0) val |= WPA_KEY_MGMT_WPS; #endif /* CONFIG_WPS */ #ifdef CONFIG_SAE else if (os_strcmp(start, "SAE") == 0) val |= WPA_KEY_MGMT_SAE; else if (os_strcmp(start, "FT-SAE") == 0) val |= WPA_KEY_MGMT_FT_SAE; #endif /* CONFIG_SAE */ #ifdef CONFIG_HS20 else if (os_strcmp(start, "OSEN") == 0) val |= WPA_KEY_MGMT_OSEN; #endif /* CONFIG_HS20 */ else { wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", line, start); errors++; } if (last) break; start = end + 1; } os_free(buf); if (val == 0) { wpa_printf(MSG_ERROR, "Line %d: no key_mgmt values configured.", line); errors++; } wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val); ssid->key_mgmt = val; return errors ? -1 : 0; } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_key_mgmt(const struct parse_data *data, struct wpa_ssid *ssid) { char *buf, *pos, *end; int ret; pos = buf = os_zalloc(100); if (buf == NULL) return NULL; end = buf + 100; if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { ret = os_snprintf(pos, end - pos, "%sWPA-PSK", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return buf; } pos += ret; } if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) { ret = os_snprintf(pos, end - pos, "%sWPA-EAP", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return buf; } pos += ret; } if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) { ret = os_snprintf(pos, end - pos, "%sIEEE8021X", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return buf; } pos += ret; } if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) { ret = os_snprintf(pos, end - pos, "%sNONE", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return buf; } pos += ret; } if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) { ret = os_snprintf(pos, end - pos, "%sWPA-NONE", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return buf; } pos += ret; } #ifdef CONFIG_IEEE80211R if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) { ret = os_snprintf(pos, end - pos, "%sFT-PSK", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return buf; } pos += ret; } if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { ret = os_snprintf(pos, end - pos, "%sFT-EAP", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return buf; } pos += ret; } #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return buf; } pos += ret; } if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return buf; } pos += ret; } #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WPS if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { ret = os_snprintf(pos, end - pos, "%sWPS", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return buf; } pos += ret; } #endif /* CONFIG_WPS */ return buf; } #endif /* NO_CONFIG_WRITE */ static int wpa_config_parse_cipher(int line, const char *value) { int val = wpa_parse_cipher(value); if (val < 0) { wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.", line, value); return -1; } if (val == 0) { wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.", line); return -1; } return val; } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_cipher(int cipher) { char *buf = os_zalloc(50); if (buf == NULL) return NULL; if (wpa_write_ciphers(buf, buf + 50, cipher, " ") < 0) { os_free(buf); return NULL; } return buf; } #endif /* NO_CONFIG_WRITE */ static int wpa_config_parse_pairwise(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { int val; val = wpa_config_parse_cipher(line, value); if (val == -1) return -1; if (val & ~WPA_ALLOWED_PAIRWISE_CIPHERS) { wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher " "(0x%x).", line, val); return -1; } wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val); ssid->pairwise_cipher = val; return 0; } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_pairwise(const struct parse_data *data, struct wpa_ssid *ssid) { return wpa_config_write_cipher(ssid->pairwise_cipher); } #endif /* NO_CONFIG_WRITE */ static int wpa_config_parse_group(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { int val; val = wpa_config_parse_cipher(line, value); if (val == -1) return -1; if (val & ~WPA_ALLOWED_GROUP_CIPHERS) { wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher " "(0x%x).", line, val); return -1; } wpa_printf(MSG_MSGDUMP, "group: 0x%x", val); ssid->group_cipher = val; return 0; } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_group(const struct parse_data *data, struct wpa_ssid *ssid) { return wpa_config_write_cipher(ssid->group_cipher); } #endif /* NO_CONFIG_WRITE */ static int wpa_config_parse_auth_alg(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { int val = 0, last, errors = 0; char *start, *end, *buf; buf = os_strdup(value); if (buf == NULL) return -1; start = buf; while (*start != '\0') { while (*start == ' ' || *start == '\t') start++; if (*start == '\0') break; end = start; while (*end != ' ' && *end != '\t' && *end != '\0') end++; last = *end == '\0'; *end = '\0'; if (os_strcmp(start, "OPEN") == 0) val |= WPA_AUTH_ALG_OPEN; else if (os_strcmp(start, "SHARED") == 0) val |= WPA_AUTH_ALG_SHARED; else if (os_strcmp(start, "LEAP") == 0) val |= WPA_AUTH_ALG_LEAP; else { wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'", line, start); errors++; } if (last) break; start = end + 1; } os_free(buf); if (val == 0) { wpa_printf(MSG_ERROR, "Line %d: no auth_alg values configured.", line); errors++; } wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val); ssid->auth_alg = val; return errors ? -1 : 0; } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_auth_alg(const struct parse_data *data, struct wpa_ssid *ssid) { char *buf, *pos, *end; int ret; pos = buf = os_zalloc(30); if (buf == NULL) return NULL; end = buf + 30; if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) { ret = os_snprintf(pos, end - pos, "%sOPEN", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return buf; } pos += ret; } if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) { ret = os_snprintf(pos, end - pos, "%sSHARED", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return buf; } pos += ret; } if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) { ret = os_snprintf(pos, end - pos, "%sLEAP", pos == buf ? "" : " "); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return buf; } pos += ret; } return buf; } #endif /* NO_CONFIG_WRITE */ static int * wpa_config_parse_int_array(const char *value) { int *freqs; size_t used, len; const char *pos; used = 0; len = 10; freqs = os_calloc(len + 1, sizeof(int)); if (freqs == NULL) return NULL; pos = value; while (pos) { while (*pos == ' ') pos++; if (used == len) { int *n; size_t i; n = os_realloc_array(freqs, len * 2 + 1, sizeof(int)); if (n == NULL) { os_free(freqs); return NULL; } for (i = len; i <= len * 2; i++) n[i] = 0; freqs = n; len *= 2; } freqs[used] = atoi(pos); if (freqs[used] == 0) break; used++; pos = os_strchr(pos + 1, ' '); } return freqs; } static int wpa_config_parse_scan_freq(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { int *freqs; freqs = wpa_config_parse_int_array(value); if (freqs == NULL) return -1; if (freqs[0] == 0) { os_free(freqs); freqs = NULL; } os_free(ssid->scan_freq); ssid->scan_freq = freqs; return 0; } static int wpa_config_parse_freq_list(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { int *freqs; freqs = wpa_config_parse_int_array(value); if (freqs == NULL) return -1; if (freqs[0] == 0) { os_free(freqs); freqs = NULL; } os_free(ssid->freq_list); ssid->freq_list = freqs; return 0; } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_freqs(const struct parse_data *data, const int *freqs) { char *buf, *pos, *end; int i, ret; size_t count; if (freqs == NULL) return NULL; count = 0; for (i = 0; freqs[i]; i++) count++; pos = buf = os_zalloc(10 * count + 1); if (buf == NULL) return NULL; end = buf + 10 * count + 1; for (i = 0; freqs[i]; i++) { ret = os_snprintf(pos, end - pos, "%s%u", i == 0 ? "" : " ", freqs[i]); if (ret < 0 || ret >= end - pos) { end[-1] = '\0'; return buf; } pos += ret; } return buf; } static char * wpa_config_write_scan_freq(const struct parse_data *data, struct wpa_ssid *ssid) { return wpa_config_write_freqs(data, ssid->scan_freq); } static char * wpa_config_write_freq_list(const struct parse_data *data, struct wpa_ssid *ssid) { return wpa_config_write_freqs(data, ssid->freq_list); } #endif /* NO_CONFIG_WRITE */ #ifdef IEEE8021X_EAPOL static int wpa_config_parse_eap(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { int last, errors = 0; char *start, *end, *buf; struct eap_method_type *methods = NULL, *tmp; size_t num_methods = 0; buf = os_strdup(value); if (buf == NULL) return -1; start = buf; while (*start != '\0') { while (*start == ' ' || *start == '\t') start++; if (*start == '\0') break; end = start; while (*end != ' ' && *end != '\t' && *end != '\0') end++; last = *end == '\0'; *end = '\0'; tmp = methods; methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods)); if (methods == NULL) { os_free(tmp); os_free(buf); return -1; } methods[num_methods].method = eap_peer_get_type( start, &methods[num_methods].vendor); if (methods[num_methods].vendor == EAP_VENDOR_IETF && methods[num_methods].method == EAP_TYPE_NONE) { wpa_printf(MSG_ERROR, "Line %d: unknown EAP method " "'%s'", line, start); wpa_printf(MSG_ERROR, "You may need to add support for" " this EAP method during wpa_supplicant\n" "build time configuration.\n" "See README for more information."); errors++; } else if (methods[num_methods].vendor == EAP_VENDOR_IETF && methods[num_methods].method == EAP_TYPE_LEAP) ssid->leap++; else ssid->non_leap++; num_methods++; if (last) break; start = end + 1; } os_free(buf); tmp = methods; methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods)); if (methods == NULL) { os_free(tmp); return -1; } methods[num_methods].vendor = EAP_VENDOR_IETF; methods[num_methods].method = EAP_TYPE_NONE; num_methods++; wpa_hexdump(MSG_MSGDUMP, "eap methods", (u8 *) methods, num_methods * sizeof(*methods)); os_free(ssid->eap.eap_methods); ssid->eap.eap_methods = methods; return errors ? -1 : 0; } static char * wpa_config_write_eap(const struct parse_data *data, struct wpa_ssid *ssid) { int i, ret; char *buf, *pos, *end; const struct eap_method_type *eap_methods = ssid->eap.eap_methods; const char *name; if (eap_methods == NULL) return NULL; pos = buf = os_zalloc(100); if (buf == NULL) return NULL; end = buf + 100; for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF || eap_methods[i].method != EAP_TYPE_NONE; i++) { name = eap_get_name(eap_methods[i].vendor, eap_methods[i].method); if (name) { ret = os_snprintf(pos, end - pos, "%s%s", pos == buf ? "" : " ", name); if (ret < 0 || ret >= end - pos) break; pos += ret; } } end[-1] = '\0'; return buf; } static int wpa_config_parse_password(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { u8 *hash; if (os_strcmp(value, "NULL") == 0) { wpa_printf(MSG_DEBUG, "Unset configuration string 'password'"); os_free(ssid->eap.password); ssid->eap.password = NULL; ssid->eap.password_len = 0; return 0; } #ifdef CONFIG_EXT_PASSWORD if (os_strncmp(value, "ext:", 4) == 0) { char *name = os_strdup(value + 4); if (name == NULL) return -1; os_free(ssid->eap.password); ssid->eap.password = (u8 *) name; ssid->eap.password_len = os_strlen(name); ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD; return 0; } #endif /* CONFIG_EXT_PASSWORD */ if (os_strncmp(value, "hash:", 5) != 0) { char *tmp; size_t res_len; tmp = wpa_config_parse_string(value, &res_len); if (tmp == NULL) { wpa_printf(MSG_ERROR, "Line %d: failed to parse " "password.", line); return -1; } wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name, (u8 *) tmp, res_len); os_free(ssid->eap.password); ssid->eap.password = (u8 *) tmp; ssid->eap.password_len = res_len; ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD; return 0; } /* NtPasswordHash: hash:<32 hex digits> */ if (os_strlen(value + 5) != 2 * 16) { wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length " "(expected 32 hex digits)", line); return -1; } hash = os_malloc(16); if (hash == NULL) return -1; if (hexstr2bin(value + 5, hash, 16)) { os_free(hash); wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line); return -1; } wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16); os_free(ssid->eap.password); ssid->eap.password = hash; ssid->eap.password_len = 16; ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH; ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD; return 0; } static char * wpa_config_write_password(const struct parse_data *data, struct wpa_ssid *ssid) { char *buf; if (ssid->eap.password == NULL) return NULL; #ifdef CONFIG_EXT_PASSWORD if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { buf = os_zalloc(4 + ssid->eap.password_len + 1); if (buf == NULL) return NULL; os_memcpy(buf, "ext:", 4); os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len); return buf; } #endif /* CONFIG_EXT_PASSWORD */ if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) { return wpa_config_write_string( ssid->eap.password, ssid->eap.password_len); } buf = os_malloc(5 + 32 + 1); if (buf == NULL) return NULL; os_memcpy(buf, "hash:", 5); wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.password, 16); return buf; } #endif /* IEEE8021X_EAPOL */ static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line, const char *value, int idx) { char *buf, title[20]; int res; buf = wpa_config_parse_string(value, len); if (buf == NULL) { wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.", line, idx, value); return -1; } if (*len > MAX_WEP_KEY_LEN) { wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.", line, idx, value); os_free(buf); return -1; } if (*len && *len != 5 && *len != 13 && *len != 16) { wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key length %u - " "this network block will be ignored", line, (unsigned int) *len); } os_memcpy(key, buf, *len); os_free(buf); res = os_snprintf(title, sizeof(title), "wep_key%d", idx); if (res >= 0 && (size_t) res < sizeof(title)) wpa_hexdump_key(MSG_MSGDUMP, title, key, *len); return 0; } static int wpa_config_parse_wep_key0(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { return wpa_config_parse_wep_key(ssid->wep_key[0], &ssid->wep_key_len[0], line, value, 0); } static int wpa_config_parse_wep_key1(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { return wpa_config_parse_wep_key(ssid->wep_key[1], &ssid->wep_key_len[1], line, value, 1); } static int wpa_config_parse_wep_key2(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { return wpa_config_parse_wep_key(ssid->wep_key[2], &ssid->wep_key_len[2], line, value, 2); } static int wpa_config_parse_wep_key3(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { return wpa_config_parse_wep_key(ssid->wep_key[3], &ssid->wep_key_len[3], line, value, 3); } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx) { if (ssid->wep_key_len[idx] == 0) return NULL; return wpa_config_write_string(ssid->wep_key[idx], ssid->wep_key_len[idx]); } static char * wpa_config_write_wep_key0(const struct parse_data *data, struct wpa_ssid *ssid) { return wpa_config_write_wep_key(ssid, 0); } static char * wpa_config_write_wep_key1(const struct parse_data *data, struct wpa_ssid *ssid) { return wpa_config_write_wep_key(ssid, 1); } static char * wpa_config_write_wep_key2(const struct parse_data *data, struct wpa_ssid *ssid) { return wpa_config_write_wep_key(ssid, 2); } static char * wpa_config_write_wep_key3(const struct parse_data *data, struct wpa_ssid *ssid) { return wpa_config_write_wep_key(ssid, 3); } #endif /* NO_CONFIG_WRITE */ #ifdef CONFIG_P2P static int wpa_config_parse_go_p2p_dev_addr(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 || os_strcmp(value, "any") == 0) { os_memset(ssid->go_p2p_dev_addr, 0, ETH_ALEN); wpa_printf(MSG_MSGDUMP, "GO P2P Device Address any"); return 0; } if (hwaddr_aton(value, ssid->go_p2p_dev_addr)) { wpa_printf(MSG_ERROR, "Line %d: Invalid GO P2P Device Address '%s'.", line, value); return -1; } ssid->bssid_set = 1; wpa_printf(MSG_MSGDUMP, "GO P2P Device Address " MACSTR, MAC2STR(ssid->go_p2p_dev_addr)); return 0; } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_go_p2p_dev_addr(const struct parse_data *data, struct wpa_ssid *ssid) { char *value; int res; if (is_zero_ether_addr(ssid->go_p2p_dev_addr)) return NULL; value = os_malloc(20); if (value == NULL) return NULL; res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->go_p2p_dev_addr)); if (res < 0 || res >= 20) { os_free(value); return NULL; } value[20 - 1] = '\0'; return value; } #endif /* NO_CONFIG_WRITE */ static int wpa_config_parse_p2p_client_list(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { const char *pos; u8 *buf, *n, addr[ETH_ALEN]; size_t count; buf = NULL; count = 0; pos = value; while (pos && *pos) { while (*pos == ' ') pos++; if (hwaddr_aton(pos, addr)) { if (count == 0) { wpa_printf(MSG_ERROR, "Line %d: Invalid " "p2p_client_list address '%s'.", line, value); os_free(buf); return -1; } /* continue anyway since this could have been from a * truncated configuration file line */ wpa_printf(MSG_INFO, "Line %d: Ignore likely " "truncated p2p_client_list address '%s'", line, pos); } else { n = os_realloc_array(buf, count + 1, ETH_ALEN); if (n == NULL) { os_free(buf); return -1; } buf = n; os_memmove(buf + ETH_ALEN, buf, count * ETH_ALEN); os_memcpy(buf, addr, ETH_ALEN); count++; wpa_hexdump(MSG_MSGDUMP, "p2p_client_list", addr, ETH_ALEN); } pos = os_strchr(pos, ' '); } os_free(ssid->p2p_client_list); ssid->p2p_client_list = buf; ssid->num_p2p_clients = count; return 0; } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_p2p_client_list(const struct parse_data *data, struct wpa_ssid *ssid) { char *value, *end, *pos; int res; size_t i; if (ssid->p2p_client_list == NULL || ssid->num_p2p_clients == 0) return NULL; value = os_malloc(20 * ssid->num_p2p_clients); if (value == NULL) return NULL; pos = value; end = value + 20 * ssid->num_p2p_clients; for (i = ssid->num_p2p_clients; i > 0; i--) { res = os_snprintf(pos, end - pos, MACSTR " ", MAC2STR(ssid->p2p_client_list + (i - 1) * ETH_ALEN)); if (res < 0 || res >= end - pos) { os_free(value); return NULL; } pos += res; } if (pos > value) pos[-1] = '\0'; return value; } #endif /* NO_CONFIG_WRITE */ static int wpa_config_parse_psk_list(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { struct psk_list_entry *p; const char *pos; p = os_zalloc(sizeof(*p)); if (p == NULL) return -1; pos = value; if (os_strncmp(pos, "P2P-", 4) == 0) { p->p2p = 1; pos += 4; } if (hwaddr_aton(pos, p->addr)) { wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list address '%s'", line, pos); os_free(p); return -1; } pos += 17; if (*pos != '-') { wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list '%s'", line, pos); os_free(p); return -1; } pos++; if (hexstr2bin(pos, p->psk, PMK_LEN) || pos[PMK_LEN * 2] != '\0') { wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list PSK '%s'", line, pos); os_free(p); return -1; } dl_list_add(&ssid->psk_list, &p->list); return 0; } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_psk_list(const struct parse_data *data, struct wpa_ssid *ssid) { return NULL; } #endif /* NO_CONFIG_WRITE */ #endif /* CONFIG_P2P */ /* Helper macros for network block parser */ #ifdef OFFSET #undef OFFSET #endif /* OFFSET */ /* OFFSET: Get offset of a variable within the wpa_ssid structure */ #define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v) /* STR: Define a string variable for an ASCII string; f = field name */ #ifdef NO_CONFIG_WRITE #define _STR(f) #f, wpa_config_parse_str, OFFSET(f) #define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f) #else /* NO_CONFIG_WRITE */ #define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f) #define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f) #endif /* NO_CONFIG_WRITE */ #define STR(f) _STR(f), NULL, NULL, NULL, 0 #define STRe(f) _STRe(f), NULL, NULL, NULL, 0 #define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1 #define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1 /* STR_LEN: Define a string variable with a separate variable for storing the * data length. Unlike STR(), this can be used to store arbitrary binary data * (i.e., even nul termination character). */ #define _STR_LEN(f) _STR(f), OFFSET(f ## _len) #define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len) #define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0 #define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0 #define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1 /* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length * explicitly specified. */ #define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max) #define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0 #define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1 #ifdef NO_CONFIG_WRITE #define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0 #define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0 #else /* NO_CONFIG_WRITE */ #define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \ OFFSET(f), (void *) 0 #define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \ OFFSET(eap.f), (void *) 0 #endif /* NO_CONFIG_WRITE */ /* INT: Define an integer variable */ #define INT(f) _INT(f), NULL, NULL, 0 #define INTe(f) _INTe(f), NULL, NULL, 0 /* INT_RANGE: Define an integer variable with allowed value range */ #define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0 /* FUNC: Define a configuration variable that uses a custom function for * parsing and writing the value. */ #ifdef NO_CONFIG_WRITE #define _FUNC(f) #f, wpa_config_parse_ ## f, NULL, NULL, NULL, NULL #else /* NO_CONFIG_WRITE */ #define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \ NULL, NULL, NULL, NULL #endif /* NO_CONFIG_WRITE */ #define FUNC(f) _FUNC(f), 0 #define FUNC_KEY(f) _FUNC(f), 1 /* * Table of network configuration variables. This table is used to parse each * network configuration variable, e.g., each line in wpa_supplicant.conf file * that is inside a network block. * * This table is generated using the helper macros defined above and with * generous help from the C pre-processor. The field name is stored as a string * into .name and for STR and INT types, the offset of the target buffer within * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar * offset to the field containing the length of the configuration variable. * .param3 and .param4 can be used to mark the allowed range (length for STR * and value for INT). * * For each configuration line in wpa_supplicant.conf, the parser goes through * this table and select the entry that matches with the field name. The parser * function (.parser) is then called to parse the actual value of the field. * * This kind of mechanism makes it easy to add new configuration parameters, * since only one line needs to be added into this table and into the * struct wpa_ssid definition if the new variable is either a string or * integer. More complex types will need to use their own parser and writer * functions. */ static const struct parse_data ssid_fields[] = { { STR_RANGE(ssid, 0, MAX_SSID_LEN) }, { INT_RANGE(scan_ssid, 0, 1) }, { FUNC(bssid) }, { FUNC_KEY(psk) }, { FUNC(proto) }, { FUNC(key_mgmt) }, { INT(bg_scan_period) }, { FUNC(pairwise) }, { FUNC(group) }, { FUNC(auth_alg) }, { FUNC(scan_freq) }, { FUNC(freq_list) }, #ifdef IEEE8021X_EAPOL { FUNC(eap) }, { STR_LENe(identity) }, { STR_LENe(anonymous_identity) }, { FUNC_KEY(password) }, { STRe(ca_cert) }, { STRe(ca_path) }, { STRe(client_cert) }, { STRe(private_key) }, { STR_KEYe(private_key_passwd) }, { STRe(dh_file) }, { STRe(subject_match) }, { STRe(altsubject_match) }, { STRe(domain_suffix_match) }, { STRe(ca_cert2) }, { STRe(ca_path2) }, { STRe(client_cert2) }, { STRe(private_key2) }, { STR_KEYe(private_key2_passwd) }, { STRe(dh_file2) }, { STRe(subject_match2) }, { STRe(altsubject_match2) }, { STRe(domain_suffix_match2) }, { STRe(phase1) }, { STRe(phase2) }, { STRe(pcsc) }, { STR_KEYe(pin) }, { STRe(engine_id) }, { STRe(key_id) }, { STRe(cert_id) }, { STRe(ca_cert_id) }, { STR_KEYe(pin2) }, { STRe(engine2_id) }, { STRe(key2_id) }, { STRe(cert2_id) }, { STRe(ca_cert2_id) }, { INTe(engine) }, { INTe(engine2) }, { INT(eapol_flags) }, { INTe(sim_num) }, #endif /* IEEE8021X_EAPOL */ { FUNC_KEY(wep_key0) }, { FUNC_KEY(wep_key1) }, { FUNC_KEY(wep_key2) }, { FUNC_KEY(wep_key3) }, { INT(wep_tx_keyidx) }, { INT(priority) }, #ifdef IEEE8021X_EAPOL { INT(eap_workaround) }, { STRe(pac_file) }, { INTe(fragment_size) }, { INTe(ocsp) }, #endif /* IEEE8021X_EAPOL */ { INT_RANGE(mode, 0, 4) }, { INT_RANGE(proactive_key_caching, 0, 1) }, { INT_RANGE(disabled, 0, 2) }, { STR(id_str) }, #ifdef CONFIG_IEEE80211W { INT_RANGE(ieee80211w, 0, 2) }, #endif /* CONFIG_IEEE80211W */ { INT_RANGE(peerkey, 0, 1) }, { INT_RANGE(mixed_cell, 0, 1) }, { INT_RANGE(frequency, 0, 65000) }, { INT(wpa_ptk_rekey) }, { STR(bgscan) }, { INT_RANGE(ignore_broadcast_ssid, 0, 2) }, #ifdef CONFIG_P2P { FUNC(go_p2p_dev_addr) }, { FUNC(p2p_client_list) }, { FUNC(psk_list) }, #endif /* CONFIG_P2P */ #ifdef CONFIG_HT_OVERRIDES { INT_RANGE(disable_ht, 0, 1) }, { INT_RANGE(disable_ht40, -1, 1) }, { INT_RANGE(disable_sgi, 0, 1) }, { INT_RANGE(disable_ldpc, 0, 1) }, { INT_RANGE(ht40_intolerant, 0, 1) }, { INT_RANGE(disable_max_amsdu, -1, 1) }, { INT_RANGE(ampdu_factor, -1, 3) }, { INT_RANGE(ampdu_density, -1, 7) }, { STR(ht_mcs) }, #endif /* CONFIG_HT_OVERRIDES */ #ifdef CONFIG_VHT_OVERRIDES { INT_RANGE(disable_vht, 0, 1) }, { INT(vht_capa) }, { INT(vht_capa_mask) }, { INT_RANGE(vht_rx_mcs_nss_1, -1, 3) }, { INT_RANGE(vht_rx_mcs_nss_2, -1, 3) }, { INT_RANGE(vht_rx_mcs_nss_3, -1, 3) }, { INT_RANGE(vht_rx_mcs_nss_4, -1, 3) }, { INT_RANGE(vht_rx_mcs_nss_5, -1, 3) }, { INT_RANGE(vht_rx_mcs_nss_6, -1, 3) }, { INT_RANGE(vht_rx_mcs_nss_7, -1, 3) }, { INT_RANGE(vht_rx_mcs_nss_8, -1, 3) }, { INT_RANGE(vht_tx_mcs_nss_1, -1, 3) }, { INT_RANGE(vht_tx_mcs_nss_2, -1, 3) }, { INT_RANGE(vht_tx_mcs_nss_3, -1, 3) }, { INT_RANGE(vht_tx_mcs_nss_4, -1, 3) }, { INT_RANGE(vht_tx_mcs_nss_5, -1, 3) }, { INT_RANGE(vht_tx_mcs_nss_6, -1, 3) }, { INT_RANGE(vht_tx_mcs_nss_7, -1, 3) }, { INT_RANGE(vht_tx_mcs_nss_8, -1, 3) }, #endif /* CONFIG_VHT_OVERRIDES */ { INT(ap_max_inactivity) }, { INT(dtim_period) }, { INT(beacon_int) }, #ifdef CONFIG_MACSEC { INT_RANGE(macsec_policy, 0, 1) }, #endif /* CONFIG_MACSEC */ }; #undef OFFSET #undef _STR #undef STR #undef STR_KEY #undef _STR_LEN #undef STR_LEN #undef STR_LEN_KEY #undef _STR_RANGE #undef STR_RANGE #undef STR_RANGE_KEY #undef _INT #undef INT #undef INT_RANGE #undef _FUNC #undef FUNC #undef FUNC_KEY #define NUM_SSID_FIELDS ARRAY_SIZE(ssid_fields) /** * wpa_config_add_prio_network - Add a network to priority lists * @config: Configuration data from wpa_config_read() * @ssid: Pointer to the network configuration to be added to the list * Returns: 0 on success, -1 on failure * * This function is used to add a network block to the priority list of * networks. This must be called for each network when reading in the full * configuration. In addition, this can be used indirectly when updating * priorities by calling wpa_config_update_prio_list(). */ int wpa_config_add_prio_network(struct wpa_config *config, struct wpa_ssid *ssid) { int prio; struct wpa_ssid *prev, **nlist; /* * Add to an existing priority list if one is available for the * configured priority level for this network. */ for (prio = 0; prio < config->num_prio; prio++) { prev = config->pssid[prio]; if (prev->priority == ssid->priority) { while (prev->pnext) prev = prev->pnext; prev->pnext = ssid; return 0; } } /* First network for this priority - add a new priority list */ nlist = os_realloc_array(config->pssid, config->num_prio + 1, sizeof(struct wpa_ssid *)); if (nlist == NULL) return -1; for (prio = 0; prio < config->num_prio; prio++) { if (nlist[prio]->priority < ssid->priority) { os_memmove(&nlist[prio + 1], &nlist[prio], (config->num_prio - prio) * sizeof(struct wpa_ssid *)); break; } } nlist[prio] = ssid; config->num_prio++; config->pssid = nlist; return 0; } /** * wpa_config_update_prio_list - Update network priority list * @config: Configuration data from wpa_config_read() * Returns: 0 on success, -1 on failure * * This function is called to update the priority list of networks in the * configuration when a network is being added or removed. This is also called * if a priority for a network is changed. */ int wpa_config_update_prio_list(struct wpa_config *config) { struct wpa_ssid *ssid; int ret = 0; os_free(config->pssid); config->pssid = NULL; config->num_prio = 0; ssid = config->ssid; while (ssid) { ssid->pnext = NULL; if (wpa_config_add_prio_network(config, ssid) < 0) ret = -1; ssid = ssid->next; } return ret; } #ifdef IEEE8021X_EAPOL static void eap_peer_config_free(struct eap_peer_config *eap) { os_free(eap->eap_methods); os_free(eap->identity); os_free(eap->anonymous_identity); os_free(eap->password); os_free(eap->ca_cert); os_free(eap->ca_path); os_free(eap->client_cert); os_free(eap->private_key); os_free(eap->private_key_passwd); os_free(eap->dh_file); os_free(eap->subject_match); os_free(eap->altsubject_match); os_free(eap->domain_suffix_match); os_free(eap->ca_cert2); os_free(eap->ca_path2); os_free(eap->client_cert2); os_free(eap->private_key2); os_free(eap->private_key2_passwd); os_free(eap->dh_file2); os_free(eap->subject_match2); os_free(eap->altsubject_match2); os_free(eap->domain_suffix_match2); os_free(eap->phase1); os_free(eap->phase2); os_free(eap->pcsc); os_free(eap->pin); os_free(eap->engine_id); os_free(eap->key_id); os_free(eap->cert_id); os_free(eap->ca_cert_id); os_free(eap->key2_id); os_free(eap->cert2_id); os_free(eap->ca_cert2_id); os_free(eap->pin2); os_free(eap->engine2_id); os_free(eap->otp); os_free(eap->pending_req_otp); os_free(eap->pac_file); os_free(eap->new_password); os_free(eap->external_sim_resp); } #endif /* IEEE8021X_EAPOL */ /** * wpa_config_free_ssid - Free network/ssid configuration data * @ssid: Configuration data for the network * * This function frees all resources allocated for the network configuration * data. */ void wpa_config_free_ssid(struct wpa_ssid *ssid) { struct psk_list_entry *psk; os_free(ssid->ssid); os_free(ssid->passphrase); os_free(ssid->ext_psk); #ifdef IEEE8021X_EAPOL eap_peer_config_free(&ssid->eap); #endif /* IEEE8021X_EAPOL */ os_free(ssid->id_str); os_free(ssid->scan_freq); os_free(ssid->freq_list); os_free(ssid->bgscan); os_free(ssid->p2p_client_list); #ifdef CONFIG_HT_OVERRIDES os_free(ssid->ht_mcs); #endif /* CONFIG_HT_OVERRIDES */ while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry, list))) { dl_list_del(&psk->list); os_free(psk); } os_free(ssid); } void wpa_config_free_cred(struct wpa_cred *cred) { size_t i; os_free(cred->realm); os_free(cred->username); os_free(cred->password); os_free(cred->ca_cert); os_free(cred->client_cert); os_free(cred->private_key); os_free(cred->private_key_passwd); os_free(cred->imsi); os_free(cred->milenage); for (i = 0; i < cred->num_domain; i++) os_free(cred->domain[i]); os_free(cred->domain); os_free(cred->domain_suffix_match); os_free(cred->eap_method); os_free(cred->phase1); os_free(cred->phase2); os_free(cred->excluded_ssid); os_free(cred->roaming_partner); os_free(cred->provisioning_sp); for (i = 0; i < cred->num_req_conn_capab; i++) os_free(cred->req_conn_capab_port[i]); os_free(cred->req_conn_capab_port); os_free(cred->req_conn_capab_proto); os_free(cred); } void wpa_config_flush_blobs(struct wpa_config *config) { #ifndef CONFIG_NO_CONFIG_BLOBS struct wpa_config_blob *blob, *prev; blob = config->blobs; config->blobs = NULL; while (blob) { prev = blob; blob = blob->next; wpa_config_free_blob(prev); } #endif /* CONFIG_NO_CONFIG_BLOBS */ } /** * wpa_config_free - Free configuration data * @config: Configuration data from wpa_config_read() * * This function frees all resources allocated for the configuration data by * wpa_config_read(). */ void wpa_config_free(struct wpa_config *config) { struct wpa_ssid *ssid, *prev = NULL; struct wpa_cred *cred, *cprev; ssid = config->ssid; while (ssid) { prev = ssid; ssid = ssid->next; wpa_config_free_ssid(prev); } cred = config->cred; while (cred) { cprev = cred; cred = cred->next; wpa_config_free_cred(cprev); } wpa_config_flush_blobs(config); wpabuf_free(config->wps_vendor_ext_m1); os_free(config->ctrl_interface); os_free(config->ctrl_interface_group); os_free(config->opensc_engine_path); os_free(config->pkcs11_engine_path); os_free(config->pkcs11_module_path); os_free(config->pcsc_reader); os_free(config->pcsc_pin); os_free(config->driver_param); os_free(config->device_name); os_free(config->manufacturer); os_free(config->model_name); os_free(config->model_number); os_free(config->serial_number); os_free(config->config_methods); os_free(config->p2p_ssid_postfix); os_free(config->pssid); os_free(config->p2p_pref_chan); os_free(config->p2p_no_go_freq.range); os_free(config->autoscan); os_free(config->freq_list); wpabuf_free(config->wps_nfc_dh_pubkey); wpabuf_free(config->wps_nfc_dh_privkey); wpabuf_free(config->wps_nfc_dev_pw); os_free(config->ext_password_backend); os_free(config->sae_groups); wpabuf_free(config->ap_vendor_elements); os_free(config->osu_dir); os_free(config->wowlan_triggers); os_free(config); } /** * wpa_config_foreach_network - Iterate over each configured network * @config: Configuration data from wpa_config_read() * @func: Callback function to process each network * @arg: Opaque argument to pass to callback function * * Iterate over the set of configured networks calling the specified * function for each item. We guard against callbacks removing the * supplied network. */ void wpa_config_foreach_network(struct wpa_config *config, void (*func)(void *, struct wpa_ssid *), void *arg) { struct wpa_ssid *ssid, *next; ssid = config->ssid; while (ssid) { next = ssid->next; func(arg, ssid); ssid = next; } } /** * wpa_config_get_network - Get configured network based on id * @config: Configuration data from wpa_config_read() * @id: Unique network id to search for * Returns: Network configuration or %NULL if not found */ struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id) { struct wpa_ssid *ssid; ssid = config->ssid; while (ssid) { if (id == ssid->id) break; ssid = ssid->next; } return ssid; } /** * wpa_config_add_network - Add a new network with empty configuration * @config: Configuration data from wpa_config_read() * Returns: The new network configuration or %NULL if operation failed */ struct wpa_ssid * wpa_config_add_network(struct wpa_config *config) { int id; struct wpa_ssid *ssid, *last = NULL; id = -1; ssid = config->ssid; while (ssid) { if (ssid->id > id) id = ssid->id; last = ssid; ssid = ssid->next; } id++; ssid = os_zalloc(sizeof(*ssid)); if (ssid == NULL) return NULL; ssid->id = id; dl_list_init(&ssid->psk_list); if (last) last->next = ssid; else config->ssid = ssid; wpa_config_update_prio_list(config); return ssid; } /** * wpa_config_remove_network - Remove a configured network based on id * @config: Configuration data from wpa_config_read() * @id: Unique network id to search for * Returns: 0 on success, or -1 if the network was not found */ int wpa_config_remove_network(struct wpa_config *config, int id) { struct wpa_ssid *ssid, *prev = NULL; ssid = config->ssid; while (ssid) { if (id == ssid->id) break; prev = ssid; ssid = ssid->next; } if (ssid == NULL) return -1; if (prev) prev->next = ssid->next; else config->ssid = ssid->next; wpa_config_update_prio_list(config); wpa_config_free_ssid(ssid); return 0; } /** * wpa_config_set_network_defaults - Set network default values * @ssid: Pointer to network configuration data */ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) { ssid->proto = DEFAULT_PROTO; ssid->pairwise_cipher = DEFAULT_PAIRWISE; ssid->group_cipher = DEFAULT_GROUP; ssid->key_mgmt = DEFAULT_KEY_MGMT; ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; #ifdef IEEE8021X_EAPOL ssid->eapol_flags = DEFAULT_EAPOL_FLAGS; ssid->eap_workaround = DEFAULT_EAP_WORKAROUND; ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE; ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM; #endif /* IEEE8021X_EAPOL */ #ifdef CONFIG_HT_OVERRIDES ssid->disable_ht = DEFAULT_DISABLE_HT; ssid->disable_ht40 = DEFAULT_DISABLE_HT40; ssid->disable_sgi = DEFAULT_DISABLE_SGI; ssid->disable_ldpc = DEFAULT_DISABLE_LDPC; ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU; ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR; ssid->ampdu_density = DEFAULT_AMPDU_DENSITY; #endif /* CONFIG_HT_OVERRIDES */ #ifdef CONFIG_VHT_OVERRIDES ssid->vht_rx_mcs_nss_1 = -1; ssid->vht_rx_mcs_nss_2 = -1; ssid->vht_rx_mcs_nss_3 = -1; ssid->vht_rx_mcs_nss_4 = -1; ssid->vht_rx_mcs_nss_5 = -1; ssid->vht_rx_mcs_nss_6 = -1; ssid->vht_rx_mcs_nss_7 = -1; ssid->vht_rx_mcs_nss_8 = -1; ssid->vht_tx_mcs_nss_1 = -1; ssid->vht_tx_mcs_nss_2 = -1; ssid->vht_tx_mcs_nss_3 = -1; ssid->vht_tx_mcs_nss_4 = -1; ssid->vht_tx_mcs_nss_5 = -1; ssid->vht_tx_mcs_nss_6 = -1; ssid->vht_tx_mcs_nss_7 = -1; ssid->vht_tx_mcs_nss_8 = -1; #endif /* CONFIG_VHT_OVERRIDES */ ssid->proactive_key_caching = -1; #ifdef CONFIG_IEEE80211W ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT; #endif /* CONFIG_IEEE80211W */ } /** * wpa_config_set - Set a variable in network configuration * @ssid: Pointer to network configuration data * @var: Variable name, e.g., "ssid" * @value: Variable value * @line: Line number in configuration file or 0 if not used * Returns: 0 on success, -1 on failure * * This function can be used to set network configuration variables based on * both the configuration file and management interface input. The value * parameter must be in the same format as the text-based configuration file is * using. For example, strings are using double quotation marks. */ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, int line) { size_t i; int ret = 0; if (ssid == NULL || var == NULL || value == NULL) return -1; for (i = 0; i < NUM_SSID_FIELDS; i++) { const struct parse_data *field = &ssid_fields[i]; if (os_strcmp(var, field->name) != 0) continue; if (field->parser(field, ssid, line, value)) { if (line) { wpa_printf(MSG_ERROR, "Line %d: failed to " "parse %s '%s'.", line, var, value); } ret = -1; } break; } if (i == NUM_SSID_FIELDS) { if (line) { wpa_printf(MSG_ERROR, "Line %d: unknown network field " "'%s'.", line, var); } ret = -1; } return ret; } int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var, const char *value) { size_t len; char *buf; int ret; len = os_strlen(value); buf = os_malloc(len + 3); if (buf == NULL) return -1; buf[0] = '"'; os_memcpy(buf + 1, value, len); buf[len + 1] = '"'; buf[len + 2] = '\0'; ret = wpa_config_set(ssid, var, buf, 0); os_free(buf); return ret; } /** * wpa_config_get_all - Get all options from network configuration * @ssid: Pointer to network configuration data * @get_keys: Determines if keys/passwords will be included in returned list * (if they may be exported) * Returns: %NULL terminated list of all set keys and their values in the form * of [key1, val1, key2, val2, ... , NULL] * * This function can be used to get list of all configured network properties. * The caller is responsible for freeing the returned list and all its * elements. */ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys) { const struct parse_data *field; char *key, *value; size_t i; char **props; int fields_num; get_keys = get_keys && ssid->export_keys; props = os_calloc(2 * NUM_SSID_FIELDS + 1, sizeof(char *)); if (!props) return NULL; fields_num = 0; for (i = 0; i < NUM_SSID_FIELDS; i++) { field = &ssid_fields[i]; if (field->key_data && !get_keys) continue; value = field->writer(field, ssid); if (value == NULL) continue; if (os_strlen(value) == 0) { os_free(value); continue; } key = os_strdup(field->name); if (key == NULL) { os_free(value); goto err; } props[fields_num * 2] = key; props[fields_num * 2 + 1] = value; fields_num++; } return props; err: value = *props; while (value) os_free(value++); os_free(props); return NULL; } #ifndef NO_CONFIG_WRITE /** * wpa_config_get - Get a variable in network configuration * @ssid: Pointer to network configuration data * @var: Variable name, e.g., "ssid" * Returns: Value of the variable or %NULL on failure * * This function can be used to get network configuration variables. The * returned value is a copy of the configuration variable in text format, i.e,. * the same format that the text-based configuration file and wpa_config_set() * are using for the value. The caller is responsible for freeing the returned * value. */ char * wpa_config_get(struct wpa_ssid *ssid, const char *var) { size_t i; if (ssid == NULL || var == NULL) return NULL; for (i = 0; i < NUM_SSID_FIELDS; i++) { const struct parse_data *field = &ssid_fields[i]; if (os_strcmp(var, field->name) == 0) return field->writer(field, ssid); } return NULL; } /** * wpa_config_get_no_key - Get a variable in network configuration (no keys) * @ssid: Pointer to network configuration data * @var: Variable name, e.g., "ssid" * Returns: Value of the variable or %NULL on failure * * This function can be used to get network configuration variable like * wpa_config_get(). The only difference is that this functions does not expose * key/password material from the configuration. In case a key/password field * is requested, the returned value is an empty string or %NULL if the variable * is not set or "*" if the variable is set (regardless of its value). The * returned value is a copy of the configuration variable in text format, i.e,. * the same format that the text-based configuration file and wpa_config_set() * are using for the value. The caller is responsible for freeing the returned * value. */ char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var) { size_t i; if (ssid == NULL || var == NULL) return NULL; for (i = 0; i < NUM_SSID_FIELDS; i++) { const struct parse_data *field = &ssid_fields[i]; if (os_strcmp(var, field->name) == 0) { char *res = field->writer(field, ssid); if (field->key_data) { if (res && res[0]) { wpa_printf(MSG_DEBUG, "Do not allow " "key_data field to be " "exposed"); os_free(res); return os_strdup("*"); } os_free(res); return NULL; } return res; } } return NULL; } #endif /* NO_CONFIG_WRITE */ /** * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID * @ssid: Pointer to network configuration data * * This function must be called to update WPA PSK when either SSID or the * passphrase has changed for the network configuration. */ void wpa_config_update_psk(struct wpa_ssid *ssid) { #ifndef CONFIG_NO_PBKDF2 pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096, ssid->psk, PMK_LEN); wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", ssid->psk, PMK_LEN); ssid->psk_set = 1; #endif /* CONFIG_NO_PBKDF2 */ } static int wpa_config_set_cred_req_conn_capab(struct wpa_cred *cred, const char *value) { u8 *proto; int **port; int *ports, *nports; const char *pos; unsigned int num_ports; proto = os_realloc_array(cred->req_conn_capab_proto, cred->num_req_conn_capab + 1, sizeof(u8)); if (proto == NULL) return -1; cred->req_conn_capab_proto = proto; port = os_realloc_array(cred->req_conn_capab_port, cred->num_req_conn_capab + 1, sizeof(int *)); if (port == NULL) return -1; cred->req_conn_capab_port = port; proto[cred->num_req_conn_capab] = atoi(value); pos = os_strchr(value, ':'); if (pos == NULL) { port[cred->num_req_conn_capab] = NULL; cred->num_req_conn_capab++; return 0; } pos++; ports = NULL; num_ports = 0; while (*pos) { nports = os_realloc_array(ports, num_ports + 1, sizeof(int)); if (nports == NULL) { os_free(ports); return -1; } ports = nports; ports[num_ports++] = atoi(pos); pos = os_strchr(pos, ','); if (pos == NULL) break; pos++; } nports = os_realloc_array(ports, num_ports + 1, sizeof(int)); if (nports == NULL) { os_free(ports); return -1; } ports = nports; ports[num_ports] = -1; port[cred->num_req_conn_capab] = ports; cred->num_req_conn_capab++; return 0; } int wpa_config_set_cred(struct wpa_cred *cred, const char *var, const char *value, int line) { char *val; size_t len; if (os_strcmp(var, "temporary") == 0) { cred->temporary = atoi(value); return 0; } if (os_strcmp(var, "priority") == 0) { cred->priority = atoi(value); return 0; } if (os_strcmp(var, "sp_priority") == 0) { int prio = atoi(value); if (prio < 0 || prio > 255) return -1; cred->sp_priority = prio; return 0; } if (os_strcmp(var, "pcsc") == 0) { cred->pcsc = atoi(value); return 0; } if (os_strcmp(var, "eap") == 0) { struct eap_method_type method; method.method = eap_peer_get_type(value, &method.vendor); if (method.vendor == EAP_VENDOR_IETF && method.method == EAP_TYPE_NONE) { wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' " "for a credential", line, value); return -1; } os_free(cred->eap_method); cred->eap_method = os_malloc(sizeof(*cred->eap_method)); if (cred->eap_method == NULL) return -1; os_memcpy(cred->eap_method, &method, sizeof(method)); return 0; } if (os_strcmp(var, "password") == 0 && os_strncmp(value, "ext:", 4) == 0) { os_free(cred->password); cred->password = os_strdup(value); cred->ext_password = 1; return 0; } if (os_strcmp(var, "update_identifier") == 0) { cred->update_identifier = atoi(value); return 0; } if (os_strcmp(var, "min_dl_bandwidth_home") == 0) { cred->min_dl_bandwidth_home = atoi(value); return 0; } if (os_strcmp(var, "min_ul_bandwidth_home") == 0) { cred->min_ul_bandwidth_home = atoi(value); return 0; } if (os_strcmp(var, "min_dl_bandwidth_roaming") == 0) { cred->min_dl_bandwidth_roaming = atoi(value); return 0; } if (os_strcmp(var, "min_ul_bandwidth_roaming") == 0) { cred->min_ul_bandwidth_roaming = atoi(value); return 0; } if (os_strcmp(var, "max_bss_load") == 0) { cred->max_bss_load = atoi(value); return 0; } if (os_strcmp(var, "req_conn_capab") == 0) return wpa_config_set_cred_req_conn_capab(cred, value); if (os_strcmp(var, "ocsp") == 0) { cred->ocsp = atoi(value); return 0; } if (os_strcmp(var, "sim_num") == 0) { cred->sim_num = atoi(value); return 0; } val = wpa_config_parse_string(value, &len); if (val == NULL) { wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string " "value '%s'.", line, var, value); return -1; } if (os_strcmp(var, "realm") == 0) { os_free(cred->realm); cred->realm = val; return 0; } if (os_strcmp(var, "username") == 0) { os_free(cred->username); cred->username = val; return 0; } if (os_strcmp(var, "password") == 0) { os_free(cred->password); cred->password = val; cred->ext_password = 0; return 0; } if (os_strcmp(var, "ca_cert") == 0) { os_free(cred->ca_cert); cred->ca_cert = val; return 0; } if (os_strcmp(var, "client_cert") == 0) { os_free(cred->client_cert); cred->client_cert = val; return 0; } if (os_strcmp(var, "private_key") == 0) { os_free(cred->private_key); cred->private_key = val; return 0; } if (os_strcmp(var, "private_key_passwd") == 0) { os_free(cred->private_key_passwd); cred->private_key_passwd = val; return 0; } if (os_strcmp(var, "imsi") == 0) { os_free(cred->imsi); cred->imsi = val; return 0; } if (os_strcmp(var, "milenage") == 0) { os_free(cred->milenage); cred->milenage = val; return 0; } if (os_strcmp(var, "domain_suffix_match") == 0) { os_free(cred->domain_suffix_match); cred->domain_suffix_match = val; return 0; } if (os_strcmp(var, "domain") == 0) { char **new_domain; new_domain = os_realloc_array(cred->domain, cred->num_domain + 1, sizeof(char *)); if (new_domain == NULL) { os_free(val); return -1; } new_domain[cred->num_domain++] = val; cred->domain = new_domain; return 0; } if (os_strcmp(var, "phase1") == 0) { os_free(cred->phase1); cred->phase1 = val; return 0; } if (os_strcmp(var, "phase2") == 0) { os_free(cred->phase2); cred->phase2 = val; return 0; } if (os_strcmp(var, "roaming_consortium") == 0) { if (len < 3 || len > sizeof(cred->roaming_consortium)) { wpa_printf(MSG_ERROR, "Line %d: invalid " "roaming_consortium length %d (3..15 " "expected)", line, (int) len); os_free(val); return -1; } os_memcpy(cred->roaming_consortium, val, len); cred->roaming_consortium_len = len; os_free(val); return 0; } if (os_strcmp(var, "required_roaming_consortium") == 0) { if (len < 3 || len > sizeof(cred->required_roaming_consortium)) { wpa_printf(MSG_ERROR, "Line %d: invalid " "required_roaming_consortium length %d " "(3..15 expected)", line, (int) len); os_free(val); return -1; } os_memcpy(cred->required_roaming_consortium, val, len); cred->required_roaming_consortium_len = len; os_free(val); return 0; } if (os_strcmp(var, "excluded_ssid") == 0) { struct excluded_ssid *e; if (len > MAX_SSID_LEN) { wpa_printf(MSG_ERROR, "Line %d: invalid " "excluded_ssid length %d", line, (int) len); os_free(val); return -1; } e = os_realloc_array(cred->excluded_ssid, cred->num_excluded_ssid + 1, sizeof(struct excluded_ssid)); if (e == NULL) { os_free(val); return -1; } cred->excluded_ssid = e; e = &cred->excluded_ssid[cred->num_excluded_ssid++]; os_memcpy(e->ssid, val, len); e->ssid_len = len; os_free(val); return 0; } if (os_strcmp(var, "roaming_partner") == 0) { struct roaming_partner *p; char *pos; p = os_realloc_array(cred->roaming_partner, cred->num_roaming_partner + 1, sizeof(struct roaming_partner)); if (p == NULL) { os_free(val); return -1; } cred->roaming_partner = p; p = &cred->roaming_partner[cred->num_roaming_partner]; pos = os_strchr(val, ','); if (pos == NULL) { os_free(val); return -1; } *pos++ = '\0'; if (pos - val - 1 >= (int) sizeof(p->fqdn)) { os_free(val); return -1; } os_memcpy(p->fqdn, val, pos - val); p->exact_match = atoi(pos); pos = os_strchr(pos, ','); if (pos == NULL) { os_free(val); return -1; } *pos++ = '\0'; p->priority = atoi(pos); pos = os_strchr(pos, ','); if (pos == NULL) { os_free(val); return -1; } *pos++ = '\0'; if (os_strlen(pos) >= sizeof(p->country)) { os_free(val); return -1; } os_memcpy(p->country, pos, os_strlen(pos) + 1); cred->num_roaming_partner++; os_free(val); return 0; } if (os_strcmp(var, "provisioning_sp") == 0) { os_free(cred->provisioning_sp); cred->provisioning_sp = val; return 0; } if (line) { wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.", line, var); } os_free(val); return -1; } char * alloc_int_str(int val) { char *buf; buf = os_malloc(20); if (buf == NULL) return NULL; os_snprintf(buf, 20, "%d", val); return buf; } char * alloc_strdup(const char *str) { if (str == NULL) return NULL; return os_strdup(str); } char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var) { if (os_strcmp(var, "temporary") == 0) return alloc_int_str(cred->temporary); if (os_strcmp(var, "priority") == 0) return alloc_int_str(cred->priority); if (os_strcmp(var, "sp_priority") == 0) return alloc_int_str(cred->sp_priority); if (os_strcmp(var, "pcsc") == 0) return alloc_int_str(cred->pcsc); if (os_strcmp(var, "eap") == 0) { if (!cred->eap_method) return NULL; return alloc_strdup(eap_get_name(cred->eap_method[0].vendor, cred->eap_method[0].method)); } if (os_strcmp(var, "update_identifier") == 0) return alloc_int_str(cred->update_identifier); if (os_strcmp(var, "min_dl_bandwidth_home") == 0) return alloc_int_str(cred->min_dl_bandwidth_home); if (os_strcmp(var, "min_ul_bandwidth_home") == 0) return alloc_int_str(cred->min_ul_bandwidth_home); if (os_strcmp(var, "min_dl_bandwidth_roaming") == 0) return alloc_int_str(cred->min_dl_bandwidth_roaming); if (os_strcmp(var, "min_ul_bandwidth_roaming") == 0) return alloc_int_str(cred->min_ul_bandwidth_roaming); if (os_strcmp(var, "max_bss_load") == 0) return alloc_int_str(cred->max_bss_load); if (os_strcmp(var, "req_conn_capab") == 0) { unsigned int i; char *buf, *end, *pos; int ret; if (!cred->num_req_conn_capab) return NULL; buf = os_malloc(4000); if (buf == NULL) return NULL; pos = buf; end = pos + 4000; for (i = 0; i < cred->num_req_conn_capab; i++) { int *ports; ret = os_snprintf(pos, end - pos, "%s%u", i > 0 ? "\n" : "", cred->req_conn_capab_proto[i]); if (ret < 0 || ret >= end - pos) return buf; pos += ret; ports = cred->req_conn_capab_port[i]; if (ports) { int j; for (j = 0; ports[j] != -1; j++) { ret = os_snprintf(pos, end - pos, "%s%d", j > 0 ? "," : ":", ports[j]); if (ret < 0 || ret >= end - pos) return buf; pos += ret; } } } return buf; } if (os_strcmp(var, "ocsp") == 0) return alloc_int_str(cred->ocsp); if (os_strcmp(var, "realm") == 0) return alloc_strdup(cred->realm); if (os_strcmp(var, "username") == 0) return alloc_strdup(cred->username); if (os_strcmp(var, "password") == 0) { if (!cred->password) return NULL; return alloc_strdup("*"); } if (os_strcmp(var, "ca_cert") == 0) return alloc_strdup(cred->ca_cert); if (os_strcmp(var, "client_cert") == 0) return alloc_strdup(cred->client_cert); if (os_strcmp(var, "private_key") == 0) return alloc_strdup(cred->private_key); if (os_strcmp(var, "private_key_passwd") == 0) { if (!cred->private_key_passwd) return NULL; return alloc_strdup("*"); } if (os_strcmp(var, "imsi") == 0) return alloc_strdup(cred->imsi); if (os_strcmp(var, "milenage") == 0) { if (!(cred->milenage)) return NULL; return alloc_strdup("*"); } if (os_strcmp(var, "domain_suffix_match") == 0) return alloc_strdup(cred->domain_suffix_match); if (os_strcmp(var, "domain") == 0) { unsigned int i; char *buf, *end, *pos; int ret; if (!cred->num_domain) return NULL; buf = os_malloc(4000); if (buf == NULL) return NULL; pos = buf; end = pos + 4000; for (i = 0; i < cred->num_domain; i++) { ret = os_snprintf(pos, end - pos, "%s%s", i > 0 ? "\n" : "", cred->domain[i]); if (ret < 0 || ret >= end - pos) return buf; pos += ret; } return buf; } if (os_strcmp(var, "phase1") == 0) return alloc_strdup(cred->phase1); if (os_strcmp(var, "phase2") == 0) return alloc_strdup(cred->phase2); if (os_strcmp(var, "roaming_consortium") == 0) { size_t buflen; char *buf; if (!cred->roaming_consortium_len) return NULL; buflen = cred->roaming_consortium_len * 2 + 1; buf = os_malloc(buflen); if (buf == NULL) return NULL; wpa_snprintf_hex(buf, buflen, cred->roaming_consortium, cred->roaming_consortium_len); return buf; } if (os_strcmp(var, "required_roaming_consortium") == 0) { size_t buflen; char *buf; if (!cred->required_roaming_consortium_len) return NULL; buflen = cred->required_roaming_consortium_len * 2 + 1; buf = os_malloc(buflen); if (buf == NULL) return NULL; wpa_snprintf_hex(buf, buflen, cred->required_roaming_consortium, cred->required_roaming_consortium_len); return buf; } if (os_strcmp(var, "excluded_ssid") == 0) { unsigned int i; char *buf, *end, *pos; if (!cred->num_excluded_ssid) return NULL; buf = os_malloc(4000); if (buf == NULL) return NULL; pos = buf; end = pos + 4000; for (i = 0; i < cred->num_excluded_ssid; i++) { struct excluded_ssid *e; int ret; e = &cred->excluded_ssid[i]; ret = os_snprintf(pos, end - pos, "%s%s", i > 0 ? "\n" : "", wpa_ssid_txt(e->ssid, e->ssid_len)); if (ret < 0 || ret >= end - pos) return buf; pos += ret; } return buf; } if (os_strcmp(var, "roaming_partner") == 0) { unsigned int i; char *buf, *end, *pos; if (!cred->num_roaming_partner) return NULL; buf = os_malloc(4000); if (buf == NULL) return NULL; pos = buf; end = pos + 4000; for (i = 0; i < cred->num_roaming_partner; i++) { struct roaming_partner *p; int ret; p = &cred->roaming_partner[i]; ret = os_snprintf(pos, end - pos, "%s%s,%d,%u,%s", i > 0 ? "\n" : "", p->fqdn, p->exact_match, p->priority, p->country); if (ret < 0 || ret >= end - pos) return buf; pos += ret; } return buf; } if (os_strcmp(var, "provisioning_sp") == 0) return alloc_strdup(cred->provisioning_sp); return NULL; } struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id) { struct wpa_cred *cred; cred = config->cred; while (cred) { if (id == cred->id) break; cred = cred->next; } return cred; } struct wpa_cred * wpa_config_add_cred(struct wpa_config *config) { int id; struct wpa_cred *cred, *last = NULL; id = -1; cred = config->cred; while (cred) { if (cred->id > id) id = cred->id; last = cred; cred = cred->next; } id++; cred = os_zalloc(sizeof(*cred)); if (cred == NULL) return NULL; cred->id = id; cred->sim_num = DEFAULT_USER_SELECTED_SIM; if (last) last->next = cred; else config->cred = cred; return cred; } int wpa_config_remove_cred(struct wpa_config *config, int id) { struct wpa_cred *cred, *prev = NULL; cred = config->cred; while (cred) { if (id == cred->id) break; prev = cred; cred = cred->next; } if (cred == NULL) return -1; if (prev) prev->next = cred->next; else config->cred = cred->next; wpa_config_free_cred(cred); return 0; } #ifndef CONFIG_NO_CONFIG_BLOBS /** * wpa_config_get_blob - Get a named configuration blob * @config: Configuration data from wpa_config_read() * @name: Name of the blob * Returns: Pointer to blob data or %NULL if not found */ const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config, const char *name) { struct wpa_config_blob *blob = config->blobs; while (blob) { if (os_strcmp(blob->name, name) == 0) return blob; blob = blob->next; } return NULL; } /** * wpa_config_set_blob - Set or add a named configuration blob * @config: Configuration data from wpa_config_read() * @blob: New value for the blob * * Adds a new configuration blob or replaces the current value of an existing * blob. */ void wpa_config_set_blob(struct wpa_config *config, struct wpa_config_blob *blob) { wpa_config_remove_blob(config, blob->name); blob->next = config->blobs; config->blobs = blob; } /** * wpa_config_free_blob - Free blob data * @blob: Pointer to blob to be freed */ void wpa_config_free_blob(struct wpa_config_blob *blob) { if (blob) { os_free(blob->name); os_free(blob->data); os_free(blob); } } /** * wpa_config_remove_blob - Remove a named configuration blob * @config: Configuration data from wpa_config_read() * @name: Name of the blob to remove * Returns: 0 if blob was removed or -1 if blob was not found */ int wpa_config_remove_blob(struct wpa_config *config, const char *name) { struct wpa_config_blob *pos = config->blobs, *prev = NULL; while (pos) { if (os_strcmp(pos->name, name) == 0) { if (prev) prev->next = pos->next; else config->blobs = pos->next; wpa_config_free_blob(pos); return 0; } prev = pos; pos = pos->next; } return -1; } #endif /* CONFIG_NO_CONFIG_BLOBS */ /** * wpa_config_alloc_empty - Allocate an empty configuration * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain * socket * @driver_param: Driver parameters * Returns: Pointer to allocated configuration data or %NULL on failure */ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, const char *driver_param) { struct wpa_config *config; const int aCWmin = 4, aCWmax = 10; const struct hostapd_wmm_ac_params ac_bk = { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */ const struct hostapd_wmm_ac_params ac_be = { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */ const struct hostapd_wmm_ac_params ac_vi = /* video traffic */ { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 }; const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */ { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 }; config = os_zalloc(sizeof(*config)); if (config == NULL) return NULL; config->eapol_version = DEFAULT_EAPOL_VERSION; config->ap_scan = DEFAULT_AP_SCAN; config->fast_reauth = DEFAULT_FAST_REAUTH; config->p2p_go_intent = DEFAULT_P2P_GO_INTENT; config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS; config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY; config->bss_max_count = DEFAULT_BSS_MAX_COUNT; config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE; config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT; config->max_num_sta = DEFAULT_MAX_NUM_STA; config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE; config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ; config->wmm_ac_params[0] = ac_be; config->wmm_ac_params[1] = ac_bk; config->wmm_ac_params[2] = ac_vi; config->wmm_ac_params[3] = ac_vo; if (ctrl_interface) config->ctrl_interface = os_strdup(ctrl_interface); if (driver_param) config->driver_param = os_strdup(driver_param); return config; } #ifndef CONFIG_NO_STDOUT_DEBUG /** * wpa_config_debug_dump_networks - Debug dump of configured networks * @config: Configuration data from wpa_config_read() */ void wpa_config_debug_dump_networks(struct wpa_config *config) { int prio; struct wpa_ssid *ssid; for (prio = 0; prio < config->num_prio; prio++) { ssid = config->pssid[prio]; wpa_printf(MSG_DEBUG, "Priority group %d", ssid->priority); while (ssid) { wpa_printf(MSG_DEBUG, " id=%d ssid='%s'", ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); ssid = ssid->pnext; } } } #endif /* CONFIG_NO_STDOUT_DEBUG */ struct global_parse_data { char *name; int (*parser)(const struct global_parse_data *data, struct wpa_config *config, int line, const char *value); void *param1, *param2, *param3; unsigned int changed_flag; }; static int wpa_global_config_parse_int(const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { int val, *dst; char *end; dst = (int *) (((u8 *) config) + (long) data->param1); val = strtol(pos, &end, 0); if (*end) { wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"", line, pos); return -1; } *dst = val; wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst); if (data->param2 && *dst < (long) data->param2) { wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d " "min_value=%ld)", line, data->name, *dst, (long) data->param2); *dst = (long) data->param2; return -1; } if (data->param3 && *dst > (long) data->param3) { wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d " "max_value=%ld)", line, data->name, *dst, (long) data->param3); *dst = (long) data->param3; return -1; } return 0; } static int wpa_global_config_parse_str(const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { size_t len; char **dst, *tmp; len = os_strlen(pos); if (data->param2 && len < (size_t) data->param2) { wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu " "min_len=%ld)", line, data->name, (unsigned long) len, (long) data->param2); return -1; } if (data->param3 && len > (size_t) data->param3) { wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu " "max_len=%ld)", line, data->name, (unsigned long) len, (long) data->param3); return -1; } tmp = os_strdup(pos); if (tmp == NULL) return -1; dst = (char **) (((u8 *) config) + (long) data->param1); os_free(*dst); *dst = tmp; wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst); return 0; } static int wpa_config_process_bgscan(const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { size_t len; char *tmp; int res; tmp = wpa_config_parse_string(pos, &len); if (tmp == NULL) { wpa_printf(MSG_ERROR, "Line %d: failed to parse %s", line, data->name); return -1; } res = wpa_global_config_parse_str(data, config, line, tmp); os_free(tmp); return res; } static int wpa_global_config_parse_bin(const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { size_t len; struct wpabuf **dst, *tmp; len = os_strlen(pos); if (len & 0x01) return -1; tmp = wpabuf_alloc(len / 2); if (tmp == NULL) return -1; if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) { wpabuf_free(tmp); return -1; } dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1); wpabuf_free(*dst); *dst = tmp; wpa_printf(MSG_DEBUG, "%s", data->name); return 0; } static int wpa_config_process_freq_list(const struct global_parse_data *data, struct wpa_config *config, int line, const char *value) { int *freqs; freqs = wpa_config_parse_int_array(value); if (freqs == NULL) return -1; if (freqs[0] == 0) { os_free(freqs); freqs = NULL; } os_free(config->freq_list); config->freq_list = freqs; return 0; } #ifdef CONFIG_P2P static int wpa_global_config_parse_ipv4(const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { u32 *dst; struct hostapd_ip_addr addr; if (hostapd_parse_ip_addr(pos, &addr) < 0) return -1; if (addr.af != AF_INET) return -1; dst = (u32 *) (((u8 *) config) + (long) data->param1); os_memcpy(dst, &addr.u.v4.s_addr, 4); wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name, WPA_GET_BE32((u8 *) dst)); return 0; } #endif /* CONFIG_P2P */ static int wpa_config_process_country(const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { if (!pos[0] || !pos[1]) { wpa_printf(MSG_DEBUG, "Invalid country set"); return -1; } config->country[0] = pos[0]; config->country[1] = pos[1]; wpa_printf(MSG_DEBUG, "country='%c%c'", config->country[0], config->country[1]); return 0; } static int wpa_config_process_load_dynamic_eap( const struct global_parse_data *data, struct wpa_config *config, int line, const char *so) { int ret; wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so); ret = eap_peer_method_load(so); if (ret == -2) { wpa_printf(MSG_DEBUG, "This EAP type was already loaded - not " "reloading."); } else if (ret) { wpa_printf(MSG_ERROR, "Line %d: Failed to load dynamic EAP " "method '%s'.", line, so); return -1; } return 0; } #ifdef CONFIG_WPS static int wpa_config_process_uuid(const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { char buf[40]; if (uuid_str2bin(pos, config->uuid)) { wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line); return -1; } uuid_bin2str(config->uuid, buf, sizeof(buf)); wpa_printf(MSG_DEBUG, "uuid=%s", buf); return 0; } static int wpa_config_process_device_type( const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { return wps_dev_type_str2bin(pos, config->device_type); } static int wpa_config_process_os_version(const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { if (hexstr2bin(pos, config->os_version, 4)) { wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line); return -1; } wpa_printf(MSG_DEBUG, "os_version=%08x", WPA_GET_BE32(config->os_version)); return 0; } static int wpa_config_process_wps_vendor_ext_m1( const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { struct wpabuf *tmp; int len = os_strlen(pos) / 2; u8 *p; if (!len) { wpa_printf(MSG_ERROR, "Line %d: " "invalid wps_vendor_ext_m1", line); return -1; } tmp = wpabuf_alloc(len); if (tmp) { p = wpabuf_put(tmp, len); if (hexstr2bin(pos, p, len)) { wpa_printf(MSG_ERROR, "Line %d: " "invalid wps_vendor_ext_m1", line); wpabuf_free(tmp); return -1; } wpabuf_free(config->wps_vendor_ext_m1); config->wps_vendor_ext_m1 = tmp; } else { wpa_printf(MSG_ERROR, "Can not allocate " "memory for wps_vendor_ext_m1"); return -1; } return 0; } #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P static int wpa_config_process_sec_device_type( const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { int idx; if (config->num_sec_device_types >= MAX_SEC_DEVICE_TYPES) { wpa_printf(MSG_ERROR, "Line %d: too many sec_device_type " "items", line); return -1; } idx = config->num_sec_device_types; if (wps_dev_type_str2bin(pos, config->sec_device_type[idx])) return -1; config->num_sec_device_types++; return 0; } static int wpa_config_process_p2p_pref_chan( const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { struct p2p_channel *pref = NULL, *n; unsigned int num = 0; const char *pos2; u8 op_class, chan; /* format: class:chan,class:chan,... */ while (*pos) { op_class = atoi(pos); pos2 = os_strchr(pos, ':'); if (pos2 == NULL) goto fail; pos2++; chan = atoi(pos2); n = os_realloc_array(pref, num + 1, sizeof(struct p2p_channel)); if (n == NULL) goto fail; pref = n; pref[num].op_class = op_class; pref[num].chan = chan; num++; pos = os_strchr(pos2, ','); if (pos == NULL) break; pos++; } os_free(config->p2p_pref_chan); config->p2p_pref_chan = pref; config->num_p2p_pref_chan = num; wpa_hexdump(MSG_DEBUG, "P2P: Preferred class/channel pairs", (u8 *) config->p2p_pref_chan, config->num_p2p_pref_chan * sizeof(struct p2p_channel)); return 0; fail: os_free(pref); wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line); return -1; } static int wpa_config_process_p2p_no_go_freq( const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { int ret; ret = freq_range_list_parse(&config->p2p_no_go_freq, pos); if (ret < 0) { wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_no_go_freq", line); return -1; } wpa_printf(MSG_DEBUG, "P2P: p2p_no_go_freq with %u items", config->p2p_no_go_freq.num); return 0; } #endif /* CONFIG_P2P */ static int wpa_config_process_hessid( const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { if (hwaddr_aton2(pos, config->hessid) < 0) { wpa_printf(MSG_ERROR, "Line %d: Invalid hessid '%s'", line, pos); return -1; } return 0; } static int wpa_config_process_sae_groups( const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { int *groups = wpa_config_parse_int_array(pos); if (groups == NULL) { wpa_printf(MSG_ERROR, "Line %d: Invalid sae_groups '%s'", line, pos); return -1; } os_free(config->sae_groups); config->sae_groups = groups; return 0; } static int wpa_config_process_ap_vendor_elements( const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { struct wpabuf *tmp; int len = os_strlen(pos) / 2; u8 *p; if (!len) { wpa_printf(MSG_ERROR, "Line %d: invalid ap_vendor_elements", line); return -1; } tmp = wpabuf_alloc(len); if (tmp) { p = wpabuf_put(tmp, len); if (hexstr2bin(pos, p, len)) { wpa_printf(MSG_ERROR, "Line %d: invalid " "ap_vendor_elements", line); wpabuf_free(tmp); return -1; } wpabuf_free(config->ap_vendor_elements); config->ap_vendor_elements = tmp; } else { wpa_printf(MSG_ERROR, "Cannot allocate memory for " "ap_vendor_elements"); return -1; } return 0; } #ifdef CONFIG_CTRL_IFACE static int wpa_config_process_no_ctrl_interface( const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { wpa_printf(MSG_DEBUG, "no_ctrl_interface -> ctrl_interface=NULL"); os_free(config->ctrl_interface); config->ctrl_interface = NULL; return 0; } #endif /* CONFIG_CTRL_IFACE */ #ifdef OFFSET #undef OFFSET #endif /* OFFSET */ /* OFFSET: Get offset of a variable within the wpa_config structure */ #define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v) #define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL #define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL #define _INT(f) #f, wpa_global_config_parse_int, OFFSET(f) #define INT(f) _INT(f), NULL, NULL #define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max #define _STR(f) #f, wpa_global_config_parse_str, OFFSET(f) #define STR(f) _STR(f), NULL, NULL #define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max #define BIN(f) #f, wpa_global_config_parse_bin, OFFSET(f), NULL, NULL #define IPV4(f) #f, wpa_global_config_parse_ipv4, OFFSET(f), NULL, NULL static const struct global_parse_data global_fields[] = { #ifdef CONFIG_CTRL_IFACE { STR(ctrl_interface), 0 }, { FUNC_NO_VAR(no_ctrl_interface), 0 }, { STR(ctrl_interface_group), 0 } /* deprecated */, #endif /* CONFIG_CTRL_IFACE */ #ifdef CONFIG_MACSEC { INT_RANGE(eapol_version, 1, 3), 0 }, #else /* CONFIG_MACSEC */ { INT_RANGE(eapol_version, 1, 2), 0 }, #endif /* CONFIG_MACSEC */ { INT(ap_scan), 0 }, { FUNC(bgscan), 0 }, { INT(disable_scan_offload), 0 }, { INT(fast_reauth), 0 }, { STR(opensc_engine_path), 0 }, { STR(pkcs11_engine_path), 0 }, { STR(pkcs11_module_path), 0 }, { STR(pcsc_reader), 0 }, { STR(pcsc_pin), 0 }, { INT(external_sim), 0 }, { STR(driver_param), 0 }, { INT(dot11RSNAConfigPMKLifetime), 0 }, { INT(dot11RSNAConfigPMKReauthThreshold), 0 }, { INT(dot11RSNAConfigSATimeout), 0 }, #ifndef CONFIG_NO_CONFIG_WRITE { INT(update_config), 0 }, #endif /* CONFIG_NO_CONFIG_WRITE */ { FUNC_NO_VAR(load_dynamic_eap), 0 }, #ifdef CONFIG_WPS { FUNC(uuid), CFG_CHANGED_UUID }, { STR_RANGE(device_name, 0, 32), CFG_CHANGED_DEVICE_NAME }, { STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING }, { STR_RANGE(model_name, 0, 32), CFG_CHANGED_WPS_STRING }, { STR_RANGE(model_number, 0, 32), CFG_CHANGED_WPS_STRING }, { STR_RANGE(serial_number, 0, 32), CFG_CHANGED_WPS_STRING }, { FUNC(device_type), CFG_CHANGED_DEVICE_TYPE }, { FUNC(os_version), CFG_CHANGED_OS_VERSION }, { STR(config_methods), CFG_CHANGED_CONFIG_METHODS }, { INT_RANGE(wps_cred_processing, 0, 2), 0 }, { FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION }, #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P { FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE }, { INT(p2p_listen_reg_class), 0 }, { INT(p2p_listen_channel), 0 }, { INT(p2p_oper_reg_class), CFG_CHANGED_P2P_OPER_CHANNEL }, { INT(p2p_oper_channel), CFG_CHANGED_P2P_OPER_CHANNEL }, { INT_RANGE(p2p_go_intent, 0, 15), 0 }, { STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX }, { INT_RANGE(persistent_reconnect, 0, 1), 0 }, { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS }, { INT(p2p_group_idle), 0 }, { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN }, { FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN }, { INT_RANGE(p2p_add_cli_chan, 0, 1), 0 }, { INT(p2p_go_ht40), 0 }, { INT(p2p_go_vht), 0 }, { INT(p2p_disabled), 0 }, { INT(p2p_no_group_iface), 0 }, { INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 }, { IPV4(ip_addr_go), 0 }, { IPV4(ip_addr_mask), 0 }, { IPV4(ip_addr_start), 0 }, { IPV4(ip_addr_end), 0 }, #endif /* CONFIG_P2P */ { FUNC(country), CFG_CHANGED_COUNTRY }, { INT(bss_max_count), 0 }, { INT(bss_expiration_age), 0 }, { INT(bss_expiration_scan_count), 0 }, { INT_RANGE(filter_ssids, 0, 1), 0 }, { INT_RANGE(filter_rssi, -100, 0), 0 }, { INT(max_num_sta), 0 }, { INT_RANGE(disassoc_low_ack, 0, 1), 0 }, #ifdef CONFIG_HS20 { INT_RANGE(hs20, 0, 1), 0 }, #endif /* CONFIG_HS20 */ { INT_RANGE(interworking, 0, 1), 0 }, { FUNC(hessid), 0 }, { INT_RANGE(access_network_type, 0, 15), 0 }, { INT_RANGE(pbc_in_m1, 0, 1), 0 }, { STR(autoscan), 0 }, { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), CFG_CHANGED_NFC_PASSWORD_TOKEN }, { BIN(wps_nfc_dh_pubkey), CFG_CHANGED_NFC_PASSWORD_TOKEN }, { BIN(wps_nfc_dh_privkey), CFG_CHANGED_NFC_PASSWORD_TOKEN }, { BIN(wps_nfc_dev_pw), CFG_CHANGED_NFC_PASSWORD_TOKEN }, { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND }, { INT(p2p_go_max_inactivity), 0 }, { INT_RANGE(auto_interworking, 0, 1), 0 }, { INT(okc), 0 }, { INT(pmf), 0 }, { FUNC(sae_groups), 0 }, { INT(dtim_period), 0 }, { INT(beacon_int), 0 }, { FUNC(ap_vendor_elements), 0 }, { INT_RANGE(ignore_old_scan_res, 0, 1), 0 }, { FUNC(freq_list), 0 }, { INT(scan_cur_freq), 0 }, { INT(sched_scan_interval), 0 }, { INT(tdls_external_control), 0}, { STR(osu_dir), 0 }, { STR(wowlan_triggers), 0 }, }; #undef FUNC #undef _INT #undef INT #undef INT_RANGE #undef _STR #undef STR #undef STR_RANGE #undef BIN #undef IPV4 #define NUM_GLOBAL_FIELDS ARRAY_SIZE(global_fields) int wpa_config_process_global(struct wpa_config *config, char *pos, int line) { size_t i; int ret = 0; for (i = 0; i < NUM_GLOBAL_FIELDS; i++) { const struct global_parse_data *field = &global_fields[i]; size_t flen = os_strlen(field->name); if (os_strncmp(pos, field->name, flen) != 0 || pos[flen] != '=') continue; if (field->parser(field, config, line, pos + flen + 1)) { wpa_printf(MSG_ERROR, "Line %d: failed to " "parse '%s'.", line, pos); ret = -1; } if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN) config->wps_nfc_pw_from_config = 1; config->changed_parameters |= field->changed_flag; break; } if (i == NUM_GLOBAL_FIELDS) { #ifdef CONFIG_AP if (os_strncmp(pos, "wmm_ac_", 7) == 0) { char *tmp = os_strchr(pos, '='); if (tmp == NULL) { if (line < 0) return -1; wpa_printf(MSG_ERROR, "Line %d: invalid line " "'%s'", line, pos); return -1; } *tmp++ = '\0'; if (hostapd_config_wmm_ac(config->wmm_ac_params, pos, tmp)) { wpa_printf(MSG_ERROR, "Line %d: invalid WMM " "AC item", line); return -1; } } #endif /* CONFIG_AP */ if (line < 0) return -1; wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.", line, pos); ret = -1; } return ret; } wpa_supplicant-2.2/wpa_supplicant/events.c0000664000175000017500000027137612343617166016740 0ustar jmjm/* * WPA Supplicant - Driver event processing * Copyright (c) 2003-2014, 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 "eapol_supp/eapol_supp_sm.h" #include "rsn_supp/wpa.h" #include "eloop.h" #include "config.h" #include "l2_packet/l2_packet.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "pcsc_funcs.h" #include "rsn_supp/preauth.h" #include "rsn_supp/pmksa_cache.h" #include "common/wpa_ctrl.h" #include "eap_peer/eap.h" #include "ap/hostapd.h" #include "p2p/p2p.h" #include "wnm_sta.h" #include "notify.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "crypto/random.h" #include "blacklist.h" #include "wpas_glue.h" #include "wps_supplicant.h" #include "ibss_rsn.h" #include "sme.h" #include "gas_query.h" #include "p2p_supplicant.h" #include "bgscan.h" #include "autoscan.h" #include "ap.h" #include "bss.h" #include "scan.h" #include "offchannel.h" #include "interworking.h" #ifndef CONFIG_NO_SCAN_PROCESSING static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, int new_scan, int own_request); #endif /* CONFIG_NO_SCAN_PROCESSING */ static int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct os_reltime now; if (ssid == NULL || ssid->disabled_until.sec == 0) return 0; os_get_reltime(&now); if (ssid->disabled_until.sec > now.sec) return ssid->disabled_until.sec - now.sec; wpas_clear_temp_disabled(wpa_s, ssid, 0); return 0; } static struct wpa_bss * wpa_supplicant_get_new_bss( struct wpa_supplicant *wpa_s, const u8 *bssid) { struct wpa_bss *bss = NULL; struct wpa_ssid *ssid = wpa_s->current_ssid; if (ssid->ssid_len > 0) bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len); if (!bss) bss = wpa_bss_get_bssid(wpa_s, bssid); return bss; } static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid, *old_ssid; struct wpa_bss *bss; int res; if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid) return 0; wpa_dbg(wpa_s, MSG_DEBUG, "Select network based on association " "information"); ssid = wpa_supplicant_get_ssid(wpa_s); if (ssid == NULL) { wpa_msg(wpa_s, MSG_INFO, "No network configuration found for the current AP"); return -1; } if (wpas_network_disabled(wpa_s, ssid)) { wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is disabled"); return -1; } if (disallowed_bssid(wpa_s, wpa_s->bssid) || disallowed_ssid(wpa_s, ssid->ssid, ssid->ssid_len)) { wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS is disallowed"); return -1; } res = wpas_temp_disabled(wpa_s, ssid); if (res > 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is temporarily " "disabled for %d second(s)", res); return -1; } wpa_dbg(wpa_s, MSG_DEBUG, "Network configuration found for the " "current AP"); if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) { u8 wpa_ie[80]; size_t wpa_ie_len = sizeof(wpa_ie); if (wpa_supplicant_set_suites(wpa_s, NULL, ssid, wpa_ie, &wpa_ie_len) < 0) wpa_dbg(wpa_s, MSG_DEBUG, "Could not set WPA suites"); } else { wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); } if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) eapol_sm_invalidate_cached_session(wpa_s->eapol); old_ssid = wpa_s->current_ssid; wpa_s->current_ssid = ssid; bss = wpa_supplicant_get_new_bss(wpa_s, wpa_s->bssid); if (!bss) { wpa_supplicant_update_scan_results(wpa_s); /* Get the BSS from the new scan results */ bss = wpa_supplicant_get_new_bss(wpa_s, wpa_s->bssid); } if (bss) wpa_s->current_bss = bss; wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); wpa_supplicant_initiate_eapol(wpa_s); if (old_ssid != wpa_s->current_ssid) wpas_notify_network_changed(wpa_s); return 0; } void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; if (wpa_s->countermeasures) { wpa_s->countermeasures = 0; wpa_drv_set_countermeasures(wpa_s, 0); wpa_msg(wpa_s, MSG_INFO, "WPA: TKIP countermeasures stopped"); wpa_supplicant_req_scan(wpa_s, 0, 0); } } void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) { int bssid_changed; wnm_bss_keep_alive_deinit(wpa_s); #ifdef CONFIG_IBSS_RSN ibss_rsn_deinit(wpa_s->ibss_rsn); wpa_s->ibss_rsn = NULL; #endif /* CONFIG_IBSS_RSN */ #ifdef CONFIG_AP wpa_supplicant_ap_deinit(wpa_s); #endif /* CONFIG_AP */ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) return; wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); bssid_changed = !is_zero_ether_addr(wpa_s->bssid); os_memset(wpa_s->bssid, 0, ETH_ALEN); os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); #ifdef CONFIG_SME wpa_s->sme.prev_bssid_set = 0; #endif /* CONFIG_SME */ #ifdef CONFIG_P2P os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN); #endif /* CONFIG_P2P */ wpa_s->current_bss = NULL; wpa_s->assoc_freq = 0; #ifdef CONFIG_IEEE80211R #ifdef CONFIG_SME if (wpa_s->sme.ft_ies) sme_update_ft_ies(wpa_s, NULL, NULL, 0); #endif /* CONFIG_SME */ #endif /* CONFIG_IEEE80211R */ if (bssid_changed) wpas_notify_bssid_changed(wpa_s); eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE); eapol_sm_notify_portValid(wpa_s->eapol, FALSE); if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); wpa_s->ap_ies_from_associnfo = 0; wpa_s->current_ssid = NULL; eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_s->key_mgmt = 0; } static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s) { struct wpa_ie_data ie; int pmksa_set = -1; size_t i; if (wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0 || ie.pmkid == NULL) return; for (i = 0; i < ie.num_pmkid; i++) { pmksa_set = pmksa_cache_set_current(wpa_s->wpa, ie.pmkid + i * PMKID_LEN, NULL, NULL, 0); if (pmksa_set == 0) { eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1); break; } } wpa_dbg(wpa_s, MSG_DEBUG, "RSN: PMKID from assoc IE %sfound from " "PMKSA cache", pmksa_set == 0 ? "" : "not "); } static void wpa_supplicant_event_pmkid_candidate(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { if (data == NULL) { wpa_dbg(wpa_s, MSG_DEBUG, "RSN: No data in PMKID candidate " "event"); return; } wpa_dbg(wpa_s, MSG_DEBUG, "RSN: PMKID candidate event - bssid=" MACSTR " index=%d preauth=%d", MAC2STR(data->pmkid_candidate.bssid), data->pmkid_candidate.index, data->pmkid_candidate.preauth); pmksa_candidate_add(wpa_s->wpa, data->pmkid_candidate.bssid, data->pmkid_candidate.index, data->pmkid_candidate.preauth); } static int wpa_supplicant_dynamic_keys(struct wpa_supplicant *wpa_s) { if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) return 0; #ifdef IEEE8021X_EAPOL if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA && wpa_s->current_ssid && !(wpa_s->current_ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) { /* IEEE 802.1X, but not using dynamic WEP keys (i.e., either * plaintext or static WEP keys). */ return 0; } #endif /* IEEE8021X_EAPOL */ return 1; } /** * wpa_supplicant_scard_init - Initialize SIM/USIM access with PC/SC * @wpa_s: pointer to wpa_supplicant data * @ssid: Configuration data for the network * Returns: 0 on success, -1 on failure * * This function is called when starting authentication with a network that is * configured to use PC/SC for SIM/USIM access (EAP-SIM or EAP-AKA). */ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { #ifdef IEEE8021X_EAPOL #ifdef PCSC_FUNCS int aka = 0, sim = 0; if ((ssid != NULL && ssid->eap.pcsc == NULL) || wpa_s->scard != NULL || wpa_s->conf->external_sim) return 0; if (ssid == NULL || ssid->eap.eap_methods == NULL) { sim = 1; aka = 1; } else { struct eap_method_type *eap = ssid->eap.eap_methods; while (eap->vendor != EAP_VENDOR_IETF || eap->method != EAP_TYPE_NONE) { if (eap->vendor == EAP_VENDOR_IETF) { if (eap->method == EAP_TYPE_SIM) sim = 1; else if (eap->method == EAP_TYPE_AKA || eap->method == EAP_TYPE_AKA_PRIME) aka = 1; } eap++; } } if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_SIM) == NULL) sim = 0; if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA) == NULL && eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME) == NULL) aka = 0; if (!sim && !aka) { wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is configured to " "use SIM, but neither EAP-SIM nor EAP-AKA are " "enabled"); return 0; } wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is configured to use SIM " "(sim=%d aka=%d) - initialize PCSC", sim, aka); wpa_s->scard = scard_init(NULL); if (wpa_s->scard == NULL) { wpa_msg(wpa_s, MSG_WARNING, "Failed to initialize SIM " "(pcsc-lite)"); return -1; } wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard); eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard); #endif /* PCSC_FUNCS */ #endif /* IEEE8021X_EAPOL */ return 0; } #ifndef CONFIG_NO_SCAN_PROCESSING static int has_wep_key(struct wpa_ssid *ssid) { int i; for (i = 0; i < NUM_WEP_KEYS; i++) { if (ssid->wep_key_len[i]) return 1; } return 0; } static int wpa_supplicant_match_privacy(struct wpa_bss *bss, struct wpa_ssid *ssid) { int privacy = 0; if (ssid->mixed_cell) return 1; #ifdef CONFIG_WPS if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) return 1; #endif /* CONFIG_WPS */ if (has_wep_key(ssid)) privacy = 1; #ifdef IEEE8021X_EAPOL if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) privacy = 1; #endif /* IEEE8021X_EAPOL */ if (wpa_key_mgmt_wpa(ssid->key_mgmt)) privacy = 1; if (ssid->key_mgmt & WPA_KEY_MGMT_OSEN) privacy = 1; if (bss->caps & IEEE80211_CAP_PRIVACY) return privacy; return !privacy; } static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_bss *bss) { struct wpa_ie_data ie; int proto_match = 0; const u8 *rsn_ie, *wpa_ie; int ret; int wep_ok; ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss); if (ret >= 0) return ret; /* Allow TSN if local configuration accepts WEP use without WPA/WPA2 */ wep_ok = !wpa_key_mgmt_wpa(ssid->key_mgmt) && (((ssid->key_mgmt & WPA_KEY_MGMT_NONE) && ssid->wep_key_len[ssid->wep_tx_keyidx] > 0) || (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)); rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) { proto_match++; if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - parse " "failed"); break; } if (wep_ok && (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104))) { wpa_dbg(wpa_s, MSG_DEBUG, " selected based on TSN " "in RSN IE"); return 1; } if (!(ie.proto & ssid->proto)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - proto " "mismatch"); break; } if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - PTK " "cipher mismatch"); break; } if (!(ie.group_cipher & ssid->group_cipher)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - GTK " "cipher mismatch"); break; } if (!(ie.key_mgmt & ssid->key_mgmt)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - key mgmt " "mismatch"); break; } #ifdef CONFIG_IEEE80211W if (!(ie.capabilities & WPA_CAPABILITY_MFPC) && (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ? wpa_s->conf->pmf : ssid->ieee80211w) == MGMT_FRAME_PROTECTION_REQUIRED) { wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - no mgmt " "frame protection"); break; } #endif /* CONFIG_IEEE80211W */ wpa_dbg(wpa_s, MSG_DEBUG, " selected based on RSN IE"); return 1; } wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) { proto_match++; if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - parse " "failed"); break; } if (wep_ok && (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104))) { wpa_dbg(wpa_s, MSG_DEBUG, " selected based on TSN " "in WPA IE"); return 1; } if (!(ie.proto & ssid->proto)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - proto " "mismatch"); break; } if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - PTK " "cipher mismatch"); break; } if (!(ie.group_cipher & ssid->group_cipher)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - GTK " "cipher mismatch"); break; } if (!(ie.key_mgmt & ssid->key_mgmt)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - key mgmt " "mismatch"); break; } wpa_dbg(wpa_s, MSG_DEBUG, " selected based on WPA IE"); return 1; } if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && !wpa_ie && !rsn_ie) { wpa_dbg(wpa_s, MSG_DEBUG, " allow for non-WPA IEEE 802.1X"); return 1; } if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) && wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - no WPA/RSN proto match"); return 0; } if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE)) { wpa_dbg(wpa_s, MSG_DEBUG, " allow in OSEN"); return 1; } if (!wpa_key_mgmt_wpa(ssid->key_mgmt)) { wpa_dbg(wpa_s, MSG_DEBUG, " allow in non-WPA/WPA2"); return 1; } wpa_dbg(wpa_s, MSG_DEBUG, " reject due to mismatch with " "WPA/WPA2"); return 0; } static int freq_allowed(int *freqs, int freq) { int i; if (freqs == NULL) return 1; for (i = 0; freqs[i]; i++) if (freqs[i] == freq) return 1; return 0; } static int ht_supported(const struct hostapd_hw_modes *mode) { if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) { /* * The driver did not indicate whether it supports HT. Assume * it does to avoid connection issues. */ return 1; } /* * IEEE Std 802.11n-2009 20.1.1: * An HT non-AP STA shall support all EQM rates for one spatial stream. */ return mode->mcs_set[0] == 0xff; } static int vht_supported(const struct hostapd_hw_modes *mode) { if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) { /* * The driver did not indicate whether it supports VHT. Assume * it does to avoid connection issues. */ return 1; } /* * A VHT non-AP STA shall support MCS 0-7 for one spatial stream. * TODO: Verify if this complies with the standard */ return (mode->vht_mcs_set[0] & 0x3) != 3; } static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { const struct hostapd_hw_modes *mode = NULL, *modes; const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES }; const u8 *rate_ie; int i, j, k; if (bss->freq == 0) return 1; /* Cannot do matching without knowing band */ modes = wpa_s->hw.modes; if (modes == NULL) { /* * The driver does not provide any additional information * about the utilized hardware, so allow the connection attempt * to continue. */ return 1; } for (i = 0; i < wpa_s->hw.num_modes; i++) { for (j = 0; j < modes[i].num_channels; j++) { int freq = modes[i].channels[j].freq; if (freq == bss->freq) { if (mode && mode->mode == HOSTAPD_MODE_IEEE80211G) break; /* do not allow 802.11b replace * 802.11g */ mode = &modes[i]; break; } } } if (mode == NULL) return 0; for (i = 0; i < (int) sizeof(scan_ie); i++) { rate_ie = wpa_bss_get_ie(bss, scan_ie[i]); if (rate_ie == NULL) continue; for (j = 2; j < rate_ie[1] + 2; j++) { int flagged = !!(rate_ie[j] & 0x80); int r = (rate_ie[j] & 0x7f) * 5; /* * IEEE Std 802.11n-2009 7.3.2.2: * The new BSS Membership selector value is encoded * like a legacy basic rate, but it is not a rate and * only indicates if the BSS members are required to * support the mandatory features of Clause 20 [HT PHY] * in order to join the BSS. */ if (flagged && ((rate_ie[j] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY)) { if (!ht_supported(mode)) { wpa_dbg(wpa_s, MSG_DEBUG, " hardware does not support " "HT PHY"); return 0; } continue; } /* There's also a VHT selector for 802.11ac */ if (flagged && ((rate_ie[j] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)) { if (!vht_supported(mode)) { wpa_dbg(wpa_s, MSG_DEBUG, " hardware does not support " "VHT PHY"); return 0; } continue; } if (!flagged) continue; /* check for legacy basic rates */ for (k = 0; k < mode->num_rates; k++) { if (mode->rates[k] == r) break; } if (k == mode->num_rates) { /* * IEEE Std 802.11-2007 7.3.2.2 demands that in * order to join a BSS all required rates * have to be supported by the hardware. */ wpa_dbg(wpa_s, MSG_DEBUG, " hardware does " "not support required rate %d.%d Mbps", r / 10, r % 10); return 0; } } } return 1; } /* * Test whether BSS is in an ESS. * This is done differently in DMG (60 GHz) and non-DMG bands */ static int bss_is_ess(struct wpa_bss *bss) { if (bss_is_dmg(bss)) { return (bss->caps & IEEE80211_CAP_DMG_MASK) == IEEE80211_CAP_DMG_AP; } return ((bss->caps & (IEEE80211_CAP_ESS | IEEE80211_CAP_IBSS)) == IEEE80211_CAP_ESS); } static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, int i, struct wpa_bss *bss, struct wpa_ssid *group, int only_first_ssid) { u8 wpa_ie_len, rsn_ie_len; int wpa; struct wpa_blacklist *e; const u8 *ie; struct wpa_ssid *ssid; int osen; ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); wpa_ie_len = ie ? ie[1] : 0; ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); rsn_ie_len = ie ? ie[1] : 0; ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); osen = ie != NULL; wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR " ssid='%s' " "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d%s%s%s", i, MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len), wpa_ie_len, rsn_ie_len, bss->caps, bss->level, wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "", (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) || wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) ? " p2p" : "", osen ? " osen=1" : ""); e = wpa_blacklist_get(wpa_s, bss->bssid); if (e) { int limit = 1; if (wpa_supplicant_enabled_networks(wpa_s) == 1) { /* * When only a single network is enabled, we can * trigger blacklisting on the first failure. This * should not be done with multiple enabled networks to * avoid getting forced to move into a worse ESS on * single error if there are no other BSSes of the * current ESS. */ limit = 0; } if (e->count > limit) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted " "(count=%d limit=%d)", e->count, limit); return NULL; } } if (bss->ssid_len == 0) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID not known"); return NULL; } if (disallowed_bssid(wpa_s, bss->bssid)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID disallowed"); return NULL; } if (disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID disallowed"); return NULL; } wpa = wpa_ie_len > 0 || rsn_ie_len > 0; for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) { int check_ssid = wpa ? 1 : (ssid->ssid_len != 0); int res; if (wpas_network_disabled(wpa_s, ssid)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled"); continue; } res = wpas_temp_disabled(wpa_s, ssid); if (res > 0) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled " "temporarily for %d second(s)", res); continue; } #ifdef CONFIG_WPS if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted " "(WPS)"); continue; } if (wpa && ssid->ssid_len == 0 && wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss)) check_ssid = 0; if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) { /* Only allow wildcard SSID match if an AP * advertises active WPS operation that matches * with our mode. */ check_ssid = 1; if (ssid->ssid_len == 0 && wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss)) check_ssid = 0; } #endif /* CONFIG_WPS */ if (ssid->bssid_set && ssid->ssid_len == 0 && os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0) check_ssid = 0; if (check_ssid && (bss->ssid_len != ssid->ssid_len || os_memcmp(bss->ssid, ssid->ssid, bss->ssid_len) != 0)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID mismatch"); continue; } if (ssid->bssid_set && os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID mismatch"); continue; } if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss)) continue; if (!osen && !wpa && !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) && !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) && !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - non-WPA network " "not allowed"); continue; } if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) && has_wep_key(ssid)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - ignore WPA/WPA2 AP for WEP network block"); continue; } if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - non-OSEN network " "not allowed"); continue; } if (!wpa_supplicant_match_privacy(bss, ssid)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy " "mismatch"); continue; } if (!bss_is_ess(bss)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - not ESS network"); continue; } if (!freq_allowed(ssid->freq_list, bss->freq)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - frequency not " "allowed"); continue; } if (!rate_match(wpa_s, bss)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - rate sets do " "not match"); continue; } #ifdef CONFIG_P2P if (ssid->p2p_group && !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) && !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P IE seen"); continue; } if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) { struct wpabuf *p2p_ie; u8 dev_addr[ETH_ALEN]; ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE); if (ie == NULL) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P element"); continue; } p2p_ie = wpa_bss_get_vendor_ie_multi( bss, P2P_IE_VENDOR_TYPE); if (p2p_ie == NULL) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - could not fetch P2P element"); continue; } if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0 || os_memcmp(dev_addr, ssid->go_p2p_dev_addr, ETH_ALEN) != 0) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - no matching GO P2P Device Address in P2P element"); wpabuf_free(p2p_ie); continue; } wpabuf_free(p2p_ie); } /* * TODO: skip the AP if its P2P IE has Group Formation * bit set in the P2P Group Capability Bitmap and we * are not in Group Formation with that device. */ #endif /* CONFIG_P2P */ /* Matching configuration found */ return ssid; } /* No matching configuration found */ return NULL; } static struct wpa_bss * wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group, struct wpa_ssid **selected_ssid, int only_first_ssid) { unsigned int i; if (only_first_ssid) wpa_dbg(wpa_s, MSG_DEBUG, "Try to find BSS matching pre-selected network id=%d", group->id); else wpa_dbg(wpa_s, MSG_DEBUG, "Selecting BSS from priority group %d", group->priority); for (i = 0; i < wpa_s->last_scan_res_used; i++) { struct wpa_bss *bss = wpa_s->last_scan_res[i]; *selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group, only_first_ssid); if (!*selected_ssid) continue; wpa_dbg(wpa_s, MSG_DEBUG, " selected BSS " MACSTR " ssid='%s'", MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len)); return bss; } return NULL; } struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s, struct wpa_ssid **selected_ssid) { struct wpa_bss *selected = NULL; int prio; struct wpa_ssid *next_ssid = NULL; if (wpa_s->last_scan_res == NULL || wpa_s->last_scan_res_used == 0) return NULL; /* no scan results from last update */ if (wpa_s->next_ssid) { struct wpa_ssid *ssid; /* check that next_ssid is still valid */ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (ssid == wpa_s->next_ssid) break; } next_ssid = ssid; wpa_s->next_ssid = NULL; } while (selected == NULL) { for (prio = 0; prio < wpa_s->conf->num_prio; prio++) { if (next_ssid && next_ssid->priority == wpa_s->conf->pssid[prio]->priority) { selected = wpa_supplicant_select_bss( wpa_s, next_ssid, selected_ssid, 1); if (selected) break; } selected = wpa_supplicant_select_bss( wpa_s, wpa_s->conf->pssid[prio], selected_ssid, 0); if (selected) break; } if (selected == NULL && wpa_s->blacklist && !wpa_s->countermeasures) { wpa_dbg(wpa_s, MSG_DEBUG, "No APs found - clear " "blacklist and try again"); wpa_blacklist_clear(wpa_s); wpa_s->blacklist_cleared++; } else if (selected == NULL) break; } return selected; } static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s, int timeout_sec, int timeout_usec) { if (!wpa_supplicant_enabled_networks(wpa_s)) { /* * No networks are enabled; short-circuit request so * we don't wait timeout seconds before transitioning * to INACTIVE state. */ wpa_dbg(wpa_s, MSG_DEBUG, "Short-circuit new scan request " "since there are no enabled networks"); wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); return; } wpa_s->scan_for_connection = 1; wpa_supplicant_req_scan(wpa_s, timeout_sec, timeout_usec); } int wpa_supplicant_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *selected, struct wpa_ssid *ssid) { if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP "PBC session overlap"); #ifdef CONFIG_P2P if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT || wpa_s->p2p_in_provisioning) { eloop_register_timeout(0, 0, wpas_p2p_pbc_overlap_cb, wpa_s, NULL); return -1; } #endif /* CONFIG_P2P */ #ifdef CONFIG_WPS wpas_wps_cancel(wpa_s); #endif /* CONFIG_WPS */ return -1; } wpa_msg(wpa_s, MSG_DEBUG, "Considering connect request: reassociate: %d selected: " MACSTR " bssid: " MACSTR " pending: " MACSTR " wpa_state: %s ssid=%p current_ssid=%p", wpa_s->reassociate, MAC2STR(selected->bssid), MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid), wpa_supplicant_state_txt(wpa_s->wpa_state), ssid, wpa_s->current_ssid); /* * Do not trigger new association unless the BSSID has changed or if * reassociation is requested. If we are in process of associating with * the selected BSSID, do not trigger new attempt. */ if (wpa_s->reassociate || (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 && ((wpa_s->wpa_state != WPA_ASSOCIATING && wpa_s->wpa_state != WPA_AUTHENTICATING) || (!is_zero_ether_addr(wpa_s->pending_bssid) && os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) != 0) || (is_zero_ether_addr(wpa_s->pending_bssid) && ssid != wpa_s->current_ssid)))) { if (wpa_supplicant_scard_init(wpa_s, ssid)) { wpa_supplicant_req_new_scan(wpa_s, 10, 0); return 0; } wpa_msg(wpa_s, MSG_DEBUG, "Request association with " MACSTR, MAC2STR(selected->bssid)); wpa_supplicant_associate(wpa_s, selected, ssid); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Already associated or trying to " "connect with the selected AP"); } return 0; } static struct wpa_ssid * wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s) { int prio; struct wpa_ssid *ssid; for (prio = 0; prio < wpa_s->conf->num_prio; prio++) { for (ssid = wpa_s->conf->pssid[prio]; ssid; ssid = ssid->pnext) { if (wpas_network_disabled(wpa_s, ssid)) continue; if (ssid->mode == IEEE80211_MODE_IBSS || ssid->mode == IEEE80211_MODE_AP) return ssid; } } return NULL; } /* TODO: move the rsn_preauth_scan_result*() to be called from notify.c based * on BSS added and BSS changed events */ static void wpa_supplicant_rsn_preauth_scan_results( struct wpa_supplicant *wpa_s) { struct wpa_bss *bss; if (rsn_preauth_scan_results(wpa_s->wpa) < 0) return; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { const u8 *ssid, *rsn; ssid = wpa_bss_get_ie(bss, WLAN_EID_SSID); if (ssid == NULL) continue; rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN); if (rsn == NULL) continue; rsn_preauth_scan_result(wpa_s->wpa, bss->bssid, ssid, rsn); } } static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, struct wpa_bss *selected, struct wpa_ssid *ssid) { struct wpa_bss *current_bss = NULL; int min_diff; if (wpa_s->reassociate) return 1; /* explicit request to reassociate */ if (wpa_s->wpa_state < WPA_ASSOCIATED) return 1; /* we are not associated; continue */ if (wpa_s->current_ssid == NULL) return 1; /* unknown current SSID */ if (wpa_s->current_ssid != ssid) return 1; /* different network block */ if (wpas_driver_bss_selection(wpa_s)) return 0; /* Driver-based roaming */ if (wpa_s->current_ssid->ssid) current_bss = wpa_bss_get(wpa_s, wpa_s->bssid, wpa_s->current_ssid->ssid, wpa_s->current_ssid->ssid_len); if (!current_bss) current_bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid); if (!current_bss) return 1; /* current BSS not seen in scan results */ if (current_bss == selected) return 0; if (selected->last_update_idx > current_bss->last_update_idx) return 1; /* current BSS not seen in the last scan */ #ifndef CONFIG_NO_ROAMING wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation"); wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR " level=%d", MAC2STR(current_bss->bssid), current_bss->level); wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR " level=%d", MAC2STR(selected->bssid), selected->level); if (wpa_s->current_ssid->bssid_set && os_memcmp(selected->bssid, wpa_s->current_ssid->bssid, ETH_ALEN) == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Allow reassociation - selected BSS " "has preferred BSSID"); return 1; } if (current_bss->level < 0 && current_bss->level > selected->level) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better " "signal level"); return 0; } min_diff = 2; if (current_bss->level < 0) { if (current_bss->level < -85) min_diff = 1; else if (current_bss->level < -80) min_diff = 2; else if (current_bss->level < -75) min_diff = 3; else if (current_bss->level < -70) min_diff = 4; else min_diff = 5; } if (abs(current_bss->level - selected->level) < min_diff) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference " "in signal level"); return 0; } return 1; #else /* CONFIG_NO_ROAMING */ return 0; #endif /* CONFIG_NO_ROAMING */ } /* Return != 0 if no scan results could be fetched or if scan results should not * be shared with other virtual interfaces. */ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, union wpa_event_data *data, int own_request) { struct wpa_scan_results *scan_res = NULL; int ret = 0; int ap = 0; #ifndef CONFIG_NO_RANDOM_POOL size_t i, num; #endif /* CONFIG_NO_RANDOM_POOL */ #ifdef CONFIG_AP if (wpa_s->ap_iface) ap = 1; #endif /* CONFIG_AP */ wpa_supplicant_notify_scanning(wpa_s, 0); scan_res = wpa_supplicant_get_scan_results(wpa_s, data ? &data->scan_info : NULL, 1); if (scan_res == NULL) { if (wpa_s->conf->ap_scan == 2 || ap || wpa_s->scan_res_handler == scan_only_handler) return -1; if (!own_request) return -1; wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try " "scanning again"); wpa_supplicant_req_new_scan(wpa_s, 1, 0); ret = -1; goto scan_work_done; } #ifndef CONFIG_NO_RANDOM_POOL num = scan_res->num; if (num > 10) num = 10; for (i = 0; i < num; i++) { u8 buf[5]; struct wpa_scan_res *res = scan_res->res[i]; buf[0] = res->bssid[5]; buf[1] = res->qual & 0xff; buf[2] = res->noise & 0xff; buf[3] = res->level & 0xff; buf[4] = res->tsf & 0xff; random_add_randomness(buf, sizeof(buf)); } #endif /* CONFIG_NO_RANDOM_POOL */ if (own_request && wpa_s->scan_res_handler && (wpa_s->own_scan_running || !wpa_s->external_scan_running)) { void (*scan_res_handler)(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); scan_res_handler = wpa_s->scan_res_handler; wpa_s->scan_res_handler = NULL; scan_res_handler(wpa_s, scan_res); ret = -2; goto scan_work_done; } if (ap) { wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode"); #ifdef CONFIG_AP if (wpa_s->ap_iface->scan_cb) wpa_s->ap_iface->scan_cb(wpa_s->ap_iface); #endif /* CONFIG_AP */ goto scan_work_done; } wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)", wpa_s->own_scan_running, wpa_s->external_scan_running); if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && wpa_s->manual_scan_use_id && wpa_s->own_scan_running) { wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u", wpa_s->manual_scan_id); wpa_s->manual_scan_use_id = 0; } else { wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); } wpas_notify_scan_results(wpa_s); wpas_notify_scan_done(wpa_s, 1); if (!wpa_s->own_scan_running && wpa_s->external_scan_running) { wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection"); wpa_scan_results_free(scan_res); return 0; } if (sme_proc_obss_scan(wpa_s) > 0) goto scan_work_done; if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) goto scan_work_done; if (autoscan_notify_scan(wpa_s, scan_res)) goto scan_work_done; if (wpa_s->disconnected) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); goto scan_work_done; } if (!wpas_driver_bss_selection(wpa_s) && bgscan_notify_scan(wpa_s, scan_res) == 1) goto scan_work_done; wpas_wps_update_ap_info(wpa_s, scan_res); wpa_scan_results_free(scan_res); if (wpa_s->scan_work) { struct wpa_radio_work *work = wpa_s->scan_work; wpa_s->scan_work = NULL; radio_work_done(work); } return wpas_select_network_from_last_scan(wpa_s, 1, own_request); scan_work_done: wpa_scan_results_free(scan_res); if (wpa_s->scan_work) { struct wpa_radio_work *work = wpa_s->scan_work; wpa_s->scan_work = NULL; radio_work_done(work); } return ret; } static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, int new_scan, int own_request) { struct wpa_bss *selected; struct wpa_ssid *ssid = NULL; selected = wpa_supplicant_pick_network(wpa_s, &ssid); if (selected) { int skip; skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid); if (skip) { if (new_scan) wpa_supplicant_rsn_preauth_scan_results(wpa_s); return 0; } if (wpa_supplicant_connect(wpa_s, selected, ssid) < 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed"); return -1; } if (new_scan) wpa_supplicant_rsn_preauth_scan_results(wpa_s); /* * Do not notify other virtual radios of scan results since we do not * want them to start other associations at the same time. */ return 1; } else { wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found"); ssid = wpa_supplicant_pick_new_network(wpa_s); if (ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "Setup a new network"); wpa_supplicant_associate(wpa_s, NULL, ssid); if (new_scan) wpa_supplicant_rsn_preauth_scan_results(wpa_s); } else if (own_request) { /* * No SSID found. If SCAN results are as a result of * own scan request and not due to a scan request on * another shared interface, try another scan. */ int timeout_sec = wpa_s->scan_interval; int timeout_usec = 0; #ifdef CONFIG_P2P if (wpas_p2p_scan_no_go_seen(wpa_s) == 1) return 0; if (wpa_s->p2p_in_provisioning || wpa_s->show_group_started || wpa_s->p2p_in_invitation) { /* * Use shorter wait during P2P Provisioning * state and during P2P join-a-group operation * to speed up group formation. */ timeout_sec = 0; timeout_usec = 250000; wpa_supplicant_req_new_scan(wpa_s, timeout_sec, timeout_usec); return 0; } #endif /* CONFIG_P2P */ #ifdef CONFIG_INTERWORKING if (wpa_s->conf->auto_interworking && wpa_s->conf->interworking && wpa_s->conf->cred) { wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: " "start ANQP fetch since no matching " "networks found"); wpa_s->network_select = 1; wpa_s->auto_network_select = 1; interworking_start_fetch_anqp(wpa_s); return 1; } #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_WPS if (wpa_s->after_wps > 0 || wpas_wps_searching(wpa_s)) { wpa_dbg(wpa_s, MSG_DEBUG, "Use shorter wait during WPS processing"); timeout_sec = 0; timeout_usec = 500000; wpa_supplicant_req_new_scan(wpa_s, timeout_sec, timeout_usec); return 0; } #endif /* CONFIG_WPS */ if (wpa_supplicant_req_sched_scan(wpa_s)) wpa_supplicant_req_new_scan(wpa_s, timeout_sec, timeout_usec); } } return 0; } static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { struct wpa_supplicant *ifs; if (_wpa_supplicant_event_scan_results(wpa_s, data, 1) != 0) { /* * If no scan results could be fetched, then no need to * notify those interfaces that did not actually request * this scan. Similarly, if scan results started a new operation on this * interface, do not notify other interfaces to avoid concurrent * operations during a connection attempt. */ return; } /* * Check other interfaces to see if they share the same radio. If * so, they get updated with this same scan info. */ dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant, radio_list) { if (ifs != wpa_s) { wpa_printf(MSG_DEBUG, "%s: Updating scan results from " "sibling", ifs->ifname); _wpa_supplicant_event_scan_results(ifs, data, 0); } } } #endif /* CONFIG_NO_SCAN_PROCESSING */ int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s) { #ifdef CONFIG_NO_SCAN_PROCESSING return -1; #else /* CONFIG_NO_SCAN_PROCESSING */ struct os_reltime now; if (wpa_s->last_scan_res_used <= 0) return -1; os_get_reltime(&now); if (os_reltime_expired(&now, &wpa_s->last_scan, 5)) { wpa_printf(MSG_DEBUG, "Fast associate: Old scan results"); return -1; } return wpas_select_network_from_last_scan(wpa_s, 0, 1); #endif /* CONFIG_NO_SCAN_PROCESSING */ } #ifdef CONFIG_WNM static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; if (wpa_s->wpa_state < WPA_ASSOCIATED) return; if (!wpa_s->no_keep_alive) { wpa_printf(MSG_DEBUG, "WNM: Send keep-alive to AP " MACSTR, MAC2STR(wpa_s->bssid)); /* TODO: could skip this if normal data traffic has been sent */ /* TODO: Consider using some more appropriate data frame for * this */ if (wpa_s->l2) l2_packet_send(wpa_s->l2, wpa_s->bssid, 0x0800, (u8 *) "", 0); } #ifdef CONFIG_SME if (wpa_s->sme.bss_max_idle_period) { unsigned int msec; msec = wpa_s->sme.bss_max_idle_period * 1024; /* times 1000 */ if (msec > 100) msec -= 100; eloop_register_timeout(msec / 1000, msec % 1000 * 1000, wnm_bss_keep_alive, wpa_s, NULL); } #endif /* CONFIG_SME */ } static void wnm_process_assoc_resp(struct wpa_supplicant *wpa_s, const u8 *ies, size_t ies_len) { struct ieee802_11_elems elems; if (ies == NULL) return; if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) return; #ifdef CONFIG_SME if (elems.bss_max_idle_period) { unsigned int msec; wpa_s->sme.bss_max_idle_period = WPA_GET_LE16(elems.bss_max_idle_period); wpa_printf(MSG_DEBUG, "WNM: BSS Max Idle Period: %u (* 1000 " "TU)%s", wpa_s->sme.bss_max_idle_period, (elems.bss_max_idle_period[2] & 0x01) ? " (protected keep-live required)" : ""); if (wpa_s->sme.bss_max_idle_period == 0) wpa_s->sme.bss_max_idle_period = 1; if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) { eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL); /* msec times 1000 */ msec = wpa_s->sme.bss_max_idle_period * 1024; if (msec > 100) msec -= 100; eloop_register_timeout(msec / 1000, msec % 1000 * 1000, wnm_bss_keep_alive, wpa_s, NULL); } } #endif /* CONFIG_SME */ } #endif /* CONFIG_WNM */ void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s) { #ifdef CONFIG_WNM eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL); #endif /* CONFIG_WNM */ } #ifdef CONFIG_INTERWORKING static int wpas_qos_map_set(struct wpa_supplicant *wpa_s, const u8 *qos_map, size_t len) { int res; wpa_hexdump(MSG_DEBUG, "Interworking: QoS Map Set", qos_map, len); res = wpa_drv_set_qos_map(wpa_s, qos_map, len); if (res) { wpa_printf(MSG_DEBUG, "Interworking: Failed to configure QoS Map Set to the driver"); } return res; } static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s, const u8 *ies, size_t ies_len) { struct ieee802_11_elems elems; if (ies == NULL) return; if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) return; if (elems.qos_map_set) { wpas_qos_map_set(wpa_s, elems.qos_map_set, elems.qos_map_set_len); } } #endif /* CONFIG_INTERWORKING */ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { int l, len, found = 0, wpa_found, rsn_found; const u8 *p; #ifdef CONFIG_IEEE80211R u8 bssid[ETH_ALEN]; #endif /* CONFIG_IEEE80211R */ wpa_dbg(wpa_s, MSG_DEBUG, "Association info event"); if (data->assoc_info.req_ies) wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies, data->assoc_info.req_ies_len); if (data->assoc_info.resp_ies) { wpa_hexdump(MSG_DEBUG, "resp_ies", data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); #ifdef CONFIG_TDLS wpa_tdls_assoc_resp_ies(wpa_s->wpa, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); #endif /* CONFIG_TDLS */ #ifdef CONFIG_WNM wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); #endif /* CONFIG_WNM */ #ifdef CONFIG_INTERWORKING interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); #endif /* CONFIG_INTERWORKING */ } if (data->assoc_info.beacon_ies) wpa_hexdump(MSG_DEBUG, "beacon_ies", data->assoc_info.beacon_ies, data->assoc_info.beacon_ies_len); if (data->assoc_info.freq) wpa_dbg(wpa_s, MSG_DEBUG, "freq=%u MHz", data->assoc_info.freq); p = data->assoc_info.req_ies; l = data->assoc_info.req_ies_len; /* Go through the IEs and make a copy of the WPA/RSN IE, if present. */ while (p && l >= 2) { len = p[1] + 2; if (len > l) { wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info", p, l); break; } if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 && (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) || (p[0] == WLAN_EID_RSN && p[1] >= 2)) { if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len)) break; found = 1; wpa_find_assoc_pmkid(wpa_s); break; } l -= len; p += len; } if (!found && data->assoc_info.req_ies) wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); #ifdef CONFIG_IEEE80211R #ifdef CONFIG_SME if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) { if (wpa_drv_get_bssid(wpa_s, bssid) < 0 || wpa_ft_validate_reassoc_resp(wpa_s->wpa, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len, bssid) < 0) { wpa_dbg(wpa_s, MSG_DEBUG, "FT: Validation of " "Reassociation Response failed"); wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_INVALID_IE); return -1; } } p = data->assoc_info.resp_ies; l = data->assoc_info.resp_ies_len; #ifdef CONFIG_WPS_STRICT if (p && wpa_s->current_ssid && wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_WPS) { struct wpabuf *wps; wps = ieee802_11_vendor_ie_concat(p, l, WPS_IE_VENDOR_TYPE); if (wps == NULL) { wpa_msg(wpa_s, MSG_INFO, "WPS-STRICT: AP did not " "include WPS IE in (Re)Association Response"); return -1; } if (wps_validate_assoc_resp(wps) < 0) { wpabuf_free(wps); wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_INVALID_IE); return -1; } wpabuf_free(wps); } #endif /* CONFIG_WPS_STRICT */ /* Go through the IEs and make a copy of the MDIE, if present. */ while (p && l >= 2) { len = p[1] + 2; if (len > l) { wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info", p, l); break; } if (p[0] == WLAN_EID_MOBILITY_DOMAIN && p[1] >= MOBILITY_DOMAIN_ID_LEN) { wpa_s->sme.ft_used = 1; os_memcpy(wpa_s->sme.mobility_domain, p + 2, MOBILITY_DOMAIN_ID_LEN); break; } l -= len; p += len; } #endif /* CONFIG_SME */ /* Process FT when SME is in the driver */ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && wpa_ft_is_completed(wpa_s->wpa)) { if (wpa_drv_get_bssid(wpa_s, bssid) < 0 || wpa_ft_validate_reassoc_resp(wpa_s->wpa, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len, bssid) < 0) { wpa_dbg(wpa_s, MSG_DEBUG, "FT: Validation of " "Reassociation Response failed"); wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_INVALID_IE); return -1; } wpa_dbg(wpa_s, MSG_DEBUG, "FT: Reassociation Response done"); } wpa_sm_set_ft_params(wpa_s->wpa, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); #endif /* CONFIG_IEEE80211R */ /* WPA/RSN IE from Beacon/ProbeResp */ p = data->assoc_info.beacon_ies; l = data->assoc_info.beacon_ies_len; /* Go through the IEs and make a copy of the WPA/RSN IEs, if present. */ wpa_found = rsn_found = 0; while (p && l >= 2) { len = p[1] + 2; if (len > l) { wpa_hexdump(MSG_DEBUG, "Truncated IE in beacon_ies", p, l); break; } if (!wpa_found && p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 && os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0) { wpa_found = 1; wpa_sm_set_ap_wpa_ie(wpa_s->wpa, p, len); } if (!rsn_found && p[0] == WLAN_EID_RSN && p[1] >= 2) { rsn_found = 1; wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len); } l -= len; p += len; } if (!wpa_found && data->assoc_info.beacon_ies) wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0); if (!rsn_found && data->assoc_info.beacon_ies) wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0); if (wpa_found || rsn_found) wpa_s->ap_ies_from_associnfo = 1; if (wpa_s->assoc_freq && data->assoc_info.freq && wpa_s->assoc_freq != data->assoc_info.freq) { wpa_printf(MSG_DEBUG, "Operating frequency changed from " "%u to %u MHz", wpa_s->assoc_freq, data->assoc_info.freq); wpa_supplicant_update_scan_results(wpa_s); } wpa_s->assoc_freq = data->assoc_info.freq; return 0; } static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s) { const u8 *bss_wpa = NULL, *bss_rsn = NULL; if (!wpa_s->current_bss || !wpa_s->current_ssid) return -1; if (!wpa_key_mgmt_wpa_any(wpa_s->current_ssid->key_mgmt)) return 0; bss_wpa = wpa_bss_get_vendor_ie(wpa_s->current_bss, WPA_IE_VENDOR_TYPE); bss_rsn = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSN); if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa, bss_wpa ? 2 + bss_wpa[1] : 0) || wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn, bss_rsn ? 2 + bss_rsn[1] : 0)) return -1; return 0; } static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { u8 bssid[ETH_ALEN]; int ft_completed; #ifdef CONFIG_AP if (wpa_s->ap_iface) { hostapd_notif_assoc(wpa_s->ap_iface->bss[0], data->assoc_info.addr, data->assoc_info.req_ies, data->assoc_info.req_ies_len, data->assoc_info.reassoc); return; } #endif /* CONFIG_AP */ ft_completed = wpa_ft_is_completed(wpa_s->wpa); if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0) return; if (wpa_drv_get_bssid(wpa_s, bssid) < 0) { wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID"); wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); return; } wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED); if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID=" MACSTR, MAC2STR(bssid)); random_add_randomness(bssid, ETH_ALEN); os_memcpy(wpa_s->bssid, bssid, ETH_ALEN); os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); wpas_notify_bssid_changed(wpa_s); if (wpa_supplicant_dynamic_keys(wpa_s) && !ft_completed) { wpa_clear_keys(wpa_s, bssid); } if (wpa_supplicant_select_config(wpa_s) < 0) { wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); return; } if (wpa_s->conf->ap_scan == 1 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION) { if (wpa_supplicant_assoc_update_ie(wpa_s) < 0) wpa_msg(wpa_s, MSG_WARNING, "WPA/RSN IEs not updated"); } } #ifdef CONFIG_SME os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN); wpa_s->sme.prev_bssid_set = 1; #endif /* CONFIG_SME */ wpa_msg(wpa_s, MSG_INFO, "Associated with " MACSTR, MAC2STR(bssid)); if (wpa_s->current_ssid) { /* When using scanning (ap_scan=1), SIM PC/SC interface can be * initialized before association, but for other modes, * initialize PC/SC here, if the current configuration needs * smartcard or SIM/USIM. */ wpa_supplicant_scard_init(wpa_s, wpa_s->current_ssid); } wpa_sm_notify_assoc(wpa_s->wpa, bssid); if (wpa_s->l2) l2_packet_notify_auth_start(wpa_s->l2); /* * Set portEnabled first to FALSE in order to get EAP state machine out * of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE * state machine may transit to AUTHENTICATING state based on obsolete * eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to * AUTHENTICATED without ever giving chance to EAP state machine to * reset the state. */ if (!ft_completed) { eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE); eapol_sm_notify_portValid(wpa_s->eapol, FALSE); } if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed) eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); /* 802.1X::portControl = Auto */ eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE); wpa_s->eapol_received = 0; if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE || (wpa_s->current_ssid && wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS)) { if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE)) { /* * Set the key after having received joined-IBSS event * from the driver. */ wpa_supplicant_set_wpa_none_key(wpa_s, wpa_s->current_ssid); } wpa_supplicant_cancel_auth_timeout(wpa_s); wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); } else if (!ft_completed) { /* Timeout for receiving the first EAPOL packet */ wpa_supplicant_req_auth_timeout(wpa_s, 10, 0); } wpa_supplicant_cancel_scan(wpa_s); if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) && wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) { /* * We are done; the driver will take care of RSN 4-way * handshake. */ wpa_supplicant_cancel_auth_timeout(wpa_s); wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); eapol_sm_notify_portValid(wpa_s->eapol, TRUE); eapol_sm_notify_eap_success(wpa_s->eapol, TRUE); } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) && wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { /* * The driver will take care of RSN 4-way handshake, so we need * to allow EAPOL supplicant to complete its work without * waiting for WPA supplicant. */ eapol_sm_notify_portValid(wpa_s->eapol, TRUE); } else if (ft_completed) { /* * FT protocol completed - make sure EAPOL state machine ends * up in authenticated. */ wpa_supplicant_cancel_auth_timeout(wpa_s); wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); eapol_sm_notify_portValid(wpa_s->eapol, TRUE); eapol_sm_notify_eap_success(wpa_s->eapol, TRUE); } wpa_s->last_eapol_matches_bssid = 0; if (wpa_s->pending_eapol_rx) { struct os_reltime now, age; os_get_reltime(&now); os_reltime_sub(&now, &wpa_s->pending_eapol_rx_time, &age); if (age.sec == 0 && age.usec < 100000 && os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Process pending EAPOL " "frame that was received just before " "association notification"); wpa_supplicant_rx_eapol( wpa_s, wpa_s->pending_eapol_rx_src, wpabuf_head(wpa_s->pending_eapol_rx), wpabuf_len(wpa_s->pending_eapol_rx)); } wpabuf_free(wpa_s->pending_eapol_rx); wpa_s->pending_eapol_rx = NULL; } if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) && wpa_s->current_ssid && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE)) { /* Set static WEP keys again */ wpa_set_wep_keys(wpa_s, wpa_s->current_ssid); } #ifdef CONFIG_IBSS_RSN if (wpa_s->current_ssid && wpa_s->current_ssid->mode == WPAS_MODE_IBSS && wpa_s->key_mgmt != WPA_KEY_MGMT_NONE && wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE && wpa_s->ibss_rsn == NULL) { wpa_s->ibss_rsn = ibss_rsn_init(wpa_s); if (!wpa_s->ibss_rsn) { wpa_msg(wpa_s, MSG_INFO, "Failed to init IBSS RSN"); wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); return; } ibss_rsn_set_psk(wpa_s->ibss_rsn, wpa_s->current_ssid->psk); } #endif /* CONFIG_IBSS_RSN */ wpas_wps_notify_assoc(wpa_s, bssid); } static int disconnect_reason_recoverable(u16 reason_code) { return reason_code == WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY || reason_code == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA || reason_code == WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA; } static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s, u16 reason_code, int locally_generated) { const u8 *bssid; if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) { /* * At least Host AP driver and a Prism3 card seemed to be * generating streams of disconnected events when configuring * IBSS for WPA-None. Ignore them for now. */ return; } bssid = wpa_s->bssid; if (is_zero_ether_addr(bssid)) bssid = wpa_s->pending_bssid; if (!is_zero_ether_addr(bssid) || wpa_s->wpa_state >= WPA_AUTHENTICATING) { wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR " reason=%d%s", MAC2STR(bssid), reason_code, locally_generated ? " locally_generated=1" : ""); } } static int could_be_psk_mismatch(struct wpa_supplicant *wpa_s, u16 reason_code, int locally_generated) { if (wpa_s->wpa_state != WPA_4WAY_HANDSHAKE || !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) return 0; /* Not in 4-way handshake with PSK */ /* * It looks like connection was lost while trying to go through PSK * 4-way handshake. Filter out known disconnection cases that are caused * by something else than PSK mismatch to avoid confusing reports. */ if (locally_generated) { if (reason_code == WLAN_REASON_IE_IN_4WAY_DIFFERS) return 0; } return 1; } static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, u16 reason_code, int locally_generated) { const u8 *bssid; int authenticating; u8 prev_pending_bssid[ETH_ALEN]; struct wpa_bss *fast_reconnect = NULL; struct wpa_ssid *fast_reconnect_ssid = NULL; struct wpa_ssid *last_ssid; authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING; os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN); if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) { /* * At least Host AP driver and a Prism3 card seemed to be * generating streams of disconnected events when configuring * IBSS for WPA-None. Ignore them for now. */ wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - ignore in " "IBSS/WPA-None mode"); return; } if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) { wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - " "pre-shared key may be incorrect"); if (wpas_p2p_4way_hs_failed(wpa_s) > 0) return; /* P2P group removed */ wpas_auth_failed(wpa_s, "WRONG_KEY"); } if (!wpa_s->disconnected && (!wpa_s->auto_reconnect_disabled || wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)) { wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect enabled: try to " "reconnect (wps=%d wpa_state=%d)", wpa_s->key_mgmt == WPA_KEY_MGMT_WPS, wpa_s->wpa_state); if (wpa_s->wpa_state == WPA_COMPLETED && wpa_s->current_ssid && wpa_s->current_ssid->mode == WPAS_MODE_INFRA && !locally_generated && disconnect_reason_recoverable(reason_code)) { /* * It looks like the AP has dropped association with * us, but could allow us to get back in. Try to * reconnect to the same BSS without full scan to save * time for some common cases. */ fast_reconnect = wpa_s->current_bss; fast_reconnect_ssid = wpa_s->current_ssid; } else if (wpa_s->wpa_state >= WPA_ASSOCIATING) wpa_supplicant_req_scan(wpa_s, 0, 100000); else wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new " "immediate scan"); } else { wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect disabled: do not " "try to re-connect"); wpa_s->reassociate = 0; wpa_s->disconnected = 1; wpa_supplicant_cancel_sched_scan(wpa_s); } bssid = wpa_s->bssid; if (is_zero_ether_addr(bssid)) bssid = wpa_s->pending_bssid; if (wpa_s->wpa_state >= WPA_AUTHENTICATING) wpas_connection_failed(wpa_s, bssid); wpa_sm_notify_disassoc(wpa_s->wpa); if (locally_generated) wpa_s->disconnect_reason = -reason_code; else wpa_s->disconnect_reason = reason_code; wpas_notify_disconnect_reason(wpa_s); if (wpa_supplicant_dynamic_keys(wpa_s)) { wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys"); wpa_clear_keys(wpa_s, wpa_s->bssid); } last_ssid = wpa_s->current_ssid; wpa_supplicant_mark_disassoc(wpa_s); if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) { sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid); wpa_s->current_ssid = last_ssid; } if (fast_reconnect && !wpas_network_disabled(wpa_s, fast_reconnect_ssid) && !disallowed_bssid(wpa_s, fast_reconnect->bssid) && !disallowed_ssid(wpa_s, fast_reconnect->ssid, fast_reconnect->ssid_len) && !wpas_temp_disabled(wpa_s, fast_reconnect_ssid)) { #ifndef CONFIG_NO_SCAN_PROCESSING wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS"); if (wpa_supplicant_connect(wpa_s, fast_reconnect, fast_reconnect_ssid) < 0) { /* Recover through full scan */ wpa_supplicant_req_scan(wpa_s, 0, 100000); } #endif /* CONFIG_NO_SCAN_PROCESSING */ } else if (fast_reconnect) { /* * Could not reconnect to the same BSS due to network being * disabled. Use a new scan to match the alternative behavior * above, i.e., to continue automatic reconnection attempt in a * way that enforces disabled network rules. */ wpa_supplicant_req_scan(wpa_s, 0, 100000); } } #ifdef CONFIG_DELAYED_MIC_ERROR_REPORT void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; if (!wpa_s->pending_mic_error_report) return; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Sending pending MIC error report"); wpa_sm_key_request(wpa_s->wpa, 1, wpa_s->pending_mic_error_pairwise); wpa_s->pending_mic_error_report = 0; } #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */ static void wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { int pairwise; struct os_reltime t; wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected"); pairwise = (data && data->michael_mic_failure.unicast); os_get_reltime(&t); if ((wpa_s->last_michael_mic_error.sec && !os_reltime_expired(&t, &wpa_s->last_michael_mic_error, 60)) || wpa_s->pending_mic_error_report) { if (wpa_s->pending_mic_error_report) { /* * Send the pending MIC error report immediately since * we are going to start countermeasures and AP better * do the same. */ wpa_sm_key_request(wpa_s->wpa, 1, wpa_s->pending_mic_error_pairwise); } /* Send the new MIC error report immediately since we are going * to start countermeasures and AP better do the same. */ wpa_sm_key_request(wpa_s->wpa, 1, pairwise); /* initialize countermeasures */ wpa_s->countermeasures = 1; wpa_blacklist_add(wpa_s, wpa_s->bssid); wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started"); /* * Need to wait for completion of request frame. We do not get * any callback for the message completion, so just wait a * short while and hope for the best. */ os_sleep(0, 10000); wpa_drv_set_countermeasures(wpa_s, 1); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_MICHAEL_MIC_FAILURE); eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL); eloop_register_timeout(60, 0, wpa_supplicant_stop_countermeasures, wpa_s, NULL); /* TODO: mark the AP rejected for 60 second. STA is * allowed to associate with another AP.. */ } else { #ifdef CONFIG_DELAYED_MIC_ERROR_REPORT if (wpa_s->mic_errors_seen) { /* * Reduce the effectiveness of Michael MIC error * reports as a means for attacking against TKIP if * more than one MIC failure is noticed with the same * PTK. We delay the transmission of the reports by a * random time between 0 and 60 seconds in order to * force the attacker wait 60 seconds before getting * the information on whether a frame resulted in a MIC * failure. */ u8 rval[4]; int sec; if (os_get_random(rval, sizeof(rval)) < 0) sec = os_random() % 60; else sec = WPA_GET_BE32(rval) % 60; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Delay MIC error " "report %d seconds", sec); wpa_s->pending_mic_error_report = 1; wpa_s->pending_mic_error_pairwise = pairwise; eloop_cancel_timeout( wpa_supplicant_delayed_mic_error_report, wpa_s, NULL); eloop_register_timeout( sec, os_random() % 1000000, wpa_supplicant_delayed_mic_error_report, wpa_s, NULL); } else { wpa_sm_key_request(wpa_s->wpa, 1, pairwise); } #else /* CONFIG_DELAYED_MIC_ERROR_REPORT */ wpa_sm_key_request(wpa_s->wpa, 1, pairwise); #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */ } wpa_s->last_michael_mic_error = t; wpa_s->mic_errors_seen++; } #ifdef CONFIG_TERMINATE_ONLASTIF static int any_interfaces(struct wpa_supplicant *head) { struct wpa_supplicant *wpa_s; for (wpa_s = head; wpa_s != NULL; wpa_s = wpa_s->next) if (!wpa_s->interface_removed) return 1; return 0; } #endif /* CONFIG_TERMINATE_ONLASTIF */ static void wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { if (os_strcmp(wpa_s->ifname, data->interface_status.ifname) != 0) return; switch (data->interface_status.ievent) { case EVENT_INTERFACE_ADDED: if (!wpa_s->interface_removed) break; wpa_s->interface_removed = 0; wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was added"); if (wpa_supplicant_driver_init(wpa_s) < 0) { wpa_msg(wpa_s, MSG_INFO, "Failed to initialize the " "driver after interface was added"); } break; case EVENT_INTERFACE_REMOVED: wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was removed"); wpa_s->interface_removed = 1; wpa_supplicant_mark_disassoc(wpa_s); wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED); l2_packet_deinit(wpa_s->l2); wpa_s->l2 = NULL; #ifdef CONFIG_TERMINATE_ONLASTIF /* check if last interface */ if (!any_interfaces(wpa_s->global->ifaces)) eloop_terminate(); #endif /* CONFIG_TERMINATE_ONLASTIF */ break; } } #ifdef CONFIG_PEERKEY static void wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { if (data == NULL) return; wpa_sm_stkstart(wpa_s->wpa, data->stkstart.peer); } #endif /* CONFIG_PEERKEY */ #ifdef CONFIG_TDLS static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { if (data == NULL) return; switch (data->tdls.oper) { case TDLS_REQUEST_SETUP: wpa_tdls_remove(wpa_s->wpa, data->tdls.peer); if (wpa_tdls_is_external_setup(wpa_s->wpa)) wpa_tdls_start(wpa_s->wpa, data->tdls.peer); else wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, data->tdls.peer); break; case TDLS_REQUEST_TEARDOWN: if (wpa_tdls_is_external_setup(wpa_s->wpa)) wpa_tdls_teardown_link(wpa_s->wpa, data->tdls.peer, data->tdls.reason_code); else wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, data->tdls.peer); break; } } #endif /* CONFIG_TDLS */ #ifdef CONFIG_WNM static void wpa_supplicant_event_wnm(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { if (data == NULL) return; switch (data->wnm.oper) { case WNM_OPER_SLEEP: wpa_printf(MSG_DEBUG, "Start sending WNM-Sleep Request " "(action=%d, intval=%d)", data->wnm.sleep_action, data->wnm.sleep_intval); ieee802_11_send_wnmsleep_req(wpa_s, data->wnm.sleep_action, data->wnm.sleep_intval, NULL); break; } } #endif /* CONFIG_WNM */ #ifdef CONFIG_IEEE80211R static void wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { if (data == NULL) return; if (wpa_ft_process_response(wpa_s->wpa, data->ft_ies.ies, data->ft_ies.ies_len, data->ft_ies.ft_action, data->ft_ies.target_ap, data->ft_ies.ric_ies, data->ft_ies.ric_ies_len) < 0) { /* TODO: prevent MLME/driver from trying to associate? */ } } #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IBSS_RSN static void wpa_supplicant_event_ibss_rsn_start(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { struct wpa_ssid *ssid; if (wpa_s->wpa_state < WPA_ASSOCIATED) return; if (data == NULL) return; ssid = wpa_s->current_ssid; if (ssid == NULL) return; if (ssid->mode != WPAS_MODE_IBSS || !wpa_key_mgmt_wpa(ssid->key_mgmt)) return; ibss_rsn_start(wpa_s->ibss_rsn, data->ibss_rsn_start.peer); } static void wpa_supplicant_event_ibss_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { struct wpa_ssid *ssid = wpa_s->current_ssid; if (ssid == NULL) return; /* check if the ssid is correctly configured as IBSS/RSN */ if (ssid->mode != WPAS_MODE_IBSS || !wpa_key_mgmt_wpa(ssid->key_mgmt)) return; ibss_rsn_handle_auth(wpa_s->ibss_rsn, data->rx_mgmt.frame, data->rx_mgmt.frame_len); } #endif /* CONFIG_IBSS_RSN */ #ifdef CONFIG_IEEE80211R static void ft_rx_action(struct wpa_supplicant *wpa_s, const u8 *data, size_t len) { const u8 *sta_addr, *target_ap_addr; u16 status; wpa_hexdump(MSG_MSGDUMP, "FT: RX Action", data, len); if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) return; /* only SME case supported for now */ if (len < 1 + 2 * ETH_ALEN + 2) return; if (data[0] != 2) return; /* Only FT Action Response is supported for now */ sta_addr = data + 1; target_ap_addr = data + 1 + ETH_ALEN; status = WPA_GET_LE16(data + 1 + 2 * ETH_ALEN); wpa_dbg(wpa_s, MSG_DEBUG, "FT: Received FT Action Response: STA " MACSTR " TargetAP " MACSTR " status %u", MAC2STR(sta_addr), MAC2STR(target_ap_addr), status); if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) { wpa_dbg(wpa_s, MSG_DEBUG, "FT: Foreign STA Address " MACSTR " in FT Action Response", MAC2STR(sta_addr)); return; } if (status) { wpa_dbg(wpa_s, MSG_DEBUG, "FT: FT Action Response indicates " "failure (status code %d)", status); /* TODO: report error to FT code(?) */ return; } if (wpa_ft_process_response(wpa_s->wpa, data + 1 + 2 * ETH_ALEN + 2, len - (1 + 2 * ETH_ALEN + 2), 1, target_ap_addr, NULL, 0) < 0) return; #ifdef CONFIG_SME { struct wpa_bss *bss; bss = wpa_bss_get_bssid(wpa_s, target_ap_addr); if (bss) wpa_s->sme.freq = bss->freq; wpa_s->sme.auth_alg = WPA_AUTH_ALG_FT; sme_associate(wpa_s, WPAS_MODE_INFRA, target_ap_addr, WLAN_AUTH_FT); } #endif /* CONFIG_SME */ } #endif /* CONFIG_IEEE80211R */ static void wpa_supplicant_event_unprot_deauth(struct wpa_supplicant *wpa_s, struct unprot_deauth *e) { #ifdef CONFIG_IEEE80211W wpa_printf(MSG_DEBUG, "Unprotected Deauthentication frame " "dropped: " MACSTR " -> " MACSTR " (reason code %u)", MAC2STR(e->sa), MAC2STR(e->da), e->reason_code); sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code); #endif /* CONFIG_IEEE80211W */ } static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s, struct unprot_disassoc *e) { #ifdef CONFIG_IEEE80211W wpa_printf(MSG_DEBUG, "Unprotected Disassociation frame " "dropped: " MACSTR " -> " MACSTR " (reason code %u)", MAC2STR(e->sa), MAC2STR(e->da), e->reason_code); sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code); #endif /* CONFIG_IEEE80211W */ } static void wpas_event_disconnect(struct wpa_supplicant *wpa_s, const u8 *addr, u16 reason_code, int locally_generated, const u8 *ie, size_t ie_len, int deauth) { #ifdef CONFIG_AP if (wpa_s->ap_iface && addr) { hostapd_notif_disassoc(wpa_s->ap_iface->bss[0], addr); return; } if (wpa_s->ap_iface) { wpa_dbg(wpa_s, MSG_DEBUG, "Ignore deauth event in AP mode"); return; } #endif /* CONFIG_AP */ wpa_supplicant_event_disassoc(wpa_s, reason_code, locally_generated); if (((reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED || ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) || (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) && eapol_sm_failed(wpa_s->eapol))) && !wpa_s->eap_expected_failure)) wpas_auth_failed(wpa_s, "AUTH_FAILED"); #ifdef CONFIG_P2P if (deauth && reason_code > 0) { if (wpas_p2p_deauth_notif(wpa_s, addr, reason_code, ie, ie_len, locally_generated) > 0) { /* * The interface was removed, so cannot continue * processing any additional operations after this. */ return; } } #endif /* CONFIG_P2P */ wpa_supplicant_event_disassoc_finish(wpa_s, reason_code, locally_generated); } static void wpas_event_disassoc(struct wpa_supplicant *wpa_s, struct disassoc_info *info) { u16 reason_code = 0; int locally_generated = 0; const u8 *addr = NULL; const u8 *ie = NULL; size_t ie_len = 0; wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification"); if (info) { addr = info->addr; ie = info->ie; ie_len = info->ie_len; reason_code = info->reason_code; locally_generated = info->locally_generated; wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s", reason_code, locally_generated ? " (locally generated)" : ""); if (addr) wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR, MAC2STR(addr)); wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)", ie, ie_len); } #ifdef CONFIG_AP if (wpa_s->ap_iface && info && info->addr) { hostapd_notif_disassoc(wpa_s->ap_iface->bss[0], info->addr); return; } if (wpa_s->ap_iface) { wpa_dbg(wpa_s, MSG_DEBUG, "Ignore disassoc event in AP mode"); return; } #endif /* CONFIG_AP */ #ifdef CONFIG_P2P if (info) { wpas_p2p_disassoc_notif( wpa_s, info->addr, reason_code, info->ie, info->ie_len, locally_generated); } #endif /* CONFIG_P2P */ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) sme_event_disassoc(wpa_s, info); wpas_event_disconnect(wpa_s, addr, reason_code, locally_generated, ie, ie_len, 0); } static void wpas_event_deauth(struct wpa_supplicant *wpa_s, struct deauth_info *info) { u16 reason_code = 0; int locally_generated = 0; const u8 *addr = NULL; const u8 *ie = NULL; size_t ie_len = 0; wpa_dbg(wpa_s, MSG_DEBUG, "Deauthentication notification"); if (info) { addr = info->addr; ie = info->ie; ie_len = info->ie_len; reason_code = info->reason_code; locally_generated = info->locally_generated; wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s", reason_code, locally_generated ? " (locally generated)" : ""); if (addr) { wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR, MAC2STR(addr)); } wpa_hexdump(MSG_DEBUG, "Deauthentication frame IE(s)", ie, ie_len); } wpa_reset_ft_completed(wpa_s->wpa); wpas_event_disconnect(wpa_s, addr, reason_code, locally_generated, ie, ie_len, 1); } static const char * reg_init_str(enum reg_change_initiator init) { switch (init) { case REGDOM_SET_BY_CORE: return "CORE"; case REGDOM_SET_BY_USER: return "USER"; case REGDOM_SET_BY_DRIVER: return "DRIVER"; case REGDOM_SET_BY_COUNTRY_IE: return "COUNTRY_IE"; case REGDOM_BEACON_HINT: return "BEACON_HINT"; } return "?"; } static const char * reg_type_str(enum reg_type type) { switch (type) { case REGDOM_TYPE_UNKNOWN: return "UNKNOWN"; case REGDOM_TYPE_COUNTRY: return "COUNTRY"; case REGDOM_TYPE_WORLD: return "WORLD"; case REGDOM_TYPE_CUSTOM_WORLD: return "CUSTOM_WORLD"; case REGDOM_TYPE_INTERSECTION: return "INTERSECTION"; } return "?"; } static void wpa_supplicant_update_channel_list( struct wpa_supplicant *wpa_s, struct channel_list_changed *info) { struct wpa_supplicant *ifs; wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s", reg_init_str(info->type), reg_type_str(info->type), info->alpha2[0] ? " alpha2=" : "", info->alpha2[0] ? info->alpha2 : ""); if (wpa_s->drv_priv == NULL) return; /* Ignore event during drv initialization */ free_hw_features(wpa_s); wpa_s->hw.modes = wpa_drv_get_hw_feature_data( wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags); #ifdef CONFIG_P2P wpas_p2p_update_channel_list(wpa_s); #endif /* CONFIG_P2P */ /* * Check other interfaces to see if they share the same radio. If * so, they get updated with this same hw mode info. */ dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant, radio_list) { if (ifs != wpa_s) { wpa_printf(MSG_DEBUG, "%s: Updating hw mode", ifs->ifname); free_hw_features(ifs); ifs->hw.modes = wpa_drv_get_hw_feature_data( ifs, &ifs->hw.num_modes, &ifs->hw.flags); } } } static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, const struct ieee80211_mgmt *mgmt, size_t len, int freq) { const u8 *payload; size_t plen; u8 category; if (len < IEEE80211_HDRLEN + 2) return; payload = &mgmt->u.action.category; category = *payload++; plen = (((const u8 *) mgmt) + len) - payload; wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR " Category=%u DataLen=%d freq=%d MHz", MAC2STR(mgmt->sa), category, (int) plen, freq); #ifdef CONFIG_IEEE80211R if (category == WLAN_ACTION_FT) { ft_rx_action(wpa_s, payload, plen); return; } #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W #ifdef CONFIG_SME if (category == WLAN_ACTION_SA_QUERY) { sme_sa_query_rx(wpa_s, mgmt->sa, payload, plen); return; } #endif /* CONFIG_SME */ #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WNM if (mgmt->u.action.category == WLAN_ACTION_WNM) { ieee802_11_rx_wnm_action(wpa_s, mgmt, len); return; } #endif /* CONFIG_WNM */ #ifdef CONFIG_GAS if ((mgmt->u.action.category == WLAN_ACTION_PUBLIC || mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL) && gas_query_rx(wpa_s->gas, mgmt->da, mgmt->sa, mgmt->bssid, mgmt->u.action.category, payload, plen, freq) == 0) return; #endif /* CONFIG_GAS */ #ifdef CONFIG_TDLS if (category == WLAN_ACTION_PUBLIC && plen >= 4 && payload[0] == WLAN_TDLS_DISCOVERY_RESPONSE) { wpa_dbg(wpa_s, MSG_DEBUG, "TDLS: Received Discovery Response from " MACSTR, MAC2STR(mgmt->sa)); return; } #endif /* CONFIG_TDLS */ #ifdef CONFIG_INTERWORKING if (category == WLAN_ACTION_QOS && plen >= 1 && payload[0] == QOS_QOS_MAP_CONFIG) { const u8 *pos = payload + 1; size_t qlen = plen - 1; wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: Received QoS Map Configure frame from " MACSTR, MAC2STR(mgmt->sa)); if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) == 0 && qlen > 2 && pos[0] == WLAN_EID_QOS_MAP_SET && pos[1] <= qlen - 2 && pos[1] >= 16) wpas_qos_map_set(wpa_s, pos + 2, pos[1]); return; } #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_P2P wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid, category, payload, plen, freq); #endif /* CONFIG_P2P */ } static void wpa_supplicant_notify_avoid_freq(struct wpa_supplicant *wpa_s, union wpa_event_data *event) { #ifdef CONFIG_P2P struct wpa_supplicant *ifs; #endif /* CONFIG_P2P */ struct wpa_freq_range_list *list; char *str = NULL; list = &event->freq_range; if (list->num) str = freq_range_list_str(list); wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_AVOID_FREQ "ranges=%s", str ? str : ""); #ifdef CONFIG_P2P if (freq_range_list_parse(&wpa_s->global->p2p_go_avoid_freq, str)) { wpa_dbg(wpa_s, MSG_ERROR, "%s: Failed to parse freq range", __func__); } else { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Update channel list based on frequency avoid event"); wpas_p2p_update_channel_list(wpa_s); } for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) { int freq; if (!ifs->current_ssid || !ifs->current_ssid->p2p_group || (ifs->current_ssid->mode != WPAS_MODE_P2P_GO && ifs->current_ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)) continue; freq = ifs->current_ssid->frequency; if (!freq_range_list_includes(list, freq)) { wpa_dbg(ifs, MSG_DEBUG, "P2P GO operating frequency %d MHz in safe range", freq); continue; } wpa_dbg(ifs, MSG_DEBUG, "P2P GO operating in unsafe frequency %d MHz", freq); /* TODO: Consider using CSA or removing the group within * wpa_supplicant */ wpa_msg(ifs, MSG_INFO, P2P_EVENT_REMOVE_AND_REFORM_GROUP); } #endif /* CONFIG_P2P */ os_free(str); } void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { struct wpa_supplicant *wpa_s = ctx; if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED && event != EVENT_INTERFACE_ENABLED && event != EVENT_INTERFACE_STATUS && event != EVENT_SCHED_SCAN_STOPPED) { wpa_dbg(wpa_s, MSG_DEBUG, "Ignore event %s (%d) while interface is disabled", event_to_string(event), event); return; } #ifndef CONFIG_NO_STDOUT_DEBUG { int level = MSG_DEBUG; if (event == EVENT_RX_MGMT && data->rx_mgmt.frame_len >= 24) { const struct ieee80211_hdr *hdr; u16 fc; hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame; fc = le_to_host16(hdr->frame_control); if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) level = MSG_EXCESSIVE; } wpa_dbg(wpa_s, level, "Event %s (%d) received", event_to_string(event), event); } #endif /* CONFIG_NO_STDOUT_DEBUG */ switch (event) { case EVENT_AUTH: sme_event_auth(wpa_s, data); break; case EVENT_ASSOC: wpa_supplicant_event_assoc(wpa_s, data); break; case EVENT_DISASSOC: wpas_event_disassoc(wpa_s, data ? &data->disassoc_info : NULL); break; case EVENT_DEAUTH: wpas_event_deauth(wpa_s, data ? &data->deauth_info : NULL); break; case EVENT_MICHAEL_MIC_FAILURE: wpa_supplicant_event_michael_mic_failure(wpa_s, data); break; #ifndef CONFIG_NO_SCAN_PROCESSING case EVENT_SCAN_STARTED: os_get_reltime(&wpa_s->scan_start_time); if (wpa_s->own_scan_requested) { struct os_reltime diff; os_reltime_sub(&wpa_s->scan_start_time, &wpa_s->scan_trigger_time, &diff); wpa_dbg(wpa_s, MSG_DEBUG, "Own scan request started a scan in %ld.%06ld seconds", diff.sec, diff.usec); wpa_s->own_scan_requested = 0; wpa_s->own_scan_running = 1; if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && wpa_s->manual_scan_use_id) { wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED "id=%u", wpa_s->manual_scan_id); } else { wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED); } } else { wpa_dbg(wpa_s, MSG_DEBUG, "External program started a scan"); wpa_s->external_scan_running = 1; wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED); } break; case EVENT_SCAN_RESULTS: if (os_reltime_initialized(&wpa_s->scan_start_time)) { struct os_reltime now, diff; os_get_reltime(&now); os_reltime_sub(&now, &wpa_s->scan_start_time, &diff); wpa_s->scan_start_time.sec = 0; wpa_s->scan_start_time.usec = 0; wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %ld.%06ld seconds", diff.sec, diff.usec); } wpa_supplicant_event_scan_results(wpa_s, data); wpa_s->own_scan_running = 0; wpa_s->external_scan_running = 0; radio_work_check_next(wpa_s); break; #endif /* CONFIG_NO_SCAN_PROCESSING */ case EVENT_ASSOCINFO: wpa_supplicant_event_associnfo(wpa_s, data); break; case EVENT_INTERFACE_STATUS: wpa_supplicant_event_interface_status(wpa_s, data); break; case EVENT_PMKID_CANDIDATE: wpa_supplicant_event_pmkid_candidate(wpa_s, data); break; #ifdef CONFIG_PEERKEY case EVENT_STKSTART: wpa_supplicant_event_stkstart(wpa_s, data); break; #endif /* CONFIG_PEERKEY */ #ifdef CONFIG_TDLS case EVENT_TDLS: wpa_supplicant_event_tdls(wpa_s, data); break; #endif /* CONFIG_TDLS */ #ifdef CONFIG_WNM case EVENT_WNM: wpa_supplicant_event_wnm(wpa_s, data); break; #endif /* CONFIG_WNM */ #ifdef CONFIG_IEEE80211R case EVENT_FT_RESPONSE: wpa_supplicant_event_ft_response(wpa_s, data); break; #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IBSS_RSN case EVENT_IBSS_RSN_START: wpa_supplicant_event_ibss_rsn_start(wpa_s, data); break; #endif /* CONFIG_IBSS_RSN */ case EVENT_ASSOC_REJECT: if (data->assoc_reject.bssid) wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT "bssid=" MACSTR " status_code=%u", MAC2STR(data->assoc_reject.bssid), data->assoc_reject.status_code); else wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT "status_code=%u", data->assoc_reject.status_code); if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) sme_event_assoc_reject(wpa_s, data); else { const u8 *bssid = data->assoc_reject.bssid; if (bssid == NULL || is_zero_ether_addr(bssid)) bssid = wpa_s->pending_bssid; wpas_connection_failed(wpa_s, bssid); wpa_supplicant_mark_disassoc(wpa_s); } break; case EVENT_AUTH_TIMED_OUT: if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) sme_event_auth_timed_out(wpa_s, data); break; case EVENT_ASSOC_TIMED_OUT: if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) sme_event_assoc_timed_out(wpa_s, data); break; case EVENT_TX_STATUS: wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS dst=" MACSTR " type=%d stype=%d", MAC2STR(data->tx_status.dst), data->tx_status.type, data->tx_status.stype); #ifdef CONFIG_AP if (wpa_s->ap_iface == NULL) { #ifdef CONFIG_OFFCHANNEL if (data->tx_status.type == WLAN_FC_TYPE_MGMT && data->tx_status.stype == WLAN_FC_STYPE_ACTION) offchannel_send_action_tx_status( wpa_s, data->tx_status.dst, data->tx_status.data, data->tx_status.data_len, data->tx_status.ack ? OFFCHANNEL_SEND_ACTION_SUCCESS : OFFCHANNEL_SEND_ACTION_NO_ACK); #endif /* CONFIG_OFFCHANNEL */ break; } #endif /* CONFIG_AP */ #ifdef CONFIG_OFFCHANNEL wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS pending_dst=" MACSTR, MAC2STR(wpa_s->parent->pending_action_dst)); /* * Catch TX status events for Action frames we sent via group * interface in GO mode. */ if (data->tx_status.type == WLAN_FC_TYPE_MGMT && data->tx_status.stype == WLAN_FC_STYPE_ACTION && os_memcmp(wpa_s->parent->pending_action_dst, data->tx_status.dst, ETH_ALEN) == 0) { offchannel_send_action_tx_status( wpa_s->parent, data->tx_status.dst, data->tx_status.data, data->tx_status.data_len, data->tx_status.ack ? OFFCHANNEL_SEND_ACTION_SUCCESS : OFFCHANNEL_SEND_ACTION_NO_ACK); break; } #endif /* CONFIG_OFFCHANNEL */ #ifdef CONFIG_AP switch (data->tx_status.type) { case WLAN_FC_TYPE_MGMT: ap_mgmt_tx_cb(wpa_s, data->tx_status.data, data->tx_status.data_len, data->tx_status.stype, data->tx_status.ack); break; case WLAN_FC_TYPE_DATA: ap_tx_status(wpa_s, data->tx_status.dst, data->tx_status.data, data->tx_status.data_len, data->tx_status.ack); break; } #endif /* CONFIG_AP */ break; #ifdef CONFIG_AP case EVENT_EAPOL_TX_STATUS: ap_eapol_tx_status(wpa_s, data->eapol_tx_status.dst, data->eapol_tx_status.data, data->eapol_tx_status.data_len, data->eapol_tx_status.ack); break; case EVENT_DRIVER_CLIENT_POLL_OK: ap_client_poll_ok(wpa_s, data->client_poll.addr); break; case EVENT_RX_FROM_UNKNOWN: if (wpa_s->ap_iface == NULL) break; ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr, data->rx_from_unknown.wds); break; case EVENT_CH_SWITCH: if (!data) break; if (!wpa_s->ap_iface) { wpa_dbg(wpa_s, MSG_DEBUG, "AP: Ignore channel switch " "event in non-AP mode"); break; } wpas_ap_ch_switch(wpa_s, data->ch_switch.freq, data->ch_switch.ht_enabled, data->ch_switch.ch_offset, data->ch_switch.ch_width, data->ch_switch.cf1, data->ch_switch.cf2); break; #endif /* CONFIG_AP */ case EVENT_RX_MGMT: { u16 fc, stype; const struct ieee80211_mgmt *mgmt; #ifdef CONFIG_TESTING_OPTIONS if (wpa_s->ext_mgmt_frame_handling) { struct rx_mgmt *rx = &data->rx_mgmt; size_t hex_len = 2 * rx->frame_len + 1; char *hex = os_malloc(hex_len); if (hex) { wpa_snprintf_hex(hex, hex_len, rx->frame, rx->frame_len); wpa_msg(wpa_s, MSG_INFO, "MGMT-RX freq=%d datarate=%u ssi_signal=%d %s", rx->freq, rx->datarate, rx->ssi_signal, hex); os_free(hex); } break; } #endif /* CONFIG_TESTING_OPTIONS */ mgmt = (const struct ieee80211_mgmt *) data->rx_mgmt.frame; fc = le_to_host16(mgmt->frame_control); stype = WLAN_FC_GET_STYPE(fc); #ifdef CONFIG_AP if (wpa_s->ap_iface == NULL) { #endif /* CONFIG_AP */ #ifdef CONFIG_P2P if (stype == WLAN_FC_STYPE_PROBE_REQ && data->rx_mgmt.frame_len > 24) { const u8 *src = mgmt->sa; const u8 *ie = mgmt->u.probe_req.variable; size_t ie_len = data->rx_mgmt.frame_len - (mgmt->u.probe_req.variable - data->rx_mgmt.frame); wpas_p2p_probe_req_rx( wpa_s, src, mgmt->da, mgmt->bssid, ie, ie_len, data->rx_mgmt.ssi_signal); break; } #endif /* CONFIG_P2P */ #ifdef CONFIG_IBSS_RSN if (stype == WLAN_FC_STYPE_AUTH && data->rx_mgmt.frame_len >= 30) { wpa_supplicant_event_ibss_auth(wpa_s, data); break; } #endif /* CONFIG_IBSS_RSN */ if (stype == WLAN_FC_STYPE_ACTION) { wpas_event_rx_mgmt_action( wpa_s, mgmt, data->rx_mgmt.frame_len, data->rx_mgmt.freq); break; } wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received " "management frame in non-AP mode"); break; #ifdef CONFIG_AP } if (stype == WLAN_FC_STYPE_PROBE_REQ && data->rx_mgmt.frame_len > 24) { const u8 *ie = mgmt->u.probe_req.variable; size_t ie_len = data->rx_mgmt.frame_len - (mgmt->u.probe_req.variable - data->rx_mgmt.frame); wpas_notify_preq(wpa_s, mgmt->sa, mgmt->da, mgmt->bssid, ie, ie_len, data->rx_mgmt.ssi_signal); } ap_mgmt_rx(wpa_s, &data->rx_mgmt); #endif /* CONFIG_AP */ break; } case EVENT_RX_PROBE_REQ: if (data->rx_probe_req.sa == NULL || data->rx_probe_req.ie == NULL) break; #ifdef CONFIG_AP if (wpa_s->ap_iface) { hostapd_probe_req_rx(wpa_s->ap_iface->bss[0], data->rx_probe_req.sa, data->rx_probe_req.da, data->rx_probe_req.bssid, data->rx_probe_req.ie, data->rx_probe_req.ie_len, data->rx_probe_req.ssi_signal); break; } #endif /* CONFIG_AP */ #ifdef CONFIG_P2P wpas_p2p_probe_req_rx(wpa_s, data->rx_probe_req.sa, data->rx_probe_req.da, data->rx_probe_req.bssid, data->rx_probe_req.ie, data->rx_probe_req.ie_len, data->rx_probe_req.ssi_signal); #endif /* CONFIG_P2P */ break; case EVENT_REMAIN_ON_CHANNEL: #ifdef CONFIG_OFFCHANNEL offchannel_remain_on_channel_cb( wpa_s, data->remain_on_channel.freq, data->remain_on_channel.duration); #endif /* CONFIG_OFFCHANNEL */ #ifdef CONFIG_P2P wpas_p2p_remain_on_channel_cb( wpa_s, data->remain_on_channel.freq, data->remain_on_channel.duration); #endif /* CONFIG_P2P */ break; case EVENT_CANCEL_REMAIN_ON_CHANNEL: #ifdef CONFIG_OFFCHANNEL offchannel_cancel_remain_on_channel_cb( wpa_s, data->remain_on_channel.freq); #endif /* CONFIG_OFFCHANNEL */ #ifdef CONFIG_P2P wpas_p2p_cancel_remain_on_channel_cb( wpa_s, data->remain_on_channel.freq); #endif /* CONFIG_P2P */ break; case EVENT_EAPOL_RX: wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src, data->eapol_rx.data, data->eapol_rx.data_len); break; case EVENT_SIGNAL_CHANGE: wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SIGNAL_CHANGE "above=%d signal=%d noise=%d txrate=%d", data->signal_change.above_threshold, data->signal_change.current_signal, data->signal_change.current_noise, data->signal_change.current_txrate); bgscan_notify_signal_change( wpa_s, data->signal_change.above_threshold, data->signal_change.current_signal, data->signal_change.current_noise, data->signal_change.current_txrate); break; case EVENT_INTERFACE_ENABLED: wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled"); if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_supplicant_update_mac_addr(wpa_s); if (wpa_s->p2p_mgmt) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); break; } #ifdef CONFIG_AP if (!wpa_s->ap_iface) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); wpa_supplicant_req_scan(wpa_s, 0, 0); } else wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); #else /* CONFIG_AP */ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); wpa_supplicant_req_scan(wpa_s, 0, 0); #endif /* CONFIG_AP */ } break; case EVENT_INTERFACE_DISABLED: wpa_dbg(wpa_s, MSG_DEBUG, "Interface was disabled"); #ifdef CONFIG_P2P if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO || (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group && wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO)) { /* * The interface was externally disabled. Remove * it assuming an external entity will start a * new session if needed. */ wpas_p2p_disconnect(wpa_s); break; } if (wpa_s->p2p_scan_work && wpa_s->global->p2p && p2p_in_progress(wpa_s->global->p2p) > 1) { /* This radio work will be cancelled, so clear P2P * state as well. */ p2p_stop_find(wpa_s->global->p2p); } #endif /* CONFIG_P2P */ if (wpa_s->wpa_state >= WPA_AUTHENTICATING) { /* * Indicate disconnection to keep ctrl_iface events * consistent. */ wpa_supplicant_event_disassoc( wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1); } wpa_supplicant_mark_disassoc(wpa_s); radio_remove_works(wpa_s, NULL, 0); wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED); break; case EVENT_CHANNEL_LIST_CHANGED: wpa_supplicant_update_channel_list( wpa_s, &data->channel_list_changed); break; case EVENT_INTERFACE_UNAVAILABLE: #ifdef CONFIG_P2P wpas_p2p_interface_unavailable(wpa_s); #endif /* CONFIG_P2P */ break; case EVENT_BEST_CHANNEL: wpa_dbg(wpa_s, MSG_DEBUG, "Best channel event received " "(%d %d %d)", data->best_chan.freq_24, data->best_chan.freq_5, data->best_chan.freq_overall); wpa_s->best_24_freq = data->best_chan.freq_24; wpa_s->best_5_freq = data->best_chan.freq_5; wpa_s->best_overall_freq = data->best_chan.freq_overall; #ifdef CONFIG_P2P wpas_p2p_update_best_channels(wpa_s, data->best_chan.freq_24, data->best_chan.freq_5, data->best_chan.freq_overall); #endif /* CONFIG_P2P */ break; case EVENT_UNPROT_DEAUTH: wpa_supplicant_event_unprot_deauth(wpa_s, &data->unprot_deauth); break; case EVENT_UNPROT_DISASSOC: wpa_supplicant_event_unprot_disassoc(wpa_s, &data->unprot_disassoc); break; case EVENT_STATION_LOW_ACK: #ifdef CONFIG_AP if (wpa_s->ap_iface && data) hostapd_event_sta_low_ack(wpa_s->ap_iface->bss[0], data->low_ack.addr); #endif /* CONFIG_AP */ #ifdef CONFIG_TDLS if (data) wpa_tdls_disable_link(wpa_s->wpa, data->low_ack.addr); #endif /* CONFIG_TDLS */ break; case EVENT_IBSS_PEER_LOST: #ifdef CONFIG_IBSS_RSN ibss_rsn_stop(wpa_s->ibss_rsn, data->ibss_peer_lost.peer); #endif /* CONFIG_IBSS_RSN */ break; case EVENT_DRIVER_GTK_REKEY: if (os_memcmp(data->driver_gtk_rekey.bssid, wpa_s->bssid, ETH_ALEN)) break; if (!wpa_s->wpa) break; wpa_sm_update_replay_ctr(wpa_s->wpa, data->driver_gtk_rekey.replay_ctr); break; case EVENT_SCHED_SCAN_STOPPED: wpa_s->pno = 0; wpa_s->sched_scanning = 0; wpa_supplicant_notify_scanning(wpa_s, 0); if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) break; /* * Start a new sched scan to continue searching for more SSIDs * either if timed out or PNO schedule scan is pending. */ if (wpa_s->sched_scan_timed_out) { wpa_supplicant_req_sched_scan(wpa_s); } else if (wpa_s->pno_sched_pending) { wpa_s->pno_sched_pending = 0; wpas_start_pno(wpa_s); } break; case EVENT_WPS_BUTTON_PUSHED: #ifdef CONFIG_WPS wpas_wps_start_pbc(wpa_s, NULL, 0); #endif /* CONFIG_WPS */ break; case EVENT_AVOID_FREQUENCIES: wpa_supplicant_notify_avoid_freq(wpa_s, data); break; case EVENT_CONNECT_FAILED_REASON: #ifdef CONFIG_AP if (!wpa_s->ap_iface || !data) break; hostapd_event_connect_failed_reason( wpa_s->ap_iface->bss[0], data->connect_failed_reason.addr, data->connect_failed_reason.code); #endif /* CONFIG_AP */ break; default: wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event); break; } } wpa_supplicant-2.2/wpa_supplicant/offchannel.h0000664000175000017500000000257212343617166017532 0ustar jmjm/* * wpa_supplicant - Off-channel Action frame TX/RX * Copyright (c) 2009-2010, Atheros Communications * Copyright (c) 2011, Qualcomm Atheros * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef OFFCHANNEL_H #define OFFCHANNEL_H int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *buf, size_t len, unsigned int wait_time, void (*tx_cb)(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *data, size_t data_len, enum offchannel_send_action_result result), int no_cck); void offchannel_send_action_done(struct wpa_supplicant *wpa_s); void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq, unsigned int duration); void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq); void offchannel_deinit(struct wpa_supplicant *wpa_s); void offchannel_send_action_tx_status( struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data, size_t data_len, enum offchannel_send_action_result result); const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s); void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s); #endif /* OFFCHANNEL_H */ wpa_supplicant-2.2/wpa_supplicant/.gitignore0000664000175000017500000000001212343617166017231 0ustar jmjm*.service wpa_supplicant-2.2/wpa_supplicant/preauth_test.c0000664000175000017500000002061212343617166020124 0ustar jmjm/* * WPA Supplicant - test code for pre-authentication * Copyright (c) 2003-2007, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. * * IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c. * Not used in production version. */ #include "includes.h" #include #include "common.h" #include "config.h" #include "eapol_supp/eapol_supp_sm.h" #include "eloop.h" #include "rsn_supp/wpa.h" #include "eap_peer/eap.h" #include "wpa_supplicant_i.h" #include "l2_packet/l2_packet.h" #include "ctrl_iface.h" #include "pcsc_funcs.h" #include "rsn_supp/preauth.h" #include "rsn_supp/pmksa_cache.h" #include "drivers/driver.h" struct wpa_driver_ops *wpa_drivers[] = { NULL }; struct preauth_test_data { int auth_timed_out; }; static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code) { wpa_supplicant_deauthenticate(wpa_s, reason_code); } static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type, const void *data, u16 data_len, size_t *msg_len, void **data_pos) { struct ieee802_1x_hdr *hdr; *msg_len = sizeof(*hdr) + data_len; hdr = os_malloc(*msg_len); if (hdr == NULL) return NULL; hdr->version = wpa_s->conf->eapol_version; hdr->type = type; hdr->length = htons(data_len); if (data) os_memcpy(hdr + 1, data, data_len); else os_memset(hdr + 1, 0, data_len); if (data_pos) *data_pos = hdr + 1; return (u8 *) hdr; } static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type, const void *data, u16 data_len, size_t *msg_len, void **data_pos) { return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos); } static void _wpa_supplicant_set_state(void *ctx, enum wpa_states state) { struct wpa_supplicant *wpa_s = ctx; wpa_s->wpa_state = state; } static enum wpa_states _wpa_supplicant_get_state(void *ctx) { struct wpa_supplicant *wpa_s = ctx; return wpa_s->wpa_state; } static int wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto, const u8 *buf, size_t len) { printf("%s - not implemented\n", __func__); return -1; } static void * wpa_supplicant_get_network_ctx(void *wpa_s) { return wpa_supplicant_get_ssid(wpa_s); } static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s) { wpa_supplicant_cancel_auth_timeout(wpa_s); } static int wpa_supplicant_get_beacon_ie(void *wpa_s) { printf("%s - not implemented\n", __func__); return -1; } static int wpa_supplicant_get_bssid(void *wpa_s, u8 *bssid) { printf("%s - not implemented\n", __func__); return -1; } static int wpa_supplicant_set_key(void *wpa_s, 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) { printf("%s - not implemented\n", __func__); return -1; } static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr, int protection_type, int key_type) { printf("%s - not implemented\n", __func__); return -1; } static int wpa_supplicant_add_pmkid(void *wpa_s, const u8 *bssid, const u8 *pmkid) { printf("%s - not implemented\n", __func__); return -1; } static int wpa_supplicant_remove_pmkid(void *wpa_s, const u8 *bssid, const u8 *pmkid) { printf("%s - not implemented\n", __func__); return -1; } static void wpa_supplicant_set_config_blob(void *ctx, struct wpa_config_blob *blob) { struct wpa_supplicant *wpa_s = ctx; wpa_config_set_blob(wpa_s->conf, blob); } static const struct wpa_config_blob * wpa_supplicant_get_config_blob(void *ctx, const char *name) { struct wpa_supplicant *wpa_s = ctx; return wpa_config_get_blob(wpa_s->conf, name); } static void test_eapol_clean(struct wpa_supplicant *wpa_s) { rsn_preauth_deinit(wpa_s->wpa); pmksa_candidate_free(wpa_s->wpa); wpa_sm_deinit(wpa_s->wpa); scard_deinit(wpa_s->scard); if (wpa_s->ctrl_iface) { wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); wpa_s->ctrl_iface = NULL; } wpa_config_free(wpa_s->conf); } static void eapol_test_timeout(void *eloop_ctx, void *timeout_ctx) { struct preauth_test_data *p = eloop_ctx; printf("EAPOL test timed out\n"); p->auth_timed_out = 1; eloop_terminate(); } static void eapol_test_poll(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; if (!rsn_preauth_in_progress(wpa_s->wpa)) eloop_terminate(); else { eloop_register_timeout(0, 100000, eapol_test_poll, eloop_ctx, timeout_ctx); } } static struct wpa_driver_ops dummy_driver; static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname) { struct l2_packet_data *l2; struct wpa_sm_ctx *ctx; os_memset(&dummy_driver, 0, sizeof(dummy_driver)); wpa_s->driver = &dummy_driver; ctx = os_zalloc(sizeof(*ctx)); assert(ctx != NULL); ctx->ctx = wpa_s; ctx->msg_ctx = wpa_s; ctx->set_state = _wpa_supplicant_set_state; ctx->get_state = _wpa_supplicant_get_state; ctx->deauthenticate = _wpa_supplicant_deauthenticate; ctx->set_key = wpa_supplicant_set_key; ctx->get_network_ctx = wpa_supplicant_get_network_ctx; ctx->get_bssid = wpa_supplicant_get_bssid; ctx->ether_send = wpa_ether_send; ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie; ctx->alloc_eapol = _wpa_alloc_eapol; ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout; ctx->add_pmkid = wpa_supplicant_add_pmkid; ctx->remove_pmkid = wpa_supplicant_remove_pmkid; ctx->set_config_blob = wpa_supplicant_set_config_blob; ctx->get_config_blob = wpa_supplicant_get_config_blob; ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection; wpa_s->wpa = wpa_sm_init(ctx); assert(wpa_s->wpa != NULL); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, WPA_PROTO_RSN); os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname)); wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname, NULL); l2 = l2_packet_init(wpa_s->ifname, NULL, ETH_P_RSN_PREAUTH, NULL, NULL, 0); assert(l2 != NULL); if (l2_packet_get_own_addr(l2, wpa_s->own_addr)) { wpa_printf(MSG_WARNING, "Failed to get own L2 address\n"); exit(-1); } l2_packet_deinit(l2); wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr); } static void eapol_test_terminate(int sig, void *signal_ctx) { struct wpa_supplicant *wpa_s = signal_ctx; wpa_msg(wpa_s, MSG_INFO, "Signal %d received - terminating", sig); eloop_terminate(); } int main(int argc, char *argv[]) { struct wpa_supplicant wpa_s; int ret = 1; u8 bssid[ETH_ALEN]; struct preauth_test_data preauth_test; if (os_program_init()) return -1; os_memset(&preauth_test, 0, sizeof(preauth_test)); wpa_debug_level = 0; wpa_debug_show_keys = 1; if (argc != 4) { printf("usage: preauth_test " "\n"); return -1; } if (hwaddr_aton(argv[2], bssid)) { printf("Failed to parse target address '%s'.\n", argv[2]); return -1; } if (eap_register_methods()) { wpa_printf(MSG_ERROR, "Failed to register EAP methods"); return -1; } if (eloop_init()) { wpa_printf(MSG_ERROR, "Failed to initialize event loop"); return -1; } os_memset(&wpa_s, 0, sizeof(wpa_s)); wpa_s.conf = wpa_config_read(argv[1], NULL); if (wpa_s.conf == NULL) { printf("Failed to parse configuration file '%s'.\n", argv[1]); return -1; } if (wpa_s.conf->ssid == NULL) { printf("No networks defined.\n"); return -1; } wpa_init_conf(&wpa_s, argv[3]); wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s); if (wpa_s.ctrl_iface == NULL) { printf("Failed to initialize control interface '%s'.\n" "You may have another preauth_test process already " "running or the file was\n" "left by an unclean termination of preauth_test in " "which case you will need\n" "to manually remove this file before starting " "preauth_test again.\n", wpa_s.conf->ctrl_interface); return -1; } if (wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid)) return -1; if (rsn_preauth_init(wpa_s.wpa, bssid, &wpa_s.conf->ssid->eap)) return -1; eloop_register_timeout(30, 0, eapol_test_timeout, &preauth_test, NULL); eloop_register_timeout(0, 100000, eapol_test_poll, &wpa_s, NULL); eloop_register_signal_terminate(eapol_test_terminate, &wpa_s); eloop_register_signal_reconfig(eapol_test_terminate, &wpa_s); eloop_run(); if (preauth_test.auth_timed_out) ret = -2; else { ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0) ? 0 : -3; } test_eapol_clean(&wpa_s); eap_peer_unregister_methods(); eloop_destroy(); os_program_deinit(); return ret; } wpa_supplicant-2.2/wpa_supplicant/bgscan.h0000664000175000017500000000350512343617166016661 0ustar jmjm/* * WPA Supplicant - background scan and roaming interface * Copyright (c) 2009-2010, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef BGSCAN_H #define BGSCAN_H struct wpa_supplicant; struct wpa_ssid; struct bgscan_ops { const char *name; void * (*init)(struct wpa_supplicant *wpa_s, const char *params, const struct wpa_ssid *ssid); void (*deinit)(void *priv); int (*notify_scan)(void *priv, struct wpa_scan_results *scan_res); void (*notify_beacon_loss)(void *priv); void (*notify_signal_change)(void *priv, int above, int current_signal, int current_noise, int current_txrate); }; #ifdef CONFIG_BGSCAN int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, const char *name); void bgscan_deinit(struct wpa_supplicant *wpa_s); int bgscan_notify_scan(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s); void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above, int current_signal, int current_noise, int current_txrate); #else /* CONFIG_BGSCAN */ static inline int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, const char name) { return 0; } static inline void bgscan_deinit(struct wpa_supplicant *wpa_s) { } static inline int bgscan_notify_scan(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { return 0; } static inline void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s) { } static inline void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above, int current_signal, int current_noise, int current_txrate) { } #endif /* CONFIG_BGSCAN */ #endif /* BGSCAN_H */ wpa_supplicant-2.2/wpa_supplicant/interworking.h0000664000175000017500000000244512343617166020150 0ustar jmjm/* * Interworking (IEEE 802.11u) * Copyright (c) 2011-2012, Qualcomm Atheros * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #ifndef INTERWORKING_H #define INTERWORKING_H enum gas_query_result; int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u16 info_ids[], size_t num_ids, u32 subtypes); void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, const struct wpabuf *resp, u16 status_code); int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *adv_proto, const struct wpabuf *query); int interworking_fetch_anqp(struct wpa_supplicant *wpa_s); void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s); int interworking_select(struct wpa_supplicant *wpa_s, int auto_select, int *freqs); int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss); void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s); int interworking_home_sp_cred(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpabuf *domain_names); int domain_name_list_contains(struct wpabuf *domain_names, const char *domain, int exact_match); #endif /* INTERWORKING_H */ wpa_supplicant-2.2/wpa_supplicant/doc/0000775000175000017500000000000012343617166016015 5ustar jmjmwpa_supplicant-2.2/wpa_supplicant/doc/docbook/0000775000175000017500000000000012343703240017422 5ustar jmjmwpa_supplicant-2.2/wpa_supplicant/doc/docbook/wpa_priv.sgml0000664000175000017500000001221112343617166022145 0ustar jmjm wpa_priv 8 wpa_priv wpa_supplicant privilege separation helper wpa_priv -c ctrl path -Bdd -P pid file driver:ifname [driver:ifname ...] Overview wpa_priv is a privilege separation helper that minimizes the size of wpa_supplicant code that needs to be run with root privileges. If enabled, privileged operations are done in the wpa_priv process while leaving rest of the code (e.g., EAP authentication and WPA handshakes) to operate in an unprivileged process (wpa_supplicant) that can be run as non-root user. Privilege separation restricts the effects of potential software errors by containing the majority of the code in an unprivileged process to avoid the possibility of a full system compromise. wpa_priv needs to be run with network admin privileges (usually, root user). It opens a UNIX domain socket for each interface that is included on the command line; any other interface will be off limits for wpa_supplicant in this kind of configuration. After this, wpa_supplicant can be run as a non-root user (e.g., all standard users on a laptop or as a special non-privileged user account created just for this purpose to limit access to user files even further). Example configuration The following steps are an example of how to configure wpa_priv to allow users in the wpapriv group to communicate with wpa_supplicant with privilege separation: Create user group (e.g., wpapriv) and assign users that should be able to use wpa_supplicant into that group. Create /var/run/wpa_priv directory for UNIX domain sockets and control user access by setting it accessible only for the wpapriv group:
mkdir /var/run/wpa_priv chown root:wpapriv /var/run/wpa_priv chmod 0750 /var/run/wpa_priv
Start wpa_priv as root (e.g., from system startup scripts) with the enabled interfaces configured on the command line:
wpa_priv -B -c /var/run/wpa_priv -P /var/run/wpa_priv.pid wext:wlan0
Run wpa_supplicant as non-root with a user that is in the wpapriv group:
wpa_supplicant -i ath0 -c wpa_supplicant.conf
Command Arguments -c ctrl path Specify the path to wpa_priv control directory (Default: /var/run/wpa_priv/). -B Run as a daemon in the background. -P file Set the location of the PID file. driver:ifname [driver:ifname ...] The <driver> string dictates which of the supported wpa_supplicant driver backends is to be used. To get a list of supported driver types see wpa_supplicant help (e.g, wpa_supplicant -h). The driver backend supported by most good drivers is wext. The <ifname> string specifies which network interface is to be managed by wpa_supplicant (e.g., wlan0 or ath0). wpa_priv does not use the network interface before wpa_supplicant is started, so it is fine to include network interfaces that are not available at the time wpa_priv is started. wpa_priv can control multiple interfaces with one process, but it is also possible to run multiple wpa_priv processes at the same time, if desired. See Also wpa_supplicant 8 Legal wpa_supplicant is copyright (c) 2003-2014, Jouni Malinen j@w1.fi and contributors. All Rights Reserved. This program is licensed under the BSD license (the one with advertisement clause removed).
wpa_supplicant-2.2/wpa_supplicant/doc/docbook/wpa_cli.sgml0000664000175000017500000002467512343617166021755 0ustar jmjm wpa_cli 8 wpa_cli WPA command line client wpa_cli -p path to ctrl sockets -g path to global ctrl_interface socket -i ifname -hvB -a action file -P pid file -G ping interval command ... Overview wpa_cli is a text-based frontend program for interacting with wpa_supplicant. It is used to query current status, change configuration, trigger events, and request interactive user input. wpa_cli can show the current authentication status, selected security mode, dot11 and dot1x MIBs, etc. In addition, it can configure some variables like EAPOL state machine parameters and trigger events like reassociation and IEEE 802.1X logoff/logon. wpa_cli provides a user interface to request authentication information, like username and password, if these are not included in the configuration. This can be used to implement, e.g., one-time-passwords or generic token card authentication where the authentication is based on a challenge-response that uses an external device for generating the response. The control interface of wpa_supplicant can be configured to allow non-root user access (ctrl_interface GROUP= parameter in the configuration file). This makes it possible to run wpa_cli with a normal user account. wpa_cli supports two modes: interactive and command line. Both modes share the same command set and the main difference is in interactive mode providing access to unsolicited messages (event messages, username/password requests). Interactive mode is started when wpa_cli is executed without including the command as a command line parameter. Commands are then entered on the wpa_cli prompt. In command line mode, the same commands are entered as command line arguments for wpa_cli. Interactive authentication parameters request When wpa_supplicant need authentication parameters, like username and password, which are not present in the configuration file, it sends a request message to all attached frontend programs, e.g., wpa_cli in interactive mode. wpa_cli shows these requests with "CTRL-REQ-<type>-<id>:<text>" prefix. <type> is IDENTITY, PASSWORD, or OTP (one-time-password). <id> is a unique identifier for the current network. <text> is description of the request. In case of OTP request, it includes the challenge from the authentication server. The reply to these requests can be given with identity, password, and otp commands. <id> needs to be copied from the matching request. password and otp commands can be used regardless of whether the request was for PASSWORD or OTP. The main difference between these two commands is that values given with password are remembered as long as wpa_supplicant is running whereas values given with otp are used only once and then forgotten, i.e., wpa_supplicant will ask frontend for a new value for every use. This can be used to implement one-time-password lists and generic token card -based authentication. Example request for password and a matching reply:
CTRL-REQ-PASSWORD-1:Password needed for SSID foobar > password 1 mysecretpassword
Example request for generic token card challenge-response:
CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar > otp 2 9876
Command Arguments -p path Change the path where control sockets should be found. -g control socket path Connect to the global control socket at the indicated path rather than an interface-specific control socket. -i ifname Specify the interface that is being configured. By default, choose the first interface found with a control socket in the socket path. -h Help. Show a usage message. -v Show version information. -B Run as a daemon in the background. -a file Run in daemon mode executing the action file based on events from wpa_supplicant. The specified file will be executed with the first argument set to interface name and second to "CONNECTED" or "DISCONNECTED" depending on the event. This can be used to execute networking tools required to configure the interface. Additionally, three environmental variables are available to the file: WPA_CTRL_DIR, WPA_ID, and WPA_ID_STR. WPA_CTRL_DIR contains the absolute path to the ctrl_interface socket. WPA_ID contains the unique network_id identifier assigned to the active network, and WPA_ID_STR contains the content of the id_str option. -P file Set the location of the PID file. -G ping interval Set the interval (in seconds) at which wpa_cli pings the supplicant. command Run a command. The available commands are listed in the next section. Commands The following commands are available: status get current WPA/EAPOL/EAP status mib get MIB variables (dot1x, dot11) help show this usage help interface [ifname] show interfaces/select interface level <debug level> change debug level license show full wpa_cli license logoff IEEE 802.1X EAPOL state machine logoff logon IEEE 802.1X EAPOL state machine logon set set variables (shows list of variables when run without arguments) pmksa show PMKSA cache reassociate force reassociation reconfigure force wpa_supplicant to re-read its configuration file preauthenticate <BSSID> force preauthentication identity <network id> <identity> configure identity for an SSID password <network id> <password> configure password for an SSID pin <network id> <pin> configure pin for an SSID otp <network id> <password> configure one-time-password for an SSID bssid <network id> <BSSID> set preferred BSSID for an SSID list_networks list configured networks terminate terminate wpa_supplicant quit exit wpa_cli See Also wpa_supplicant 8 Legal wpa_supplicant is copyright (c) 2003-2014, Jouni Malinen j@w1.fi and contributors. All Rights Reserved. This program is licensed under the BSD license (the one with advertisement clause removed).
wpa_supplicant-2.2/wpa_supplicant/doc/docbook/eapol_test.80000664000175000017500000001011312343703240021646 0ustar jmjm.\" This manpage has been automatically generated by docbook2man .\" from a DocBook document. This tool can be found at: .\" .\" Please send any bug reports, improvements, comments, patches, .\" etc. to Steve Cheng . .TH "EAPOL_TEST" "8" "04 June 2014" "" "" .SH NAME eapol_test \- EAP peer and RADIUS client testing .SH SYNOPSIS \fBeapol_test\fR [ \fB-nWS\fR ] [ \fB-c\fIconfig file\fB\fR ] [ \fB-a\fIserver IP address\fB\fR ] [ \fB-A\fIclient IP address\fB\fR ] [ \fB-p\fIUDP port\fB\fR ] [ \fB-s\fIshared secret\fB\fR ] [ \fB-r\fIre-authentications\fB\fR ] [ \fB-t\fItimeout\fB\fR ] [ \fB-C\fIConnect-Info\fB\fR ] [ \fB-M\fIMAC address\fB\fR ] [ \fB-o\fIfile\fB\fR ] [ \fB-N\fIattr spec\fB\fR ] \fBeapol_test scard\fR \fBeapol_test sim\fR [ \fBPIN\fR ] [ \fBnum triplets\fR ] .SH "OVERVIEW" .PP eapol_test is a program that links together the same EAP peer implementation that wpa_supplicant is using and the RADIUS authentication client code from hostapd. In addition, it has minimal glue code to combine these two components in similar ways to IEEE 802.1X/EAPOL Authenticator state machines. In other words, it integrates IEEE 802.1X Authenticator (normally, an access point) and IEEE 802.1X Supplicant (normally, a wireless client) together to generate a single program that can be used to test EAP methods without having to setup an access point and a wireless client. .PP The main uses for eapol_test are in interoperability testing of EAP methods against RADIUS servers and in development testing for new EAP methods. It can be easily used to automate EAP testing for interoperability and regression since the program can be run from shell scripts without require additional test components apart from a RADIUS server. For example, the automated EAP tests described in eap_testing.txt are implemented with eapol_test. Similarly, eapol_test could be used to implement an automated regression test suite for a RADIUS authentication server. .PP As an example: .sp .RS .nf eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1 .fi .RE .PP tries to complete EAP authentication based on the network configuration from test.conf against the RADIUS server running on the local host. A re-authentication is triggered to test fast re-authentication. The configuration file uses the same format for network blocks as wpa_supplicant. .SH "COMMAND ARGUMENTS" .TP \fB-c configuration file path\fR A configuration to use. The configuration should use the same format for network blocks as wpa_supplicant. .TP \fB-a AS address\fR IP address of the authentication server. The default is '127.0.0.1'. .TP \fB-A client address\fR IP address of the client. The default is to select an address automatically. .TP \fB-p AS port\fR UDP port of the authentication server. The default is '1812'. .TP \fB-s AS secret\fR Shared secret with the authentication server. The default is 'radius'. .TP \fB-r count\fR Number of reauthentications. .TP \fB-t timeout\fR Timeout in seconds. The default is 30. .TP \fB-C info\fR RADIUS Connect-Info. The default is \&'CONNECT 11Mbps 802.11b'. .TP \fB-M mac address\fR Client MAC address (Calling-Station-Id). The default is '02:00:00:00:00:01'. .TP \fB-o file\fR Location to write out server certificate. .TP \fB-N attr spec\fR Send arbitrary attribute specific by attr_id:syntax:value, or attr_id alone. attr_id should be the numeric ID of the attribute, and syntax should be one of 's' (string), \&'d' (integer), or 'x' (octet string). The value is the attribute value to send. When attr_id is given alone, NULL is used as the attribute value. Multiple attributes can be specified by using the option several times. .TP \fB-n\fR Indicates that no MPPE keys are expected. .TP \fB-W\fR Wait for a control interface monitor before starting. .TP \fB-S\fR Save configuration after authentication. .SH "SEE ALSO" .PP \fBwpa_supplicant\fR(8) .SH "LEGAL" .PP wpa_supplicant is copyright (c) 2003-2014, Jouni Malinen and contributors. All Rights Reserved. .PP This program is licensed under the BSD license (the one with advertisement clause removed). wpa_supplicant-2.2/wpa_supplicant/doc/docbook/manpage.refs0000664000175000017500000000003312343703240021707 0ustar jmjm{ '' => '', '' => '' } wpa_supplicant-2.2/wpa_supplicant/doc/docbook/wpa_supplicant.80000664000175000017500000003262712343703240022556 0ustar jmjm.\" This manpage has been automatically generated by docbook2man .\" from a DocBook document. This tool can be found at: .\" .\" Please send any bug reports, improvements, comments, patches, .\" etc. to Steve Cheng . .TH "WPA_SUPPLICANT" "8" "04 June 2014" "" "" .SH NAME wpa_supplicant \- Wi-Fi Protected Access client and IEEE 802.1X supplicant .SH SYNOPSIS \fBwpa_supplicant\fR [ \fB-BddfhKLqqsTtuvW\fR ] [ \fB-i\fIifname\fB\fR ] [ \fB-c\fIconfig file\fB\fR ] [ \fB-D\fIdriver\fB\fR ] [ \fB-P\fIPID_file\fB\fR ] [ \fB-f\fIoutput file\fB\fR ] .SH "OVERVIEW" .PP Wireless networks do not require physical access to the network equipment in the same way as wired networks. This makes it easier for unauthorized users to passively monitor a network and capture all transmitted frames. In addition, unauthorized use of the network is much easier. In many cases, this can happen even without user's explicit knowledge since the wireless LAN adapter may have been configured to automatically join any available network. .PP Link-layer encryption can be used to provide a layer of security for wireless networks. The original wireless LAN standard, IEEE 802.11, included a simple encryption mechanism, WEP. However, that proved to be flawed in many areas and network protected with WEP cannot be consider secure. IEEE 802.1X authentication and frequently changed dynamic WEP keys can be used to improve the network security, but even that has inherited security issues due to the use of WEP for encryption. Wi-Fi Protected Access and IEEE 802.11i amendment to the wireless LAN standard introduce a much improvement mechanism for securing wireless networks. IEEE 802.11i enabled networks that are using CCMP (encryption mechanism based on strong cryptographic algorithm AES) can finally be called secure used for applications which require efficient protection against unauthorized access. .PP \fBwpa_supplicant\fR is an implementation of the WPA Supplicant component, i.e., the part that runs in the client stations. It implements WPA key negotiation with a WPA Authenticator and EAP authentication with Authentication Server. In addition, it controls the roaming and IEEE 802.11 authentication/association of the wireless LAN driver. .PP \fBwpa_supplicant\fR is designed to be a "daemon" program that runs in the background and acts as the backend component controlling the wireless connection. \fBwpa_supplicant\fR supports separate frontend programs and an example text-based frontend, \fBwpa_cli\fR, is included with wpa_supplicant. .PP Before wpa_supplicant can do its work, the network interface must be available. That means that the physical device must be present and enabled, and the driver for the device must be loaded. The daemon will exit immediately if the device is not already available. .PP After \fBwpa_supplicant\fR has configured the network device, higher level configuration such as DHCP may proceed. There are a variety of ways to integrate wpa_supplicant into a machine's networking scripts, a few of which are described in sections below. .PP The following steps are used when associating with an AP using WPA: .TP 0.2i \(bu \fBwpa_supplicant\fR requests the kernel driver to scan neighboring BSSes .TP 0.2i \(bu \fBwpa_supplicant\fR selects a BSS based on its configuration .TP 0.2i \(bu \fBwpa_supplicant\fR requests the kernel driver to associate with the chosen BSS .TP 0.2i \(bu If WPA-EAP: integrated IEEE 802.1X Supplicant completes EAP authentication with the authentication server (proxied by the Authenticator in the AP) .TP 0.2i \(bu If WPA-EAP: master key is received from the IEEE 802.1X Supplicant .TP 0.2i \(bu If WPA-PSK: \fBwpa_supplicant\fR uses PSK as the master session key .TP 0.2i \(bu \fBwpa_supplicant\fR completes WPA 4-Way Handshake and Group Key Handshake with the Authenticator (AP) .TP 0.2i \(bu \fBwpa_supplicant\fR configures encryption keys for unicast and broadcast .TP 0.2i \(bu normal data packets can be transmitted and received .SH "SUPPORTED FEATURES" .PP Supported WPA/IEEE 802.11i features: .TP 0.2i \(bu WPA-PSK ("WPA-Personal") .TP 0.2i \(bu WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise") Following authentication methods are supported with an integrate IEEE 802.1X Supplicant: .RS .TP 0.2i \(bu EAP-TLS .RE .RS .TP 0.2i \(bu EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1) .TP 0.2i \(bu EAP-PEAP/TLS (both PEAPv0 and PEAPv1) .TP 0.2i \(bu EAP-PEAP/GTC (both PEAPv0 and PEAPv1) .TP 0.2i \(bu EAP-PEAP/OTP (both PEAPv0 and PEAPv1) .TP 0.2i \(bu EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1) .TP 0.2i \(bu EAP-TTLS/EAP-MD5-Challenge .TP 0.2i \(bu EAP-TTLS/EAP-GTC .TP 0.2i \(bu EAP-TTLS/EAP-OTP .TP 0.2i \(bu EAP-TTLS/EAP-MSCHAPv2 .TP 0.2i \(bu EAP-TTLS/EAP-TLS .TP 0.2i \(bu EAP-TTLS/MSCHAPv2 .TP 0.2i \(bu EAP-TTLS/MSCHAP .TP 0.2i \(bu EAP-TTLS/PAP .TP 0.2i \(bu EAP-TTLS/CHAP .TP 0.2i \(bu EAP-SIM .TP 0.2i \(bu EAP-AKA .TP 0.2i \(bu EAP-PSK .TP 0.2i \(bu EAP-PAX .TP 0.2i \(bu LEAP (note: requires special support from the driver for IEEE 802.11 authentication) .TP 0.2i \(bu (following methods are supported, but since they do not generate keying material, they cannot be used with WPA or IEEE 802.1X WEP keying) .TP 0.2i \(bu EAP-MD5-Challenge .TP 0.2i \(bu EAP-MSCHAPv2 .TP 0.2i \(bu EAP-GTC .TP 0.2i \(bu EAP-OTP .RE .TP 0.2i \(bu key management for CCMP, TKIP, WEP104, WEP40 .TP 0.2i \(bu RSN/WPA2 (IEEE 802.11i) .RS .TP 0.2i \(bu pre-authentication .TP 0.2i \(bu PMKSA caching .RE .SH "AVAILABLE DRIVERS" .PP A summary of available driver backends is below. Support for each of the driver backends is chosen at wpa_supplicant compile time. For a list of supported driver backends that may be used with the -D option on your system, refer to the help output of wpa_supplicant (\fBwpa_supplicant -h\fR). .TP \fBwext\fR Linux wireless extensions (generic). .TP \fBwired\fR wpa_supplicant wired Ethernet driver .TP \fBroboswitch\fR wpa_supplicant Broadcom switch driver .TP \fBbsd\fR BSD 802.11 support (Atheros, etc.). .TP \fBndis\fR Windows NDIS driver. .SH "COMMAND LINE OPTIONS" .PP Most command line options have global scope. Some are given per interface, and are only valid if at least one \fB-i\fR option is specified, otherwise they're ignored. Option groups for different interfaces must be separated by \fB-N\fR option. .TP \fB-b br_ifname\fR Optional bridge interface name. (Per interface) .TP \fB-B\fR Run daemon in the background. .TP \fB-c filename\fR Path to configuration file. (Per interface) .TP \fB-C ctrl_interface\fR Path to ctrl_interface socket (Per interface. Only used if \fB-c\fR is not). .TP \fB-i ifname\fR Interface to listen on. Multiple instances of this option can be present, one per interface, separated by \fB-N\fR option (see below). .TP \fB-d\fR Increase debugging verbosity (\fB-dd\fR even more). .TP \fB-D driver\fR Driver to use (can be multiple drivers: nl80211,wext). (Per interface, see the available options below.) .TP \fB-e entropy file\fR File for \fBwpa_supplicant\fR to use to maintain its internal entropy store in over restarts. .TP \fB-f output file\fR Log output to specified file instead of stdout. (This is only available if \fBwpa_supplicant\fR was built with the CONFIG_DEBUG_FILE option.) .TP \fB-g global ctrl_interface\fR Path to global ctrl_interface socket. If specified, interface definitions may be omitted. .TP \fB-K\fR Include keys (passwords, etc.) in debug output. .TP \fB-t\fR Include timestamp in debug messages. .TP \fB-h\fR Help. Show a usage message. .TP \fB-L\fR Show license (BSD). .TP \fB-o override driver\fR Override the driver parameter for new interfaces. .TP \fB-O override ctrl_interface\fR Override the ctrl_interface parameter for new interfaces. .TP \fB-p\fR Driver parameters. (Per interface) .TP \fB-P PID_file\fR Path to PID file. .TP \fB-q\fR Decrease debugging verbosity (\fB-qq\fR even less). .TP \fB-s\fR Log output to syslog instead of stdout. (This is only available if \fBwpa_supplicant\fR was built with the CONFIG_DEBUG_SYSLOG option.) .TP \fB-T\fR Log output to Linux tracing in addition to any other destinations. (This is only available if \fBwpa_supplicant\fR was built with the CONFIG_DEBUG_LINUX_TRACING option.) .TP \fB-t\fR Include timestamp in debug messages. .TP \fB-u\fR Enable DBus control interface. If enabled, interface definitions may be omitted. (This is only available if \fBwpa_supplicant\fR was built with the CONFIG_DBUS option.) 0 .TP \fB-v\fR Show version. .TP \fB-W\fR Wait for a control interface monitor before starting. .TP \fB-N\fR Start describing new interface. .SH "EXAMPLES" .PP In most common cases, \fBwpa_supplicant\fR is started with: .sp .RS .nf wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0 .fi .RE .PP This makes the process fork into background. .PP The easiest way to debug problems, and to get debug log for bug reports, is to start \fBwpa_supplicant\fR on foreground with debugging enabled: .sp .RS .nf wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d .fi .RE .PP If the specific driver wrapper is not known beforehand, it is possible to specify multiple comma separated driver wrappers on the command line. \fBwpa_supplicant\fR will use the first driver wrapper that is able to initialize the interface. .sp .RS .nf wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0 .fi .RE .PP \fBwpa_supplicant\fR can control multiple interfaces (radios) either by running one process for each interface separately or by running just one process and list of options at command line. Each interface is separated with -N argument. As an example, following command would start wpa_supplicant for two interfaces: .sp .RS .nf wpa_supplicant \\ -c wpa1.conf -i wlan0 -D nl80211 -N \\ -c wpa2.conf -i ath0 -D wext .fi .RE .SH "OS REQUIREMENTS" .PP Current hardware/software requirements: .TP 0.2i \(bu Linux kernel 2.4.x or 2.6.x with Linux Wireless Extensions v15 or newer .TP 0.2i \(bu FreeBSD 6-CURRENT .TP 0.2i \(bu Microsoft Windows with WinPcap (at least WinXP, may work with other versions) .SH "SUPPORTED DRIVERS" .TP \fBLinux wireless extensions\fR In theory, any driver that supports Linux wireless extensions can be used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in configuration file. .TP \fBWired Ethernet drivers\fR Use ap_scan=0. .TP \fBBSD net80211 layer (e.g., Atheros driver)\fR At the moment, this is for FreeBSD 6-CURRENT branch. .TP \fBWindows NDIS\fR The current Windows port requires WinPcap (http://winpcap.polito.it/). See README-Windows.txt for more information. .PP wpa_supplicant was designed to be portable for different drivers and operating systems. Hopefully, support for more wlan cards and OSes will be added in the future. See developer.txt for more information about the design of wpa_supplicant and porting to other drivers. One main goal is to add full WPA/WPA2 support to Linux wireless extensions to allow new drivers to be supported without having to implement new driver-specific interface code in wpa_supplicant. .SH "ARCHITECTURE" .PP The \fBwpa_supplicant\fR system consists of the following components: .TP \fB\fIwpa_supplicant.conf\fB \fR the configuration file describing all networks that the user wants the computer to connect to. .TP \fBwpa_supplicant\fR the program that directly interacts with the network interface. .TP \fBwpa_cli\fR the client program that provides a high-level interface to the functionality of the daemon. .TP \fBwpa_passphrase\fR a utility needed to construct \fIwpa_supplicant.conf\fR files that include encrypted passwords. .SH "QUICK START" .PP First, make a configuration file, e.g. \fI/etc/wpa_supplicant.conf\fR, that describes the networks you are interested in. See \fBwpa_supplicant.conf\fR(5) for details. .PP Once the configuration is ready, you can test whether the configuration works by running \fBwpa_supplicant\fR with following command to start it on foreground with debugging enabled: .sp .RS .nf wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d .fi .RE .PP Assuming everything goes fine, you can start using following command to start \fBwpa_supplicant\fR on background without debugging: .sp .RS .nf wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B .fi .RE .PP Please note that if you included more than one driver interface in the build time configuration (.config), you may need to specify which interface to use by including -D option on the command line. .SH "INTERFACE TO PCMCIA-CS/CARDMRG" .PP For example, following small changes to pcmcia-cs scripts can be used to enable WPA support: .PP Add MODE="Managed" and WPA="y" to the network scheme in \fI/etc/pcmcia/wireless.opts\fR\&. .PP Add the following block to the end of \fBstart\fR action handler in \fI/etc/pcmcia/wireless\fR: .sp .RS .nf if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then /usr/local/bin/wpa_supplicant -B -c/etc/wpa_supplicant.conf -i$DEVICE fi .fi .RE .PP Add the following block to the end of \fBstop\fR action handler (may need to be separated from other actions) in \fI/etc/pcmcia/wireless\fR: .sp .RS .nf if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then killall wpa_supplicant fi .fi .RE .PP This will make \fBcardmgr\fR start \fBwpa_supplicant\fR when the card is plugged in. .SH "SEE ALSO" .PP \fBwpa_background\fR(8) \fBwpa_supplicant.conf\fR(5) \fBwpa_cli\fR(8) \fBwpa_passphrase\fR(8) .SH "LEGAL" .PP wpa_supplicant is copyright (c) 2003-2014, Jouni Malinen and contributors. All Rights Reserved. .PP This program is licensed under the BSD license (the one with advertisement clause removed). wpa_supplicant-2.2/wpa_supplicant/doc/docbook/wpa_gui.sgml0000664000175000017500000000453512343617166021763 0ustar jmjm wpa_gui 8 wpa_gui WPA Graphical User Interface wpa_gui -p path to ctrl sockets -i ifname -t Overview wpa_gui is a QT graphical frontend program for interacting with wpa_supplicant. It is used to query current status, change configuration and request interactive user input. wpa_gui supports (almost) all of the interactive status and configuration features of the command line client, wpa_cli. Refer to the wpa_cli manpage for a comprehensive list of the interactive mode features. Command Arguments -p path Change the path where control sockets should be found. -i ifname Specify the interface that is being configured. By default, choose the first interface found with a control socket in the socket path. -t Start program in the system tray only (if the window manager supports it). By default the main status window is shown. See Also wpa_cli 8 wpa_supplicant 8 Legal wpa_supplicant is copyright (c) 2003-2014, Jouni Malinen j@w1.fi and contributors. All Rights Reserved. This program is licensed under the BSD license (the one with advertisement clause removed). wpa_supplicant-2.2/wpa_supplicant/doc/docbook/manpage.links0000664000175000017500000000000012343703240022062 0ustar jmjmwpa_supplicant-2.2/wpa_supplicant/doc/docbook/wpa_supplicant.sgml0000664000175000017500000005332312343617166023360 0ustar jmjm wpa_supplicant 8 wpa_supplicant Wi-Fi Protected Access client and IEEE 802.1X supplicant wpa_supplicant -BddfhKLqqsTtuvW -iifname -cconfig file -Ddriver -PPID_file -foutput file Overview Wireless networks do not require physical access to the network equipment in the same way as wired networks. This makes it easier for unauthorized users to passively monitor a network and capture all transmitted frames. In addition, unauthorized use of the network is much easier. In many cases, this can happen even without user's explicit knowledge since the wireless LAN adapter may have been configured to automatically join any available network. Link-layer encryption can be used to provide a layer of security for wireless networks. The original wireless LAN standard, IEEE 802.11, included a simple encryption mechanism, WEP. However, that proved to be flawed in many areas and network protected with WEP cannot be consider secure. IEEE 802.1X authentication and frequently changed dynamic WEP keys can be used to improve the network security, but even that has inherited security issues due to the use of WEP for encryption. Wi-Fi Protected Access and IEEE 802.11i amendment to the wireless LAN standard introduce a much improvement mechanism for securing wireless networks. IEEE 802.11i enabled networks that are using CCMP (encryption mechanism based on strong cryptographic algorithm AES) can finally be called secure used for applications which require efficient protection against unauthorized access. wpa_supplicant is an implementation of the WPA Supplicant component, i.e., the part that runs in the client stations. It implements WPA key negotiation with a WPA Authenticator and EAP authentication with Authentication Server. In addition, it controls the roaming and IEEE 802.11 authentication/association of the wireless LAN driver. wpa_supplicant is designed to be a "daemon" program that runs in the background and acts as the backend component controlling the wireless connection. wpa_supplicant supports separate frontend programs and an example text-based frontend, wpa_cli, is included with wpa_supplicant. Before wpa_supplicant can do its work, the network interface must be available. That means that the physical device must be present and enabled, and the driver for the device must be loaded. The daemon will exit immediately if the device is not already available. After wpa_supplicant has configured the network device, higher level configuration such as DHCP may proceed. There are a variety of ways to integrate wpa_supplicant into a machine's networking scripts, a few of which are described in sections below. The following steps are used when associating with an AP using WPA: wpa_supplicant requests the kernel driver to scan neighboring BSSes wpa_supplicant selects a BSS based on its configuration wpa_supplicant requests the kernel driver to associate with the chosen BSS If WPA-EAP: integrated IEEE 802.1X Supplicant completes EAP authentication with the authentication server (proxied by the Authenticator in the AP) If WPA-EAP: master key is received from the IEEE 802.1X Supplicant If WPA-PSK: wpa_supplicant uses PSK as the master session key wpa_supplicant completes WPA 4-Way Handshake and Group Key Handshake with the Authenticator (AP) wpa_supplicant configures encryption keys for unicast and broadcast normal data packets can be transmitted and received Supported Features Supported WPA/IEEE 802.11i features: WPA-PSK ("WPA-Personal") WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise") Following authentication methods are supported with an integrate IEEE 802.1X Supplicant: EAP-TLS EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1) EAP-PEAP/TLS (both PEAPv0 and PEAPv1) EAP-PEAP/GTC (both PEAPv0 and PEAPv1) EAP-PEAP/OTP (both PEAPv0 and PEAPv1) EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1) EAP-TTLS/EAP-MD5-Challenge EAP-TTLS/EAP-GTC EAP-TTLS/EAP-OTP EAP-TTLS/EAP-MSCHAPv2 EAP-TTLS/EAP-TLS EAP-TTLS/MSCHAPv2 EAP-TTLS/MSCHAP EAP-TTLS/PAP EAP-TTLS/CHAP EAP-SIM EAP-AKA EAP-PSK EAP-PAX LEAP (note: requires special support from the driver for IEEE 802.11 authentication) (following methods are supported, but since they do not generate keying material, they cannot be used with WPA or IEEE 802.1X WEP keying) EAP-MD5-Challenge EAP-MSCHAPv2 EAP-GTC EAP-OTP key management for CCMP, TKIP, WEP104, WEP40 RSN/WPA2 (IEEE 802.11i) pre-authentication PMKSA caching Available Drivers A summary of available driver backends is below. Support for each of the driver backends is chosen at wpa_supplicant compile time. For a list of supported driver backends that may be used with the -D option on your system, refer to the help output of wpa_supplicant (wpa_supplicant -h). wext Linux wireless extensions (generic). wired wpa_supplicant wired Ethernet driver roboswitch wpa_supplicant Broadcom switch driver bsd BSD 802.11 support (Atheros, etc.). ndis Windows NDIS driver. Command Line Options Most command line options have global scope. Some are given per interface, and are only valid if at least one option is specified, otherwise they're ignored. Option groups for different interfaces must be separated by option. -b br_ifname Optional bridge interface name. (Per interface) -B Run daemon in the background. -c filename Path to configuration file. (Per interface) -C ctrl_interface Path to ctrl_interface socket (Per interface. Only used if is not). -i ifname Interface to listen on. Multiple instances of this option can be present, one per interface, separated by option (see below). -d Increase debugging verbosity ( even more). -D driver Driver to use (can be multiple drivers: nl80211,wext). (Per interface, see the available options below.) -e entropy file File for wpa_supplicant to use to maintain its internal entropy store in over restarts. -f output file Log output to specified file instead of stdout. (This is only available if wpa_supplicant was built with the CONFIG_DEBUG_FILE option.) -g global ctrl_interface Path to global ctrl_interface socket. If specified, interface definitions may be omitted. -K Include keys (passwords, etc.) in debug output. -t Include timestamp in debug messages. -h Help. Show a usage message. -L Show license (BSD). -o override driver Override the driver parameter for new interfaces. -O override ctrl_interface Override the ctrl_interface parameter for new interfaces. -p Driver parameters. (Per interface) -P PID_file Path to PID file. -q Decrease debugging verbosity ( even less). -s Log output to syslog instead of stdout. (This is only available if wpa_supplicant was built with the CONFIG_DEBUG_SYSLOG option.) -T Log output to Linux tracing in addition to any other destinations. (This is only available if wpa_supplicant was built with the CONFIG_DEBUG_LINUX_TRACING option.) -t Include timestamp in debug messages. -u Enable DBus control interface. If enabled, interface definitions may be omitted. (This is only available if wpa_supplicant was built with the CONFIG_DBUS option.)0 -v Show version. -W Wait for a control interface monitor before starting. -N Start describing new interface. Examples In most common cases, wpa_supplicant is started with:
wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0
This makes the process fork into background. The easiest way to debug problems, and to get debug log for bug reports, is to start wpa_supplicant on foreground with debugging enabled:
wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
If the specific driver wrapper is not known beforehand, it is possible to specify multiple comma separated driver wrappers on the command line. wpa_supplicant will use the first driver wrapper that is able to initialize the interface.
wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0
wpa_supplicant can control multiple interfaces (radios) either by running one process for each interface separately or by running just one process and list of options at command line. Each interface is separated with -N argument. As an example, following command would start wpa_supplicant for two interfaces:
wpa_supplicant \ -c wpa1.conf -i wlan0 -D nl80211 -N \ -c wpa2.conf -i ath0 -D wext
OS Requirements Current hardware/software requirements: Linux kernel 2.4.x or 2.6.x with Linux Wireless Extensions v15 or newer FreeBSD 6-CURRENT Microsoft Windows with WinPcap (at least WinXP, may work with other versions) Supported Drivers Linux wireless extensions In theory, any driver that supports Linux wireless extensions can be used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in configuration file. Wired Ethernet drivers Use ap_scan=0. BSD net80211 layer (e.g., Atheros driver) At the moment, this is for FreeBSD 6-CURRENT branch. Windows NDIS The current Windows port requires WinPcap (http://winpcap.polito.it/). See README-Windows.txt for more information. wpa_supplicant was designed to be portable for different drivers and operating systems. Hopefully, support for more wlan cards and OSes will be added in the future. See developer.txt for more information about the design of wpa_supplicant and porting to other drivers. One main goal is to add full WPA/WPA2 support to Linux wireless extensions to allow new drivers to be supported without having to implement new driver-specific interface code in wpa_supplicant. Architecture The wpa_supplicant system consists of the following components: wpa_supplicant.conf the configuration file describing all networks that the user wants the computer to connect to. wpa_supplicant the program that directly interacts with the network interface. wpa_cli the client program that provides a high-level interface to the functionality of the daemon. wpa_passphrase a utility needed to construct wpa_supplicant.conf files that include encrypted passwords. Quick Start First, make a configuration file, e.g. /etc/wpa_supplicant.conf, that describes the networks you are interested in. See wpa_supplicant.conf 5 for details. Once the configuration is ready, you can test whether the configuration works by running wpa_supplicant with following command to start it on foreground with debugging enabled:
wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d
Assuming everything goes fine, you can start using following command to start wpa_supplicant on background without debugging:
wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B
Please note that if you included more than one driver interface in the build time configuration (.config), you may need to specify which interface to use by including -D<driver name> option on the command line.
Interface to pcmcia-cs/cardmrg For example, following small changes to pcmcia-cs scripts can be used to enable WPA support: Add MODE="Managed" and WPA="y" to the network scheme in /etc/pcmcia/wireless.opts. Add the following block to the end of start action handler in /etc/pcmcia/wireless:
if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then /usr/local/bin/wpa_supplicant -B -c/etc/wpa_supplicant.conf -i$DEVICE fi
Add the following block to the end of stop action handler (may need to be separated from other actions) in /etc/pcmcia/wireless:
if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then killall wpa_supplicant fi
This will make cardmgr start wpa_supplicant when the card is plugged in.
See Also wpa_background 8 wpa_supplicant.conf 5 wpa_cli 8 wpa_passphrase 8 Legal wpa_supplicant is copyright (c) 2003-2014, Jouni Malinen j@w1.fi and contributors. All Rights Reserved. This program is licensed under the BSD license (the one with advertisement clause removed).
wpa_supplicant-2.2/wpa_supplicant/doc/docbook/wpa_priv.80000664000175000017500000000737212343703240021353 0ustar jmjm.\" This manpage has been automatically generated by docbook2man .\" from a DocBook document. This tool can be found at: .\" .\" Please send any bug reports, improvements, comments, patches, .\" etc. to Steve Cheng . .TH "WPA_PRIV" "8" "04 June 2014" "" "" .SH NAME wpa_priv \- wpa_supplicant privilege separation helper .SH SYNOPSIS \fBwpa_priv\fR [ \fB-c \fIctrl path\fB\fR ] [ \fB-Bdd\fR ] [ \fB-P \fIpid file\fB\fR ] [ \fBdriver:ifname \fI[driver:ifname ...]\fB\fR ] .SH "OVERVIEW" .PP \fBwpa_priv\fR is a privilege separation helper that minimizes the size of \fBwpa_supplicant\fR code that needs to be run with root privileges. .PP If enabled, privileged operations are done in the wpa_priv process while leaving rest of the code (e.g., EAP authentication and WPA handshakes) to operate in an unprivileged process (wpa_supplicant) that can be run as non-root user. Privilege separation restricts the effects of potential software errors by containing the majority of the code in an unprivileged process to avoid the possibility of a full system compromise. .PP \fBwpa_priv\fR needs to be run with network admin privileges (usually, root user). It opens a UNIX domain socket for each interface that is included on the command line; any other interface will be off limits for \fBwpa_supplicant\fR in this kind of configuration. After this, \fBwpa_supplicant\fR can be run as a non-root user (e.g., all standard users on a laptop or as a special non-privileged user account created just for this purpose to limit access to user files even further). .SH "EXAMPLE CONFIGURATION" .PP The following steps are an example of how to configure \fBwpa_priv\fR to allow users in the \fBwpapriv\fR group to communicate with \fBwpa_supplicant\fR with privilege separation: .PP Create user group (e.g., wpapriv) and assign users that should be able to use wpa_supplicant into that group. .PP Create /var/run/wpa_priv directory for UNIX domain sockets and control user access by setting it accessible only for the wpapriv group: .sp .RS .nf mkdir /var/run/wpa_priv chown root:wpapriv /var/run/wpa_priv chmod 0750 /var/run/wpa_priv .fi .RE .PP Start \fBwpa_priv\fR as root (e.g., from system startup scripts) with the enabled interfaces configured on the command line: .sp .RS .nf wpa_priv -B -c /var/run/wpa_priv -P /var/run/wpa_priv.pid wext:wlan0 .fi .RE .PP Run \fBwpa_supplicant\fR as non-root with a user that is in the wpapriv group: .sp .RS .nf wpa_supplicant -i ath0 -c wpa_supplicant.conf .fi .RE .SH "COMMAND ARGUMENTS" .TP \fB-c ctrl path\fR Specify the path to wpa_priv control directory (Default: /var/run/wpa_priv/). .TP \fB-B\fR Run as a daemon in the background. .TP \fB-P file\fR Set the location of the PID file. .TP \fBdriver:ifname [driver:ifname ...]\fR The string dictates which of the supported \fBwpa_supplicant\fR driver backends is to be used. To get a list of supported driver types see wpa_supplicant help (e.g, wpa_supplicant -h). The driver backend supported by most good drivers is \fBwext\fR\&. The string specifies which network interface is to be managed by \fBwpa_supplicant\fR (e.g., wlan0 or ath0). \fBwpa_priv\fR does not use the network interface before \fBwpa_supplicant\fR is started, so it is fine to include network interfaces that are not available at the time wpa_priv is started. wpa_priv can control multiple interfaces with one process, but it is also possible to run multiple \fBwpa_priv\fR processes at the same time, if desired. .SH "SEE ALSO" .PP \fBwpa_supplicant\fR(8) .SH "LEGAL" .PP wpa_supplicant is copyright (c) 2003-2014, Jouni Malinen and contributors. All Rights Reserved. .PP This program is licensed under the BSD license (the one with advertisement clause removed). wpa_supplicant-2.2/wpa_supplicant/doc/docbook/Makefile0000664000175000017500000000114712343617166021100 0ustar jmjmall: man html pdf FILES += wpa_background FILES += wpa_cli FILES += wpa_gui FILES += wpa_passphrase FILES += wpa_priv FILES += wpa_supplicant.conf FILES += wpa_supplicant FILES += eapol_test man: for i in $(FILES); do docbook2man $$i.sgml; done html: for i in $(FILES); do docbook2html $$i.sgml && \ mv index.html $$i.html; done pdf: for i in $(FILES); do docbook2pdf $$i.sgml; done clean: rm -f wpa_background.8 wpa_cli.8 wpa_gui.8 wpa_passphrase.8 wpa_priv.8 wpa_supplicant.8 eapol_test.8 rm -f wpa_supplicant.conf.5 rm -f manpage.links manpage.refs rm -f $(FILES:%=%.pdf) rm -f $(FILES:%=%.html) wpa_supplicant-2.2/wpa_supplicant/doc/docbook/wpa_supplicant.conf.50000664000175000017500000001313712343703240023472 0ustar jmjm.\" This manpage has been automatically generated by docbook2man .\" from a DocBook document. This tool can be found at: .\" .\" Please send any bug reports, improvements, comments, patches, .\" etc. to Steve Cheng . .TH "WPA_SUPPLICANT.CONF" "5" "04 June 2014" "" "" .SH NAME wpa_supplicant.conf \- configuration file for wpa_supplicant .SH "OVERVIEW" .PP \fBwpa_supplicant\fR is configured using a text file that lists all accepted networks and security policies, including pre-shared keys. See the example configuration file, probably in \fB/usr/share/doc/wpa_supplicant/\fR, for detailed information about the configuration format and supported fields. .PP All file paths in this configuration file should use full (absolute, not relative to working directory) path in order to allow working directory to be changed. This can happen if wpa_supplicant is run in the background. .PP Changes to configuration file can be reloaded be sending SIGHUP signal to \fBwpa_supplicant\fR ('killall -HUP wpa_supplicant'). Similarly, reloading can be triggered with the \fBwpa_cli reconfigure\fR command. .PP Configuration file can include one or more network blocks, e.g., one for each used SSID. wpa_supplicant will automatically select the best network based on the order of network blocks in the configuration file, network security level (WPA/WPA2 is preferred), and signal strength. .SH "QUICK EXAMPLES" .TP 3 1. WPA-Personal (PSK) as home network and WPA-Enterprise with EAP-TLS as work network. .sp .RS .nf # allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel # # home network; allow all valid ciphers network={ ssid="home" scan_ssid=1 key_mgmt=WPA-PSK psk="very secret passphrase" } # # work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers network={ ssid="work" scan_ssid=1 key_mgmt=WPA-EAP pairwise=CCMP TKIP group=CCMP TKIP eap=TLS identity="user@example.com" ca_cert="/etc/cert/ca.pem" client_cert="/etc/cert/user.pem" private_key="/etc/cert/user.prv" private_key_passwd="password" } .fi .RE .TP 3 2. WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that use old peaplabel (e.g., Funk Odyssey and SBR, Meetinghouse Aegis, Interlink RAD-Series) .sp .RS .nf ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel network={ ssid="example" scan_ssid=1 key_mgmt=WPA-EAP eap=PEAP identity="user@example.com" password="foobar" ca_cert="/etc/cert/ca.pem" phase1="peaplabel=0" phase2="auth=MSCHAPV2" } .fi .RE .TP 3 3. EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the unencrypted use. Real identity is sent only within an encrypted TLS tunnel. .sp .RS .nf ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel network={ ssid="example" scan_ssid=1 key_mgmt=WPA-EAP eap=TTLS identity="user@example.com" anonymous_identity="anonymous@example.com" password="foobar" ca_cert="/etc/cert/ca.pem" phase2="auth=MD5" } .fi .RE .TP 3 4. IEEE 802.1X (i.e., no WPA) with dynamic WEP keys (require both unicast and broadcast); use EAP-TLS for authentication .sp .RS .nf ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel network={ ssid="1x-test" scan_ssid=1 key_mgmt=IEEE8021X eap=TLS identity="user@example.com" ca_cert="/etc/cert/ca.pem" client_cert="/etc/cert/user.pem" private_key="/etc/cert/user.prv" private_key_passwd="password" eapol_flags=3 } .fi .RE .TP 3 5. Catch all example that allows more or less all configuration modes. The configuration options are used based on what security policy is used in the selected SSID. This is mostly for testing and is not recommended for normal use. .sp .RS .nf ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel network={ ssid="example" scan_ssid=1 key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE pairwise=CCMP TKIP group=CCMP TKIP WEP104 WEP40 psk="very secret passphrase" eap=TTLS PEAP TLS identity="user@example.com" password="foobar" ca_cert="/etc/cert/ca.pem" client_cert="/etc/cert/user.pem" private_key="/etc/cert/user.prv" private_key_passwd="password" phase1="peaplabel=0" ca_cert2="/etc/cert/ca2.pem" client_cert2="/etc/cer/user.pem" private_key2="/etc/cer/user.prv" private_key2_passwd="password" } .fi .RE .TP 3 6. Authentication for wired Ethernet. This can be used with \fBwired\fR or \fBroboswitch\fR interface (-Dwired or -Droboswitch on command line). .sp .RS .nf ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel ap_scan=0 network={ key_mgmt=IEEE8021X eap=MD5 identity="user" password="password" eapol_flags=0 } .fi .RE .SH "CERTIFICATES" .PP Some EAP authentication methods require use of certificates. EAP-TLS uses both server side and client certificates whereas EAP-PEAP and EAP-TTLS only require the server side certificate. When client certificate is used, a matching private key file has to also be included in configuration. If the private key uses a passphrase, this has to be configured in wpa_supplicant.conf ("private_key_passwd"). .PP wpa_supplicant supports X.509 certificates in PEM and DER formats. User certificate and private key can be included in the same file. .PP If the user certificate and private key is received in PKCS#12/PFX format, they need to be converted to suitable PEM/DER format for wpa_supplicant. This can be done, e.g., with following commands: .sp .RS .nf # convert client certificate and private key to PEM format openssl pkcs12 -in example.pfx -out user.pem -clcerts # convert CA certificate (if included in PFX file) to PEM format openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys .fi .RE .SH "SEE ALSO" .PP \fBwpa_supplicant\fR(8) \fBopenssl\fR(1) wpa_supplicant-2.2/wpa_supplicant/doc/docbook/wpa_background.sgml0000664000175000017500000001061012343617166023305 0ustar jmjm wpa_background 8 wpa_background Background information on Wi-Fi Protected Access and IEEE 802.11i WPA The original security mechanism of IEEE 802.11 standard was not designed to be strong and has proven to be insufficient for most networks that require some kind of security. Task group I (Security) of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked to address the flaws of the base standard and has in practice completed its work in May 2004. The IEEE 802.11i amendment to the IEEE 802.11 standard was approved in June 2004 and published in July 2004. Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the IEEE 802.11i work (draft 3.0) to define a subset of the security enhancements that can be implemented with existing wlan hardware. This is called Wi-Fi Protected Access<TM> (WPA). This has now become a mandatory component of interoperability testing and certification done by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web site (http://www.wi-fi.org/OpenSection/protected_access.asp). IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm for protecting wireless networks. WEP uses RC4 with 40-bit keys, 24-bit initialization vector (IV), and CRC32 to protect against packet forgery. All these choices have proven to be insufficient: key space is too small against current attacks, RC4 key scheduling is insufficient (beginning of the pseudorandom stream should be skipped), IV space is too small and IV reuse makes attacks easier, there is no replay protection, and non-keyed authentication does not protect against bit flipping packet data. WPA is an intermediate solution for the security issues. It uses Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a compromise on strong security and possibility to use existing hardware. It still uses RC4 for the encryption like WEP, but with per-packet RC4 keys. In addition, it implements replay protection, keyed packet authentication mechanism (Michael MIC). Keys can be managed using two different mechanisms. WPA can either use an external authentication server (e.g., RADIUS) and EAP just like IEEE 802.1X is using or pre-shared keys without need for additional servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal", respectively. Both mechanisms will generate a master session key for the Authenticator (AP) and Supplicant (client station). WPA implements a new key handshake (4-Way Handshake and Group Key Handshake) for generating and exchanging data encryption keys between the Authenticator and Supplicant. This handshake is also used to verify that both Authenticator and Supplicant know the master session key. These handshakes are identical regardless of the selected key management mechanism (only the method for generating master session key changes). IEEE 802.11i / WPA2 The design for parts of IEEE 802.11i that were not included in WPA has finished (May 2004) and this amendment to IEEE 802.11 was approved in June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new version of WPA called WPA2. This includes, e.g., support for more robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC) to replace TKIP and optimizations for handoff (reduced number of messages in initial key handshake, pre-authentication, and PMKSA caching). See Also wpa_supplicant 8 Legal wpa_supplicant is copyright (c) 2003-2014, Jouni Malinen j@w1.fi and contributors. All Rights Reserved. This program is licensed under the BSD license (the one with advertisement clause removed). wpa_supplicant-2.2/wpa_supplicant/doc/docbook/wpa_cli.80000664000175000017500000001476412343703237021153 0ustar jmjm.\" This manpage has been automatically generated by docbook2man .\" from a DocBook document. This tool can be found at: .\" .\" Please send any bug reports, improvements, comments, patches, .\" etc. to Steve Cheng . .TH "WPA_CLI" "8" "04 June 2014" "" "" .SH NAME wpa_cli \- WPA command line client .SH SYNOPSIS \fBwpa_cli\fR [ \fB-p \fIpath to ctrl sockets\fB\fR ] [ \fB-g \fIpath to global ctrl_interface socket\fB\fR ] [ \fB-i \fIifname\fB\fR ] [ \fB-hvB\fR ] [ \fB-a \fIaction file\fB\fR ] [ \fB-P \fIpid file\fB\fR ] [ \fB-G \fIping interval\fB\fR ] [ \fB\fIcommand ...\fB\fR ] .SH "OVERVIEW" .PP wpa_cli is a text-based frontend program for interacting with wpa_supplicant. It is used to query current status, change configuration, trigger events, and request interactive user input. .PP wpa_cli can show the current authentication status, selected security mode, dot11 and dot1x MIBs, etc. In addition, it can configure some variables like EAPOL state machine parameters and trigger events like reassociation and IEEE 802.1X logoff/logon. wpa_cli provides a user interface to request authentication information, like username and password, if these are not included in the configuration. This can be used to implement, e.g., one-time-passwords or generic token card authentication where the authentication is based on a challenge-response that uses an external device for generating the response. .PP The control interface of wpa_supplicant can be configured to allow non-root user access (ctrl_interface GROUP= parameter in the configuration file). This makes it possible to run wpa_cli with a normal user account. .PP wpa_cli supports two modes: interactive and command line. Both modes share the same command set and the main difference is in interactive mode providing access to unsolicited messages (event messages, username/password requests). .PP Interactive mode is started when wpa_cli is executed without including the command as a command line parameter. Commands are then entered on the wpa_cli prompt. In command line mode, the same commands are entered as command line arguments for wpa_cli. .SH "INTERACTIVE AUTHENTICATION PARAMETERS REQUEST" .PP When wpa_supplicant need authentication parameters, like username and password, which are not present in the configuration file, it sends a request message to all attached frontend programs, e.g., wpa_cli in interactive mode. wpa_cli shows these requests with "CTRL-REQ--:" prefix. is IDENTITY, PASSWORD, or OTP (one-time-password). is a unique identifier for the current network. is description of the request. In case of OTP request, it includes the challenge from the authentication server. .PP The reply to these requests can be given with \fBidentity\fR, \fBpassword\fR, and \fBotp\fR commands. needs to be copied from the matching request. \fBpassword\fR and \fBotp\fR commands can be used regardless of whether the request was for PASSWORD or OTP. The main difference between these two commands is that values given with \fBpassword\fR are remembered as long as wpa_supplicant is running whereas values given with \fBotp\fR are used only once and then forgotten, i.e., wpa_supplicant will ask frontend for a new value for every use. This can be used to implement one-time-password lists and generic token card -based authentication. .PP Example request for password and a matching reply: .sp .RS .nf CTRL-REQ-PASSWORD-1:Password needed for SSID foobar > password 1 mysecretpassword .fi .RE .PP Example request for generic token card challenge-response: .sp .RS .nf CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar > otp 2 9876 .fi .RE .SH "COMMAND ARGUMENTS" .TP \fB-p path\fR Change the path where control sockets should be found. .TP \fB-g control socket path\fR Connect to the global control socket at the indicated path rather than an interface-specific control socket. .TP \fB-i ifname\fR Specify the interface that is being configured. By default, choose the first interface found with a control socket in the socket path. .TP \fB-h\fR Help. Show a usage message. .TP \fB-v\fR Show version information. .TP \fB-B\fR Run as a daemon in the background. .TP \fB-a file\fR Run in daemon mode executing the action file based on events from wpa_supplicant. The specified file will be executed with the first argument set to interface name and second to "CONNECTED" or "DISCONNECTED" depending on the event. This can be used to execute networking tools required to configure the interface. Additionally, three environmental variables are available to the file: WPA_CTRL_DIR, WPA_ID, and WPA_ID_STR. WPA_CTRL_DIR contains the absolute path to the ctrl_interface socket. WPA_ID contains the unique network_id identifier assigned to the active network, and WPA_ID_STR contains the content of the id_str option. .TP \fB-P file\fR Set the location of the PID file. .TP \fB-G ping interval\fR Set the interval (in seconds) at which wpa_cli pings the supplicant. .TP \fBcommand\fR Run a command. The available commands are listed in the next section. .SH "COMMANDS" .PP The following commands are available: .TP \fBstatus\fR get current WPA/EAPOL/EAP status .TP \fBmib\fR get MIB variables (dot1x, dot11) .TP \fBhelp\fR show this usage help .TP \fBinterface [ifname]\fR show interfaces/select interface .TP \fBlevel \fR change debug level .TP \fBlicense\fR show full wpa_cli license .TP \fBlogoff\fR IEEE 802.1X EAPOL state machine logoff .TP \fBlogon\fR IEEE 802.1X EAPOL state machine logon .TP \fBset\fR set variables (shows list of variables when run without arguments) .TP \fBpmksa\fR show PMKSA cache .TP \fBreassociate\fR force reassociation .TP \fBreconfigure\fR force wpa_supplicant to re-read its configuration file .TP \fBpreauthenticate \fR force preauthentication .TP \fBidentity \fR configure identity for an SSID .TP \fBpassword \fR configure password for an SSID .TP \fBpin \fR configure pin for an SSID .TP \fBotp \fR configure one-time-password for an SSID .TP \fBbssid \fR set preferred BSSID for an SSID .TP \fBlist_networks\fR list configured networks .TP \fBterminate\fR terminate \fBwpa_supplicant\fR .TP \fBquit\fR exit wpa_cli .SH "SEE ALSO" .PP \fBwpa_supplicant\fR(8) .SH "LEGAL" .PP wpa_supplicant is copyright (c) 2003-2014, Jouni Malinen and contributors. All Rights Reserved. .PP This program is licensed under the BSD license (the one with advertisement clause removed). wpa_supplicant-2.2/wpa_supplicant/doc/docbook/.gitignore0000664000175000017500000000006012343617166021421 0ustar jmjmmanpage.links manpage.refs *.8 *.5 *.html *.pdf wpa_supplicant-2.2/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml0000664000175000017500000001547112343617166024306 0ustar jmjm wpa_supplicant.conf 5 wpa_supplicant.conf configuration file for wpa_supplicant Overview wpa_supplicant is configured using a text file that lists all accepted networks and security policies, including pre-shared keys. See the example configuration file, probably in /usr/share/doc/wpa_supplicant/, for detailed information about the configuration format and supported fields. All file paths in this configuration file should use full (absolute, not relative to working directory) path in order to allow working directory to be changed. This can happen if wpa_supplicant is run in the background. Changes to configuration file can be reloaded be sending SIGHUP signal to wpa_supplicant ('killall -HUP wpa_supplicant'). Similarly, reloading can be triggered with the wpa_cli reconfigure command. Configuration file can include one or more network blocks, e.g., one for each used SSID. wpa_supplicant will automatically select the best network based on the order of network blocks in the configuration file, network security level (WPA/WPA2 is preferred), and signal strength. Quick Examples WPA-Personal (PSK) as home network and WPA-Enterprise with EAP-TLS as work network.
# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel # # home network; allow all valid ciphers network={ ssid="home" scan_ssid=1 key_mgmt=WPA-PSK psk="very secret passphrase" } # # work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers network={ ssid="work" scan_ssid=1 key_mgmt=WPA-EAP pairwise=CCMP TKIP group=CCMP TKIP eap=TLS identity="user@example.com" ca_cert="/etc/cert/ca.pem" client_cert="/etc/cert/user.pem" private_key="/etc/cert/user.prv" private_key_passwd="password" }
WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that use old peaplabel (e.g., Funk Odyssey and SBR, Meetinghouse Aegis, Interlink RAD-Series)
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel network={ ssid="example" scan_ssid=1 key_mgmt=WPA-EAP eap=PEAP identity="user@example.com" password="foobar" ca_cert="/etc/cert/ca.pem" phase1="peaplabel=0" phase2="auth=MSCHAPV2" }
EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the unencrypted use. Real identity is sent only within an encrypted TLS tunnel.
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel network={ ssid="example" scan_ssid=1 key_mgmt=WPA-EAP eap=TTLS identity="user@example.com" anonymous_identity="anonymous@example.com" password="foobar" ca_cert="/etc/cert/ca.pem" phase2="auth=MD5" }
IEEE 802.1X (i.e., no WPA) with dynamic WEP keys (require both unicast and broadcast); use EAP-TLS for authentication
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel network={ ssid="1x-test" scan_ssid=1 key_mgmt=IEEE8021X eap=TLS identity="user@example.com" ca_cert="/etc/cert/ca.pem" client_cert="/etc/cert/user.pem" private_key="/etc/cert/user.prv" private_key_passwd="password" eapol_flags=3 }
Catch all example that allows more or less all configuration modes. The configuration options are used based on what security policy is used in the selected SSID. This is mostly for testing and is not recommended for normal use.
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel network={ ssid="example" scan_ssid=1 key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE pairwise=CCMP TKIP group=CCMP TKIP WEP104 WEP40 psk="very secret passphrase" eap=TTLS PEAP TLS identity="user@example.com" password="foobar" ca_cert="/etc/cert/ca.pem" client_cert="/etc/cert/user.pem" private_key="/etc/cert/user.prv" private_key_passwd="password" phase1="peaplabel=0" ca_cert2="/etc/cert/ca2.pem" client_cert2="/etc/cer/user.pem" private_key2="/etc/cer/user.prv" private_key2_passwd="password" }
Authentication for wired Ethernet. This can be used with wired or roboswitch interface (-Dwired or -Droboswitch on command line).
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel ap_scan=0 network={ key_mgmt=IEEE8021X eap=MD5 identity="user" password="password" eapol_flags=0 }
Certificates Some EAP authentication methods require use of certificates. EAP-TLS uses both server side and client certificates whereas EAP-PEAP and EAP-TTLS only require the server side certificate. When client certificate is used, a matching private key file has to also be included in configuration. If the private key uses a passphrase, this has to be configured in wpa_supplicant.conf ("private_key_passwd"). wpa_supplicant supports X.509 certificates in PEM and DER formats. User certificate and private key can be included in the same file. If the user certificate and private key is received in PKCS#12/PFX format, they need to be converted to suitable PEM/DER format for wpa_supplicant. This can be done, e.g., with following commands:
# convert client certificate and private key to PEM format openssl pkcs12 -in example.pfx -out user.pem -clcerts # convert CA certificate (if included in PFX file) to PEM format openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys
See Also wpa_supplicant 8 openssl 1
wpa_supplicant-2.2/wpa_supplicant/doc/docbook/eapol_test.sgml0000664000175000017500000001432012343617166022460 0ustar jmjm eapol_test 8 eapol_test EAP peer and RADIUS client testing eapol_test -nWS -cconfig file -aserver IP address -Aclient IP address -pUDP port -sshared secret -rre-authentications -ttimeout -CConnect-Info -MMAC address -ofile -Nattr spec eapol_test scard eapol_test sim PIN num triplets Overview eapol_test is a program that links together the same EAP peer implementation that wpa_supplicant is using and the RADIUS authentication client code from hostapd. In addition, it has minimal glue code to combine these two components in similar ways to IEEE 802.1X/EAPOL Authenticator state machines. In other words, it integrates IEEE 802.1X Authenticator (normally, an access point) and IEEE 802.1X Supplicant (normally, a wireless client) together to generate a single program that can be used to test EAP methods without having to setup an access point and a wireless client. The main uses for eapol_test are in interoperability testing of EAP methods against RADIUS servers and in development testing for new EAP methods. It can be easily used to automate EAP testing for interoperability and regression since the program can be run from shell scripts without require additional test components apart from a RADIUS server. For example, the automated EAP tests described in eap_testing.txt are implemented with eapol_test. Similarly, eapol_test could be used to implement an automated regression test suite for a RADIUS authentication server. As an example:
eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1
tries to complete EAP authentication based on the network configuration from test.conf against the RADIUS server running on the local host. A re-authentication is triggered to test fast re-authentication. The configuration file uses the same format for network blocks as wpa_supplicant.
Command Arguments -c configuration file path A configuration to use. The configuration should use the same format for network blocks as wpa_supplicant. -a AS address IP address of the authentication server. The default is '127.0.0.1'. -A client address IP address of the client. The default is to select an address automatically. -p AS port UDP port of the authentication server. The default is '1812'. -s AS secret Shared secret with the authentication server. The default is 'radius'. -r count Number of reauthentications. -t timeout Timeout in seconds. The default is 30. -C info RADIUS Connect-Info. The default is 'CONNECT 11Mbps 802.11b'. -M mac address Client MAC address (Calling-Station-Id). The default is '02:00:00:00:00:01'. -o file Location to write out server certificate. -N attr spec Send arbitrary attribute specific by attr_id:syntax:value, or attr_id alone. attr_id should be the numeric ID of the attribute, and syntax should be one of 's' (string), 'd' (integer), or 'x' (octet string). The value is the attribute value to send. When attr_id is given alone, NULL is used as the attribute value. Multiple attributes can be specified by using the option several times. -n Indicates that no MPPE keys are expected. -W Wait for a control interface monitor before starting. -S Save configuration after authentication. See Also wpa_supplicant 8 Legal wpa_supplicant is copyright (c) 2003-2014, Jouni Malinen j@w1.fi and contributors. All Rights Reserved. This program is licensed under the BSD license (the one with advertisement clause removed).
wpa_supplicant-2.2/wpa_supplicant/doc/docbook/wpa_passphrase.80000664000175000017500000000225612343703240022540 0ustar jmjm.\" This manpage has been automatically generated by docbook2man .\" from a DocBook document. This tool can be found at: .\" .\" Please send any bug reports, improvements, comments, patches, .\" etc. to Steve Cheng . .TH "WPA_PASSPHRASE" "8" "04 June 2014" "" "" .SH NAME wpa_passphrase \- Generate a WPA PSK from an ASCII passphrase for a SSID .SH SYNOPSIS \fBwpa_passphrase\fR [ \fB\fIssid\fB\fR ] [ \fB\fIpassphrase\fB\fR ] .SH "OVERVIEW" .PP \fBwpa_passphrase\fR pre-computes PSK entries for network configuration blocks of a \fIwpa_supplicant.conf\fR file. An ASCII passphrase and SSID are used to generate a 256-bit PSK. .SH "OPTIONS" .TP \fBssid\fR The SSID whose passphrase should be derived. .TP \fBpassphrase\fR The passphrase to use. If not included on the command line, passphrase will be read from standard input. .SH "SEE ALSO" .PP \fBwpa_supplicant.conf\fR(5) \fBwpa_supplicant\fR(8) .SH "LEGAL" .PP wpa_supplicant is copyright (c) 2003-2014, Jouni Malinen and contributors. All Rights Reserved. .PP This program is licensed under the BSD license (the one with advertisement clause removed). wpa_supplicant-2.2/wpa_supplicant/doc/docbook/wpa_passphrase.sgml0000664000175000017500000000363412343617166023347 0ustar jmjm wpa_passphrase 8 wpa_passphrase Generate a WPA PSK from an ASCII passphrase for a SSID wpa_passphrase ssid passphrase Overview wpa_passphrase pre-computes PSK entries for network configuration blocks of a wpa_supplicant.conf file. An ASCII passphrase and SSID are used to generate a 256-bit PSK. Options ssid The SSID whose passphrase should be derived. passphrase The passphrase to use. If not included on the command line, passphrase will be read from standard input. See Also wpa_supplicant.conf 5 wpa_supplicant 8 Legal wpa_supplicant is copyright (c) 2003-2014, Jouni Malinen j@w1.fi and contributors. All Rights Reserved. This program is licensed under the BSD license (the one with advertisement clause removed). wpa_supplicant-2.2/wpa_supplicant/doc/docbook/wpa_gui.80000664000175000017500000000302612343703240021147 0ustar jmjm.\" This manpage has been automatically generated by docbook2man .\" from a DocBook document. This tool can be found at: .\" .\" Please send any bug reports, improvements, comments, patches, .\" etc. to Steve Cheng . .TH "WPA_GUI" "8" "04 June 2014" "" "" .SH NAME wpa_gui \- WPA Graphical User Interface .SH SYNOPSIS \fBwpa_gui\fR [ \fB-p \fIpath to ctrl sockets\fB\fR ] [ \fB-i \fIifname\fB\fR ] [ \fB-t\fR ] .SH "OVERVIEW" .PP wpa_gui is a QT graphical frontend program for interacting with wpa_supplicant. It is used to query current status, change configuration and request interactive user input. .PP wpa_gui supports (almost) all of the interactive status and configuration features of the command line client, wpa_cli. Refer to the wpa_cli manpage for a comprehensive list of the interactive mode features. .SH "COMMAND ARGUMENTS" .TP \fB-p path\fR Change the path where control sockets should be found. .TP \fB-i ifname\fR Specify the interface that is being configured. By default, choose the first interface found with a control socket in the socket path. .TP \fB-t\fR Start program in the system tray only (if the window manager supports it). By default the main status window is shown. .SH "SEE ALSO" .PP \fBwpa_cli\fR(8) \fBwpa_supplicant\fR(8) .SH "LEGAL" .PP wpa_supplicant is copyright (c) 2003-2014, Jouni Malinen and contributors. All Rights Reserved. .PP This program is licensed under the BSD license (the one with advertisement clause removed). wpa_supplicant-2.2/wpa_supplicant/doc/docbook/wpa_background.80000664000175000017500000000755512343703237022523 0ustar jmjm.\" This manpage has been automatically generated by docbook2man .\" from a DocBook document. This tool can be found at: .\" .\" Please send any bug reports, improvements, comments, patches, .\" etc. to Steve Cheng . .TH "WPA_BACKGROUND" "8" "04 June 2014" "" "" .SH NAME wpa_background \- Background information on Wi-Fi Protected Access and IEEE 802.11i .SH "WPA" .PP The original security mechanism of IEEE 802.11 standard was not designed to be strong and has proven to be insufficient for most networks that require some kind of security. Task group I (Security) of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked to address the flaws of the base standard and has in practice completed its work in May 2004. The IEEE 802.11i amendment to the IEEE 802.11 standard was approved in June 2004 and published in July 2004. .PP Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the IEEE 802.11i work (draft 3.0) to define a subset of the security enhancements that can be implemented with existing wlan hardware. This is called Wi-Fi Protected Access (WPA). This has now become a mandatory component of interoperability testing and certification done by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web site (http://www.wi-fi.org/OpenSection/protected_access.asp). .PP IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm for protecting wireless networks. WEP uses RC4 with 40-bit keys, 24-bit initialization vector (IV), and CRC32 to protect against packet forgery. All these choices have proven to be insufficient: key space is too small against current attacks, RC4 key scheduling is insufficient (beginning of the pseudorandom stream should be skipped), IV space is too small and IV reuse makes attacks easier, there is no replay protection, and non-keyed authentication does not protect against bit flipping packet data. .PP WPA is an intermediate solution for the security issues. It uses Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a compromise on strong security and possibility to use existing hardware. It still uses RC4 for the encryption like WEP, but with per-packet RC4 keys. In addition, it implements replay protection, keyed packet authentication mechanism (Michael MIC). .PP Keys can be managed using two different mechanisms. WPA can either use an external authentication server (e.g., RADIUS) and EAP just like IEEE 802.1X is using or pre-shared keys without need for additional servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal", respectively. Both mechanisms will generate a master session key for the Authenticator (AP) and Supplicant (client station). .PP WPA implements a new key handshake (4-Way Handshake and Group Key Handshake) for generating and exchanging data encryption keys between the Authenticator and Supplicant. This handshake is also used to verify that both Authenticator and Supplicant know the master session key. These handshakes are identical regardless of the selected key management mechanism (only the method for generating master session key changes). .SH "IEEE 802.11I / WPA2" .PP The design for parts of IEEE 802.11i that were not included in WPA has finished (May 2004) and this amendment to IEEE 802.11 was approved in June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new version of WPA called WPA2. This includes, e.g., support for more robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC) to replace TKIP and optimizations for handoff (reduced number of messages in initial key handshake, pre-authentication, and PMKSA caching). .SH "SEE ALSO" .PP \fBwpa_supplicant\fR(8) .SH "LEGAL" .PP wpa_supplicant is copyright (c) 2003-2014, Jouni Malinen and contributors. All Rights Reserved. .PP This program is licensed under the BSD license (the one with advertisement clause removed). wpa_supplicant-2.2/wpa_supplicant/wifi_display.c0000664000175000017500000001666412343617166020114 0ustar jmjm/* * wpa_supplicant - Wi-Fi Display * Copyright (c) 2011, Atheros Communications, Inc. * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include "common.h" #include "p2p/p2p.h" #include "common/ieee802_11_defs.h" #include "wpa_supplicant_i.h" #include "wifi_display.h" #define WIFI_DISPLAY_SUBELEM_HEADER_LEN 3 int wifi_display_init(struct wpa_global *global) { global->wifi_display = 1; return 0; } void wifi_display_deinit(struct wpa_global *global) { int i; for (i = 0; i < MAX_WFD_SUBELEMS; i++) { wpabuf_free(global->wfd_subelem[i]); global->wfd_subelem[i] = NULL; } } static int wifi_display_update_wfd_ie(struct wpa_global *global) { struct wpabuf *ie, *buf; size_t len, plen; if (global->p2p == NULL) return 0; wpa_printf(MSG_DEBUG, "WFD: Update WFD IE"); if (!global->wifi_display) { wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not " "include WFD IE"); p2p_set_wfd_ie_beacon(global->p2p, NULL); p2p_set_wfd_ie_probe_req(global->p2p, NULL); p2p_set_wfd_ie_probe_resp(global->p2p, NULL); p2p_set_wfd_ie_assoc_req(global->p2p, NULL); p2p_set_wfd_ie_invitation(global->p2p, NULL); p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL); p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL); p2p_set_wfd_ie_go_neg(global->p2p, NULL); p2p_set_wfd_dev_info(global->p2p, NULL); p2p_set_wfd_assoc_bssid(global->p2p, NULL); p2p_set_wfd_coupled_sink_info(global->p2p, NULL); return 0; } p2p_set_wfd_dev_info(global->p2p, global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]); p2p_set_wfd_assoc_bssid( global->p2p, global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]); p2p_set_wfd_coupled_sink_info( global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]); /* * WFD IE is included in number of management frames. Two different * sets of subelements are included depending on the frame: * * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf, * Provision Discovery Req: * WFD Device Info * [Associated BSSID] * [Coupled Sink Info] * * Probe Request: * WFD Device Info * [Associated BSSID] * [Coupled Sink Info] * [WFD Extended Capability] * * Probe Response: * WFD Device Info * [Associated BSSID] * [Coupled Sink Info] * [WFD Extended Capability] * [WFD Session Info] * * (Re)Association Response, P2P Invitation Req/Resp, * Provision Discovery Resp: * WFD Device Info * [Associated BSSID] * [Coupled Sink Info] * [WFD Session Info] */ len = 0; if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]) len += wpabuf_len(global->wfd_subelem[ WFD_SUBELEM_DEVICE_INFO]); if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]) len += wpabuf_len(global->wfd_subelem[ WFD_SUBELEM_ASSOCIATED_BSSID]); if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]) len += wpabuf_len(global->wfd_subelem[ WFD_SUBELEM_COUPLED_SINK]); if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]) len += wpabuf_len(global->wfd_subelem[ WFD_SUBELEM_SESSION_INFO]); if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]) len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]); buf = wpabuf_alloc(len); if (buf == NULL) return -1; if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]) wpabuf_put_buf(buf, global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]); if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]) wpabuf_put_buf(buf, global->wfd_subelem[ WFD_SUBELEM_ASSOCIATED_BSSID]); if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]) wpabuf_put_buf(buf, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]); ie = wifi_display_encaps(buf); wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie); p2p_set_wfd_ie_beacon(global->p2p, ie); ie = wifi_display_encaps(buf); wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request", ie); p2p_set_wfd_ie_assoc_req(global->p2p, ie); ie = wifi_display_encaps(buf); wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie); p2p_set_wfd_ie_go_neg(global->p2p, ie); ie = wifi_display_encaps(buf); wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery " "Request", ie); p2p_set_wfd_ie_prov_disc_req(global->p2p, ie); plen = buf->used; if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]) wpabuf_put_buf(buf, global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]); ie = wifi_display_encaps(buf); wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie); p2p_set_wfd_ie_probe_req(global->p2p, ie); if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]) wpabuf_put_buf(buf, global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]); ie = wifi_display_encaps(buf); wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie); p2p_set_wfd_ie_probe_resp(global->p2p, ie); /* Remove WFD Extended Capability from buffer */ buf->used = plen; if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]) wpabuf_put_buf(buf, global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]); ie = wifi_display_encaps(buf); wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie); p2p_set_wfd_ie_invitation(global->p2p, ie); ie = wifi_display_encaps(buf); wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery " "Response", ie); p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie); wpabuf_free(buf); return 0; } void wifi_display_enable(struct wpa_global *global, int enabled) { wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s", enabled ? "enabled" : "disabled"); global->wifi_display = enabled; wifi_display_update_wfd_ie(global); } int wifi_display_subelem_set(struct wpa_global *global, char *cmd) { char *pos; int subelem; size_t len; struct wpabuf *e; pos = os_strchr(cmd, ' '); if (pos == NULL) return -1; *pos++ = '\0'; subelem = atoi(cmd); if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS) return -1; len = os_strlen(pos); if (len & 1) return -1; len /= 2; if (len == 0) { /* Clear subelement */ e = NULL; wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem); } else { e = wpabuf_alloc(1 + len); if (e == NULL) return -1; wpabuf_put_u8(e, subelem); if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) { wpabuf_free(e); return -1; } wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem); } wpabuf_free(global->wfd_subelem[subelem]); global->wfd_subelem[subelem] = e; wifi_display_update_wfd_ie(global); return 0; } int wifi_display_subelem_get(struct wpa_global *global, char *cmd, char *buf, size_t buflen) { int subelem; subelem = atoi(cmd); if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS) return -1; if (global->wfd_subelem[subelem] == NULL) return 0; return wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(global->wfd_subelem[subelem]) + 1, wpabuf_len(global->wfd_subelem[subelem]) - 1); } char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id) { char *subelem = NULL; const u8 *buf; size_t buflen; size_t i = 0; u16 elen; if (!wfd_subelems) return NULL; buf = wpabuf_head_u8(wfd_subelems); if (!buf) return NULL; buflen = wpabuf_len(wfd_subelems); while (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN < buflen) { elen = WPA_GET_BE16(buf + i + 1); if (buf[i] == id) { subelem = os_zalloc(2 * elen + 1); if (!subelem) return NULL; wpa_snprintf_hex(subelem, 2 * elen + 1, buf + i + WIFI_DISPLAY_SUBELEM_HEADER_LEN, elen); break; } i += elen + WIFI_DISPLAY_SUBELEM_HEADER_LEN; } return subelem; } wpa_supplicant-2.2/wpa_supplicant/offchannel.c0000664000175000017500000003276512343617166017534 0ustar jmjm/* * wpa_supplicant - Off-channel Action frame TX/RX * Copyright (c) 2009-2010, Atheros Communications * Copyright (c) 2011, Qualcomm Atheros * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include "common.h" #include "utils/eloop.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "offchannel.h" static struct wpa_supplicant * wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src) { struct wpa_supplicant *iface; if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0) return wpa_s; /* * Try to find a group interface that matches with the source address. */ iface = wpa_s->global->ifaces; while (iface) { if (os_memcmp(wpa_s->pending_action_src, iface->own_addr, ETH_ALEN) == 0) break; iface = iface->next; } if (iface) { wpa_printf(MSG_DEBUG, "P2P: Use group interface %s " "instead of interface %s for Action TX", iface->ifname, wpa_s->ifname); return iface; } return wpa_s; } static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; struct wpa_supplicant *iface; int res; int without_roc; without_roc = wpa_s->pending_action_without_roc; wpa_s->pending_action_without_roc = 0; wpa_printf(MSG_DEBUG, "Off-channel: Send Action callback (without_roc=%d pending_action_tx=%p pending_action_tx_done=%d)", without_roc, wpa_s->pending_action_tx, !!wpa_s->pending_action_tx_done); if (wpa_s->pending_action_tx == NULL || wpa_s->pending_action_tx_done) return; /* * This call is likely going to be on the P2P device instance if the * driver uses a separate interface for that purpose. However, some * Action frames are actually sent within a P2P Group and when that is * the case, we need to follow power saving (e.g., GO buffering the * frame for a client in PS mode or a client following the advertised * NoA from its GO). To make that easier for the driver, select the * correct group interface here. */ iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src); if (wpa_s->off_channel_freq != wpa_s->pending_action_freq && wpa_s->pending_action_freq != 0 && wpa_s->pending_action_freq != iface->assoc_freq) { wpa_printf(MSG_DEBUG, "Off-channel: Pending Action frame TX " "waiting for another freq=%u (off_channel_freq=%u " "assoc_freq=%u)", wpa_s->pending_action_freq, wpa_s->off_channel_freq, iface->assoc_freq); if (without_roc && wpa_s->off_channel_freq == 0) { /* * We may get here if wpas_send_action() found us to be * on the correct channel, but remain-on-channel cancel * event was received before getting here. */ wpa_printf(MSG_DEBUG, "Off-channel: Schedule " "remain-on-channel to send Action frame"); if (wpa_drv_remain_on_channel( wpa_s, wpa_s->pending_action_freq, 200) < 0) { wpa_printf(MSG_DEBUG, "Off-channel: Failed to " "request driver to remain on " "channel (%u MHz) for Action Frame " "TX", wpa_s->pending_action_freq); } else { wpa_s->off_channel_freq = 0; wpa_s->roc_waiting_drv_freq = wpa_s->pending_action_freq; } } return; } wpa_printf(MSG_DEBUG, "Off-channel: Sending pending Action frame to " MACSTR " using interface %s", MAC2STR(wpa_s->pending_action_dst), iface->ifname); res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0, wpa_s->pending_action_dst, wpa_s->pending_action_src, wpa_s->pending_action_bssid, wpabuf_head(wpa_s->pending_action_tx), wpabuf_len(wpa_s->pending_action_tx), wpa_s->pending_action_no_cck); if (res) { wpa_printf(MSG_DEBUG, "Off-channel: Failed to send the " "pending Action frame"); /* * Use fake TX status event to allow state machines to * continue. */ offchannel_send_action_tx_status( wpa_s, wpa_s->pending_action_dst, wpabuf_head(wpa_s->pending_action_tx), wpabuf_len(wpa_s->pending_action_tx), OFFCHANNEL_SEND_ACTION_FAILED); } } /** * offchannel_send_action_tx_status - TX status callback * @wpa_s: Pointer to wpa_supplicant data * @dst: Destination MAC address of the transmitted Action frame * @data: Transmitted frame payload * @data_len: Length of @data in bytes * @result: TX status * * This function is called whenever the driver indicates a TX status event for * a frame sent by offchannel_send_action() using wpa_drv_send_action(). */ void offchannel_send_action_tx_status( struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data, size_t data_len, enum offchannel_send_action_result result) { if (wpa_s->pending_action_tx == NULL) { wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - " "no pending operation"); return; } if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - " "unknown destination address"); return; } /* Accept report only if the contents of the frame matches */ if (data_len - wpabuf_len(wpa_s->pending_action_tx) != 24 || os_memcmp(data + 24, wpabuf_head(wpa_s->pending_action_tx), wpabuf_len(wpa_s->pending_action_tx)) != 0) { wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - " "mismatching contents with pending frame"); wpa_hexdump(MSG_MSGDUMP, "TX status frame data", data, data_len); wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame", wpa_s->pending_action_tx); return; } wpa_printf(MSG_DEBUG, "Off-channel: Delete matching pending action frame"); wpabuf_free(wpa_s->pending_action_tx); wpa_s->pending_action_tx = NULL; wpa_printf(MSG_DEBUG, "Off-channel: TX status result=%d cb=%p", result, wpa_s->pending_action_tx_status_cb); if (wpa_s->pending_action_tx_status_cb) { wpa_s->pending_action_tx_status_cb( wpa_s, wpa_s->pending_action_freq, wpa_s->pending_action_dst, wpa_s->pending_action_src, wpa_s->pending_action_bssid, data, data_len, result); } } /** * offchannel_send_action - Request off-channel Action frame TX * @wpa_s: Pointer to wpa_supplicant data * @freq: The frequency in MHz indicating the channel on which the frame is to * transmitted or 0 for the current channel (only if associated) * @dst: Action frame destination MAC address * @src: Action frame source MAC address * @bssid: Action frame BSSID * @buf: Frame to transmit starting from the Category field * @len: Length of @buf in bytes * @wait_time: Wait time for response in milliseconds * @tx_cb: Callback function for indicating TX status or %NULL for now callback * @no_cck: Whether CCK rates are to be disallowed for TX rate selection * Returns: 0 on success or -1 on failure * * This function is used to request an Action frame to be transmitted on the * current operating channel or on another channel (off-channel). The actual * frame transmission will be delayed until the driver is ready on the specified * channel. The @wait_time parameter can be used to request the driver to remain * awake on the channel to wait for a response. */ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *buf, size_t len, unsigned int wait_time, void (*tx_cb)(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *data, size_t data_len, enum offchannel_send_action_result result), int no_cck) { wpa_printf(MSG_DEBUG, "Off-channel: Send action frame: freq=%d dst=" MACSTR " src=" MACSTR " bssid=" MACSTR " len=%d", freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), (int) len); wpa_s->pending_action_tx_status_cb = tx_cb; if (wpa_s->pending_action_tx) { wpa_printf(MSG_DEBUG, "Off-channel: Dropped pending Action " "frame TX to " MACSTR, MAC2STR(wpa_s->pending_action_dst)); wpabuf_free(wpa_s->pending_action_tx); } wpa_s->pending_action_tx_done = 0; wpa_s->pending_action_tx = wpabuf_alloc(len); if (wpa_s->pending_action_tx == NULL) { wpa_printf(MSG_DEBUG, "Off-channel: Failed to allocate Action " "frame TX buffer (len=%llu)", (unsigned long long) len); return -1; } wpabuf_put_data(wpa_s->pending_action_tx, buf, len); os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN); os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN); os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN); wpa_s->pending_action_freq = freq; wpa_s->pending_action_no_cck = no_cck; if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) { struct wpa_supplicant *iface; int ret; iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src); wpa_s->action_tx_wait_time = wait_time; ret = wpa_drv_send_action( iface, wpa_s->pending_action_freq, wait_time, wpa_s->pending_action_dst, wpa_s->pending_action_src, wpa_s->pending_action_bssid, wpabuf_head(wpa_s->pending_action_tx), wpabuf_len(wpa_s->pending_action_tx), wpa_s->pending_action_no_cck); if (ret == 0) wpa_s->pending_action_tx_done = 1; return ret; } if (freq) { struct wpa_supplicant *tx_iface; tx_iface = wpas_get_tx_interface(wpa_s, src); if (tx_iface->assoc_freq == freq) { wpa_printf(MSG_DEBUG, "Off-channel: Already on " "requested channel (TX interface operating " "channel)"); freq = 0; } } if (wpa_s->off_channel_freq == freq || freq == 0) { wpa_printf(MSG_DEBUG, "Off-channel: Already on requested " "channel; send Action frame immediately"); /* TODO: Would there ever be need to extend the current * duration on the channel? */ wpa_s->pending_action_without_roc = 1; eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL); eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL); return 0; } wpa_s->pending_action_without_roc = 0; if (wpa_s->roc_waiting_drv_freq == freq) { wpa_printf(MSG_DEBUG, "Off-channel: Already waiting for " "driver to get to frequency %u MHz; continue " "waiting to send the Action frame", freq); return 0; } wpa_printf(MSG_DEBUG, "Off-channel: Schedule Action frame to be " "transmitted once the driver gets to the requested " "channel"); if (wait_time > wpa_s->max_remain_on_chan) wait_time = wpa_s->max_remain_on_chan; else if (wait_time == 0) wait_time = 20; if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) { wpa_printf(MSG_DEBUG, "Off-channel: Failed to request driver " "to remain on channel (%u MHz) for Action " "Frame TX", freq); return -1; } wpa_s->off_channel_freq = 0; wpa_s->roc_waiting_drv_freq = freq; return 0; } /** * offchannel_send_send_action_done - Notify completion of Action frame sequence * @wpa_s: Pointer to wpa_supplicant data * * This function can be used to cancel a wait for additional response frames on * the channel that was used with offchannel_send_action(). */ void offchannel_send_action_done(struct wpa_supplicant *wpa_s) { wpa_printf(MSG_DEBUG, "Off-channel: Action frame sequence done " "notification"); wpabuf_free(wpa_s->pending_action_tx); wpa_s->pending_action_tx = NULL; if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX && wpa_s->action_tx_wait_time) wpa_drv_send_action_cancel_wait(wpa_s); if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) { wpa_drv_cancel_remain_on_channel(wpa_s); wpa_s->off_channel_freq = 0; wpa_s->roc_waiting_drv_freq = 0; } } /** * offchannel_remain_on_channel_cb - Remain-on-channel callback function * @wpa_s: Pointer to wpa_supplicant data * @freq: Frequency (in MHz) of the selected channel * @duration: Duration of the remain-on-channel operation in milliseconds * * This function is called whenever the driver notifies beginning of a * remain-on-channel operation. */ void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq, unsigned int duration) { wpa_s->roc_waiting_drv_freq = 0; wpa_s->off_channel_freq = freq; wpas_send_action_cb(wpa_s, NULL); } /** * offchannel_cancel_remain_on_channel_cb - Remain-on-channel stopped callback * @wpa_s: Pointer to wpa_supplicant data * @freq: Frequency (in MHz) of the selected channel * * This function is called whenever the driver notifies termination of a * remain-on-channel operation. */ void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq) { wpa_s->off_channel_freq = 0; } /** * offchannel_pending_action_tx - Check whether there is a pending Action TX * @wpa_s: Pointer to wpa_supplicant data * Returns: Pointer to pending frame or %NULL if no pending operation * * This function can be used to check whether there is a pending Action frame TX * operation. The returned pointer should be used only for checking whether it * is %NULL (no pending frame) or to print the pointer value in debug * information (i.e., the pointer should not be dereferenced). */ const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s) { return wpa_s->pending_action_tx; } /** * offchannel_clear_pending_action_tx - Clear pending Action frame TX * @wpa_s: Pointer to wpa_supplicant data */ void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s) { wpabuf_free(wpa_s->pending_action_tx); wpa_s->pending_action_tx = NULL; } /** * offchannel_deinit - Deinit off-channel operations * @wpa_s: Pointer to wpa_supplicant data * * This function is used to free up any allocated resources for off-channel * operations. */ void offchannel_deinit(struct wpa_supplicant *wpa_s) { offchannel_clear_pending_action_tx(wpa_s); eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL); } wpa_supplicant-2.2/wpa_supplicant/autoscan.c0000664000175000017500000000606312343617166017236 0ustar jmjm/* * WPA Supplicant - auto scan * Copyright (c) 2012, Intel Corporation. All rights reserved. * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" #include "common.h" #include "config.h" #include "wpa_supplicant_i.h" #include "bss.h" #include "scan.h" #include "autoscan.h" #ifdef CONFIG_AUTOSCAN_EXPONENTIAL extern const struct autoscan_ops autoscan_exponential_ops; #endif /* CONFIG_AUTOSCAN_EXPONENTIAL */ #ifdef CONFIG_AUTOSCAN_PERIODIC extern const struct autoscan_ops autoscan_periodic_ops; #endif /* CONFIG_AUTOSCAN_PERIODIC */ static const struct autoscan_ops * autoscan_modules[] = { #ifdef CONFIG_AUTOSCAN_EXPONENTIAL &autoscan_exponential_ops, #endif /* CONFIG_AUTOSCAN_EXPONENTIAL */ #ifdef CONFIG_AUTOSCAN_PERIODIC &autoscan_periodic_ops, #endif /* CONFIG_AUTOSCAN_PERIODIC */ NULL }; static void request_scan(struct wpa_supplicant *wpa_s) { wpa_s->scan_req = MANUAL_SCAN_REQ; if (wpa_supplicant_req_sched_scan(wpa_s)) wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 0); } int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan) { const char *name = wpa_s->conf->autoscan; const char *params; size_t nlen; int i; const struct autoscan_ops *ops = NULL; if (wpa_s->autoscan && wpa_s->autoscan_priv) return 0; if (name == NULL) return 0; params = os_strchr(name, ':'); if (params == NULL) { params = ""; nlen = os_strlen(name); } else { nlen = params - name; params++; } for (i = 0; autoscan_modules[i]; i++) { if (os_strncmp(name, autoscan_modules[i]->name, nlen) == 0) { ops = autoscan_modules[i]; break; } } if (ops == NULL) { wpa_printf(MSG_ERROR, "autoscan: Could not find module " "matching the parameter '%s'", name); return -1; } wpa_s->autoscan_params = NULL; wpa_s->autoscan_priv = ops->init(wpa_s, params); if (wpa_s->autoscan_priv == NULL) return -1; wpa_s->autoscan = ops; wpa_printf(MSG_DEBUG, "autoscan: Initialized module '%s' with " "parameters '%s'", ops->name, params); if (!req_scan) return 0; /* * Cancelling existing scan requests, if any. */ wpa_supplicant_cancel_sched_scan(wpa_s); wpa_supplicant_cancel_scan(wpa_s); /* * Firing first scan, which will lead to call autoscan_notify_scan. */ request_scan(wpa_s); return 0; } void autoscan_deinit(struct wpa_supplicant *wpa_s) { if (wpa_s->autoscan && wpa_s->autoscan_priv) { wpa_printf(MSG_DEBUG, "autoscan: Deinitializing module '%s'", wpa_s->autoscan->name); wpa_s->autoscan->deinit(wpa_s->autoscan_priv); wpa_s->autoscan = NULL; wpa_s->autoscan_priv = NULL; wpa_s->scan_interval = 5; wpa_s->sched_scan_interval = 0; } } int autoscan_notify_scan(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { int interval; if (wpa_s->autoscan && wpa_s->autoscan_priv) { interval = wpa_s->autoscan->notify_scan(wpa_s->autoscan_priv, scan_res); if (interval <= 0) return -1; wpa_s->scan_interval = interval; wpa_s->sched_scan_interval = interval; request_scan(wpa_s); } return 0; } wpa_supplicant-2.2/wpa_supplicant/README0000664000175000017500000011413112343617166016131 0ustar jmjmWPA Supplicant ============== Copyright (c) 2003-2014, Jouni Malinen and contributors All Rights Reserved. This program is licensed under the BSD license (the one with advertisement clause removed). If you are submitting changes to the project, please see CONTRIBUTIONS file for more instructions. License ------- This software may be distributed, used, and modified under the terms of BSD license: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name(s) of the above-listed copyright holder(s) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Features -------- Supported WPA/IEEE 802.11i features: - WPA-PSK ("WPA-Personal") - WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise") Following authentication methods are supported with an integrate IEEE 802.1X Supplicant: * EAP-TLS * EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1) * EAP-PEAP/TLS (both PEAPv0 and PEAPv1) * EAP-PEAP/GTC (both PEAPv0 and PEAPv1) * EAP-PEAP/OTP (both PEAPv0 and PEAPv1) * EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1) * EAP-TTLS/EAP-MD5-Challenge * EAP-TTLS/EAP-GTC * EAP-TTLS/EAP-OTP * EAP-TTLS/EAP-MSCHAPv2 * EAP-TTLS/EAP-TLS * EAP-TTLS/MSCHAPv2 * EAP-TTLS/MSCHAP * EAP-TTLS/PAP * EAP-TTLS/CHAP * EAP-SIM * EAP-AKA * EAP-PSK * EAP-PAX * EAP-SAKE * EAP-IKEv2 * EAP-GPSK * LEAP (note: requires special support from the driver for IEEE 802.11 authentication) (following methods are supported, but since they do not generate keying material, they cannot be used with WPA or IEEE 802.1X WEP keying) * EAP-MD5-Challenge * EAP-MSCHAPv2 * EAP-GTC * EAP-OTP - key management for CCMP, TKIP, WEP104, WEP40 - RSN/WPA2 (IEEE 802.11i) * pre-authentication * PMKSA caching Supported TLS/crypto libraries: - OpenSSL (default) - GnuTLS Internal TLS/crypto implementation (optional): - can be used in place of an external TLS/crypto library - TLSv1 - X.509 certificate processing - PKCS #1 - ASN.1 - RSA - bignum - minimal size (ca. 50 kB binary, parts of which are already needed for WPA; TLSv1/X.509/ASN.1/RSA/bignum parts are about 25 kB on x86) Requirements ------------ Current hardware/software requirements: - Linux kernel 2.4.x or 2.6.x with Linux Wireless Extensions v15 or newer - FreeBSD 6-CURRENT - NetBSD-current - Microsoft Windows with WinPcap (at least WinXP, may work with other versions) - drivers: Linux drivers that support cfg80211/nl80211. Even though there are number of driver specific interface included in wpa_supplicant, please note that Linux drivers are moving to use generic wireless configuration interface driver_nl80211 (-Dnl80211 on wpa_supplicant command line) should be the default option to start with before falling back to driver specific interface. Linux drivers that support WPA/WPA2 configuration with the generic Linux wireless extensions (WE-18 or newer). Obsoleted by nl80211. In theory, any driver that supports Linux wireless extensions can be used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in configuration file. Wired Ethernet drivers (with ap_scan=0) BSD net80211 layer (e.g., Atheros driver) At the moment, this is for FreeBSD 6-CURRENT branch and NetBSD-current. Windows NDIS The current Windows port requires WinPcap (http://winpcap.polito.it/). See README-Windows.txt for more information. wpa_supplicant was designed to be portable for different drivers and operating systems. Hopefully, support for more wlan cards and OSes will be added in the future. See developer's documentation (http://hostap.epitest.fi/wpa_supplicant/devel/) for more information about the design of wpa_supplicant and porting to other drivers. One main goal is to add full WPA/WPA2 support to Linux wireless extensions to allow new drivers to be supported without having to implement new driver-specific interface code in wpa_supplicant. Optional libraries for layer2 packet processing: - libpcap (tested with 0.7.2, most relatively recent versions assumed to work, this is likely to be available with most distributions, http://tcpdump.org/) - libdnet (tested with v1.4, most versions assumed to work, http://libdnet.sourceforge.net/) These libraries are _not_ used in the default Linux build. Instead, internal Linux specific implementation is used. libpcap/libdnet are more portable and they can be used by adding CONFIG_L2_PACKET=pcap into .config. They may also be selected automatically for other operating systems. In case of Windows builds, WinPcap is used by default (CONFIG_L2_PACKET=winpcap). Optional libraries for EAP-TLS, EAP-PEAP, and EAP-TTLS: - OpenSSL (tested with 0.9.7c and 0.9.7d, and 0.9.8 versions; assumed to work with most relatively recent versions; this is likely to be available with most distributions, http://www.openssl.org/) - GnuTLS - internal TLSv1 implementation TLS options for EAP-FAST: - OpenSSL 0.9.8d _with_ openssl-0.9.8d-tls-extensions.patch applied (i.e., the default OpenSSL package does not include support for extensions needed for EAP-FAST) - internal TLSv1 implementation One of these libraries is needed when EAP-TLS, EAP-PEAP, EAP-TTLS, or EAP-FAST support is enabled. WPA-PSK mode does not require this or EAPOL/EAP implementation. A configuration file, .config, for compilation is needed to enable IEEE 802.1X/EAPOL and EAP methods. Note that EAP-MD5, EAP-GTC, EAP-OTP, and EAP-MSCHAPV2 cannot be used alone with WPA, so they should only be enabled if testing the EAPOL/EAP state machines. However, there can be used as inner authentication algorithms with EAP-PEAP and EAP-TTLS. See Building and installing section below for more detailed information about the wpa_supplicant build time configuration. WPA --- The original security mechanism of IEEE 802.11 standard was not designed to be strong and has proven to be insufficient for most networks that require some kind of security. Task group I (Security) of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked to address the flaws of the base standard and has in practice completed its work in May 2004. The IEEE 802.11i amendment to the IEEE 802.11 standard was approved in June 2004 and published in July 2004. Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the IEEE 802.11i work (draft 3.0) to define a subset of the security enhancements that can be implemented with existing wlan hardware. This is called Wi-Fi Protected Access (WPA). This has now become a mandatory component of interoperability testing and certification done by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web site (http://www.wi-fi.org/OpenSection/protected_access.asp). IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm for protecting wireless networks. WEP uses RC4 with 40-bit keys, 24-bit initialization vector (IV), and CRC32 to protect against packet forgery. All these choices have proven to be insufficient: key space is too small against current attacks, RC4 key scheduling is insufficient (beginning of the pseudorandom stream should be skipped), IV space is too small and IV reuse makes attacks easier, there is no replay protection, and non-keyed authentication does not protect against bit flipping packet data. WPA is an intermediate solution for the security issues. It uses Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a compromise on strong security and possibility to use existing hardware. It still uses RC4 for the encryption like WEP, but with per-packet RC4 keys. In addition, it implements replay protection, keyed packet authentication mechanism (Michael MIC). Keys can be managed using two different mechanisms. WPA can either use an external authentication server (e.g., RADIUS) and EAP just like IEEE 802.1X is using or pre-shared keys without need for additional servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal", respectively. Both mechanisms will generate a master session key for the Authenticator (AP) and Supplicant (client station). WPA implements a new key handshake (4-Way Handshake and Group Key Handshake) for generating and exchanging data encryption keys between the Authenticator and Supplicant. This handshake is also used to verify that both Authenticator and Supplicant know the master session key. These handshakes are identical regardless of the selected key management mechanism (only the method for generating master session key changes). IEEE 802.11i / WPA2 ------------------- The design for parts of IEEE 802.11i that were not included in WPA has finished (May 2004) and this amendment to IEEE 802.11 was approved in June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new version of WPA called WPA2. This includes, e.g., support for more robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC) to replace TKIP and optimizations for handoff (reduced number of messages in initial key handshake, pre-authentication, and PMKSA caching). wpa_supplicant -------------- wpa_supplicant is an implementation of the WPA Supplicant component, i.e., the part that runs in the client stations. It implements WPA key negotiation with a WPA Authenticator and EAP authentication with Authentication Server. In addition, it controls the roaming and IEEE 802.11 authentication/association of the wlan driver. wpa_supplicant is designed to be a "daemon" program that runs in the background and acts as the backend component controlling the wireless connection. wpa_supplicant supports separate frontend programs and an example text-based frontend, wpa_cli, is included with wpa_supplicant. Following steps are used when associating with an AP using WPA: - wpa_supplicant requests the kernel driver to scan neighboring BSSes - wpa_supplicant selects a BSS based on its configuration - wpa_supplicant requests the kernel driver to associate with the chosen BSS - If WPA-EAP: integrated IEEE 802.1X Supplicant completes EAP authentication with the authentication server (proxied by the Authenticator in the AP) - If WPA-EAP: master key is received from the IEEE 802.1X Supplicant - If WPA-PSK: wpa_supplicant uses PSK as the master session key - wpa_supplicant completes WPA 4-Way Handshake and Group Key Handshake with the Authenticator (AP) - wpa_supplicant configures encryption keys for unicast and broadcast - normal data packets can be transmitted and received Building and installing ----------------------- In order to be able to build wpa_supplicant, you will first need to select which parts of it will be included. This is done by creating a build time configuration file, .config, in the wpa_supplicant root directory. Configuration options are text lines using following format: CONFIG_